I feel very confused about some code like this[not written by me]:
version = any(func1(), func2()) # wrong, should be any([func1(), func2()])
def func1():
if something:
return 1
else:
return None
def func2():
if something:
return 2
else:
return 3
version
must be a num. when [func1(), func2()]
is [1, None]
, should return 1, when is [None, 2]
, should return 2, when [1, 2]
, should return 1.
so I think it's wrong to use any()
in this code, because any()
just return True
or False
. If I rewirte this logic using another way, I can not find a graceful way as a pythoner.
I want to know whether any()
can achieve the logic, if not, how to achieve it gracefully?
You can simply use or
here.
version = func1() or func2()
Make sure the functions are defined before trying to call them.
This works because or
returns the first True-like value or the last value (if no value is True-like) . And 'None' is considered False-like in Boolean context.
@AnandSKumar's answer is optimal. But just to give you some information on any if you are interested:
Take this example:
>>> def foo():
... return 2
...
>>> def boo():
... return 3
...
>>> def doo():
... return 4
...
>>> f = [foo, boo, doo]
>>> any(i() < 3 for i in f)
True
Ultimately what is happening inside the any is, iterate over the array of methods j, and indicate whether each item is less than 3, what the "any" will do in this case is return "ANY" condition that matches that. So even if you find one that is False, it will still return True.
There is another similar method to this called "all", that will ensure that ALL conditions are met based on your condition you are checking. Here is the example:
>>> all(i() < 3 for i in f)
False
So, as you can see, because one condition failed, it will return False.
For the arbitrary length case (where explicitly chaining or
doesn't make sense), you can make a version of any
that returns the first truthy value or a given value when all results are falsy with:
# If on Py2, you'll want to do this to get shortcircuiting behavior
from future_builtins import filter
result = next(filter(None, iterable_to_check), False) # False can be replaced with a chosen default
The filter
only produces "truthy" values, and the two arg next
gets the first "truthy" value, or the default value if filter
finds no "truthy" values.
If the iterable_to_check
is a non-empty Sequence
(rather than merely Iterable
), you can exactly match the behavior of chained or
s (the "falsy" result is the last value, not a specific value like False
or None
) with:
result = next(filter(None, sequence_to_check), sequence_to_check[-1])
to use the final element ("truthy" or "falsy") as the result when all elements were "falsy".
To be clear, if the set of things to test is fixed and smallish, explicit or
per Anand's answer is the better way to go.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With