简体   繁体   中英

Why Python built in “all” function returns True for empty iterables?

I know it has a good reason, but I want to know what reason?

>>> print all([])
True

If all() is intended to check if every item on iterable evaluates to "True", and we know empty lists are evaluated to False

>>> bool([])
False

So why the all() returns True for empty lists?

< edit >

I already read the docs, and I know the implementation

 def all(iterable):
    for element in iterable:
        if not element:
            return False
    return True

But the question is why not?

def all(iterable):
    if not iterable:
        return False
    for element in iterable:
        if not element:
            return False
    return True

There is a logic on this? if you have a list of done-tasks

today_todo_status = [task.status for task in my_todo if task.date == today]
can_i_go_home = all(today_todo_status)

Ok, on the above hypothetical example it really makes sense, if I have no tasks, so I can go home.

But there are other cases and I dont think all() was made for todo lists.. LOL

< /edit >

This is expressed as "For all X in S, X is true". If S is empty, there are no X. However, the truth statement remains True, because for all X, X was true... there just aren't any X!

Here is a explanationusing logic .

Consider two sets A and B where A+B is the union of the two sets.

If any(A+B) = True -> any(A) or any(B) = True but we cannot assert either any(A)=True or any(B)=True.

If any(A+B) = False -> any(A) = False and any(B) = False.

If all(A+B) = True -> all(A)=True and all(B)=True

if all(A+B) = False -> all(A)=False or all(B)=False but we cannot assert either all(A)=False or all(B)=False.

Now instead of B, let's add the empty set 0 to A. We want to come up logic such that adding the empty set does not change the values of all() or any(), since A+0=A.

any(A+0) = any(A) or any(0)

any(0) must be False, so that if any(A) is True, any(A+0) is True, and if any(A) is False, any(A+0) is False.

all(A+0) = all(A) and all(0)

if all(A) is True, all(A+0) is True. Therefore, all(0) is True.

all() (documented to " Return True if all elements of the iterable are true ( or if the iterable is empty ). ") is equivalent to the following:

def all(iterable):
    for element in iterable:
        if not element:
            return False
    return True

Since there are no elements, it will skip the loop and return True .

Because all elements are True. When there are no elements, you can say that 'all elements are ... anything'

This comes from the mathematical logic.

"everything is true of the elements of the empty set" ( http://en.wikipedia.org/wiki/Empty_set )

See also http://en.wikipedia.org/wiki/Vacuous_truth

Suppose all([]) is False .

Then, for all non empty list A , all(A + []) should be also False as

all(A + []) = all(A) and all([])
            = all(A) and False
            = False

Since A + [] = A , we know

all(A + []) = all(A) for any non empty list A

But, all(A) could be True (eg, A = [True] )

Hence,

for all non empty list A , all(A + []) should be also False

This contradicts. As a result, the first assumption is wrong and

all([]) is True

ELI5 version.

Take a list of numbers

L = [1,2,3,4,6]

all([isintance(l, int) for l in L])

all is defined in such a way that, the only way to make it False is by supplying at least one non-integer.

Similarly any is defined in a way that, to make it True all you need is at-least one positive integer.

Since all() is the complement of any() one must be True and other must be False

When testing for a condition, we want the first element to always be added to the list. For example, if we only want to add numbers to a list if they are less than the smallest number or greater than the largest number we can do this:

def addToList(less,num):
    if less:
        if any( num >= savedNum for savedNum in numbers):
            print('{} is not less'.format(num))
            return
    elif any( num <= savedNum for savedNum in numbers):
        print('{} is not greater'.format(num))
        return

    numbers.append(num)


numbers = []
doLess = True
doMore = False
addToList(doLess,5) #numbers is empty, but will be added
addToList(doLess,2)
addToList(doLess,7)
addToList(doMore,15)
addToList(doMore,9)
print(numbers)

Output:

7 is not less [5, 2]
9 is not greater [5, 2, 15]
[5, 2, 15]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM