Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use python's any

Tags:

python

any

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?

like image 227
chyoo CHENG Avatar asked Oct 15 '15 02:10

chyoo CHENG


3 Answers

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.

like image 146
Anand S Kumar Avatar answered Nov 16 '22 04:11

Anand S Kumar


@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.

like image 5
idjaw Avatar answered Nov 16 '22 03:11

idjaw


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 ors (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.

like image 4
ShadowRanger Avatar answered Nov 16 '22 05:11

ShadowRanger