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 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.
Related
In Python, an empty list is considered a Falsey value
Therefore this is how things should work:
>>> [] and False
False
But in reality, python returns an empty list.
>>> [] and False
[]
Is this intended or a bug?
It's intended. Both and and or are defined to return the last thing evaluated (based on short-circuiting), not actually True or False. For and, this means it returns the first falsy value, if any, and the last value (regardless of truthiness) if all the others are truthy.
It was especially useful back before the conditional expression was added, as it let you do some almost-equivalent hacks, e.g. before the conditional expression:
b if a else c
could be written as:
a and b or c
and, assuming b itself was some truthy thing, it would behave equivalently (the conditional expression lacked that limitation and was more clear about intent, which is why it was added). Even today this feature is occasionally useful for replacing all falsy values with some more specifically-typed default, e.g. when lst might be passed as None or a list, you can ensure it's a list with:
lst = lst or []
to cheaply replace None (and any other falsy thing) with a new empty list.
This is how it is supposed to work. and will only return the right hand operand if the left hand operand is truthy. Since [] is falsy, and returns the left hand operand.
That's a totally expected behaviour. To understand it, you need to know how the Boolean operators (and, or, not) work. From the Boolean Operations documentation:
The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
Now let's consider your example: [] and False. Here, since [] is falsey, it's value is returned back by the statement which is [].
Above linked Python documentation explicitly mentions:
Note: Neither and nor or restrict the value and type they return to False and True, but rather return the last evaluated argument.
However, in case you need the return value as boolean, you can explicitly type-cast the value to True or False using the bool() function.
For example, in your case it will return as False:
>>> bool([] and False)
False
I have a code that checks if a given list of integers can sum up to a specified target. If any combination of the integers in a list can sum up to a target value, it returns True. The input 'start' is the index of the list that I want to start from and continue until the end of the list
def groupSum(start, nums, target):
if start >= len(nums):
return target == 0
else:
return groupSum(start + 1, nums, target - nums[start]) or groupSum(start + 1, nums, target);
So, if I put
groupSum(0, [2,4,8], 10)
it will return True, and, if I put
groupSum(0, [2,4,8], 9)
it will return False
QUESTION: I don't understand how they can put 'or' in the return statements, in a recursive case. I don't see how that's actually working. Is it passing multiple functions simultaneously to check every combination or what?
I'm pretty new to Recursion method and would appreciate it if you can explain the technique used here. Thanks
In python and and or operators, do not return boolean values. They return the last thing evaluated. So, when you
return a or b
if a is a truthy value, a will be returned. Otherwise, the truthness of the expression depends on b, and so b will be returned.
Why it's True for 10 is because there's an exact match for 10 (8+2); which your recursive function reduces to 0 for the target variable.
So, groupSum(start + 1, nums, target - nums[start]) this becomes True - so the comparison will be True or False, which will turn out to True!
Now, for the value of 9, there's no such match and hence it'll always remain False.
You can try for 12 and 6 as well. It'll return True.
Whereas, for any other value the comparison will always be False or False.
I am drawing a blank on this one too. Rather than provide an answer, I would appreciate if someone could help me understand why my code is not printing the expected output:
def bool_to_str(bval):
if bval is True:
mytest = 'Yes'
else:
mytest = 'No'
return mytest
Expected output:
>>>bool_to_str([1, 2, 3])
'Yes'
>>>bool_to_str(abcdef)
'Yes'
What's actually output:
>>>bool_to_str([1, 2, 3])
'No'
>>>bool_to_str(abcdef)
'No'
Please help me to understand what I did wrong. I think that the function needs to test the actual truth value of the argument, but I don't understand what I'm missing.
bval is True checks to see whether [1, 2, 3] actually is the True object. You need something like bool() to evaluate whether an object is a true value but not identical to the True object.
The is checks reference equality, not truthiness. Now clearly [1,2,3] (which is a list object) does not point to the True object (which is bool object). It is hard to say if abcdef which is not defined here points to True. But since you do not provide it, I gonna assume it points to something different.
Only bool_to_str(True) or bool_to_str(<expr>) where <expr> evaluates to a bool that is True will result in 'Yes' (the bools are singletons, so all Trues are the same object).
The point is that in order to check the truthness of <expr>, simply write if <expr>:. So in your case it should be:
if bval:
You can also - although I advise against it, check the truthness explicitly with bool(..) and check reference equality like:
if bool(bval) is True:
Usually it is not a good idea to write is. Only if you want to check if two variables point to the same (i.e. not equivalent) object, or for some singleton objects like True, None, (), etc. it makes really sense.
[1,2,3] does not equal True, however, if you put in something like 1, then 1 == True would pass but when you use is it will always be False unless it is True
I'm going through Zed's "Learn Python The Hard Way" and I'm on ex49. I'm quite confused by the following code he gives:
def peek(word_list):
if word_list: # this gives me trouble
word = word_list[0]
return word[0]
else:
return None
The condition of the if statement is giving me trouble, as commented. I'm not sure what this means as word_list is an object, not a conditional statement. How can word_list, just by itself, follow if?
The if statement applies the built-in bool() function to the expression which follows. In your case, the code-block inside the if statement only runs if bool(word_list) is True.
Different objects in Python evaluate to either True or False in a Boolean context. These objects are considered to be 'Truthy' or 'Falsy'. For example:
In [180]: bool('abc')
Out[180]: True
In [181]: bool('')
Out[181]: False
In [182]: bool([1, 2, 4])
Out[182]: True
In [183]: bool([])
Out[183]: False
In [184]: bool(None)
Out[184]: False
The above are examples of the fact that:
strings of length >= 1 are Truthy.
empty strings are Falsy.
lists of length >= 1 are Truthy.
empty lists are Falsy.
None is Falsy.
So: if word_list will evaluate to True if it is a non-empty list. However, if it is an empty list or None it will evaluate to False.
He is checking if word_list is empty or not. If a list is empty and it is used in a conditional statement, it is evaluated to False. Otherwise, it is evaluated to True.
word_list = ['some value']
if word_list:
# list is not empty do some stuff
print "I WILL PRINT"
word_list = []
if word_list:
# list is empty
print "I WILL NOT PRINT"
In the above code, only the first snippet will print.
See the following reference: https://docs.python.org/2/library/stdtypes.html#truth-value-testing
word_list is a list and when you use it for an if statement condition you check word_list is empty or not :
word_list = []
bool(word_list) # False
if word_list :
print "I'm not empty" # would not printed
word_list = ['a']
bool(word_list) # True
if word_list :
print word_list[0] # 'a'
as Mad Physicist said even None elements in a list means that it's not empty:
word_list = [None]
bool(word_list) # True
What is required for an if block is just something that can be evaluated either to True or to False. A conditional evaluates directly to one of those, but there are other objects that can be converted. To see what any given object is, you can use bool:
>>> mylist = []
>>> bool(mylist)
False
>>> mylist = [4, 3, 6]
>>> bool(mylist)
True
You see, a list is False if it is empty, but True otherwise. Therefore, the if word_list: block will be evaluated if word_list is nonempty. Strings also are False if they are empty, but True otherwise. Same thing with tuples, dictionaries, sets. With numbers, 0 and 0.0 are False, but any other number is True. A fairly common argument to give to indicate to the function to come up with its own value is None which evaluates to False, so the if not mylist: block will be executed if mylist is empty or if mylist is None. (It would also be executed if mylist is 0, (), {}, etc.; but it's unlikely that mylist would be given those)
Take a look at this docs page for Truth Value Testing in python. You should get clear idea about your situation after reading this. Here is the relevant part for easy access.
5.1. Truth Value Testing
Any object can be tested for truth value, for use in an if or while
condition or as operand of the Boolean operations below. The following
values are considered false:
None
False
zero of any numeric type, for example, 0, 0.0, 0j.
any empty sequence, for example, '', (), [].
any empty mapping, for example, {}.
instances of user-defined classes, if the class defines a __bool__()
or __len__() method, when that method returns the integer zero or bool
value False.
All other values are considered true — so objects of many types are always true.
Read the first sentence (bolded) again, and note the bolded parts in the fourth rule. This relates to your question.
So, according to the 4th rule, if your word_list is empty, the condition evaluates to False, otherwise it evaluates to True.
I know you trust in the docs, but here is a code snippet to actually test the truth values for yourself. (I know it is needless to do something like this, but I am always tempted to see things with my own eyes)
def test_truth_value(arg):
# ANY object can be evaluated for truth or false in python
if arg: # or to be more verbose "if arg is True"
print("'{}' is True".format(arg))
else:
print("'{}' is False".format(arg))
class dummy_length_zero():
def __len__(self):
return 0
def __str__(self):
return 'instance of class: "dummy_length_zero"'
class dummy_bool_False():
def __bool__(self):
return False
def __str__(self):
return 'instance of class: "dummy_bool_False"'
obj_dummy_0 = dummy_length_zero()
obj_dummy_false = dummy_bool_False()
args = [None, False, 0, 0.0, 0j, '', (), [], {}, obj_dummy_0, obj_dummy_false]
for arg in args:
test_truth_value(arg)
And lastly, to test that last statement so objects of many types are always true, just remove the implementation of __len__() or __bool__() method from dummy_length_zero or dummy_bool_False class respectively, and check for truth.
In python, everything has an implicit boolean value. Putting any object in an if statement directly is equivalent (but more Pythonic than) doing if bool(word_list):. None, empty sequences, empty sets, empty dicts, 0, False, 0.0 all evaluate to False. Most other objects evaluate to True. That makes if word_list: the most Pythonic way of ensuring that the list is not None or empty before accessing the first element. The long way of expressing the same thing would be if word_list is not None and len(word_list) > 0:.
In Python, every expression can be evaluated to a boolean value (i.e. either True or False).
The following, basic, expressions evaluate to False
The keyword False (obviously!)
The keyword None
The number 0 (0, 0.0 ... )
empty sequence (tuple, list, string)
empty mapping (dictionary)
All other expressions evaluate to True.
So, what the if statement does is evaluating the expression that follows the if keyword to either True or False, then act accordingly.
So in your specific example, if word_list matches any of the above cases it will be considered False, otherwise, it will be considered True.
[#] reference
def name(x):
return x==('Jenson'or'Amra'or'McCay'or'Spinner'or'Jones')
print(name('Jenson'))
print(name('McCay'))
This is the question:
"Write a function that takes as input a name of a person (e.g.,
“smith”, “jones”, etc.) This function should check to see if the name
is one of the five names of people on the board. The five names are:
“Jenson”,”Amra”, “McCay”,”Spinner”, and “Jones”. If the name input
into the function is one of those five names, the function should
return the Boolean value True, and if it isn’t, the function should
return False. (remember comments with input types, description, and
test cases) Test the function to make sure it works."
It works if I am doing Jenson but it comes out with false if I put in any other name.
Try like this,
def name(x):
return x in ('Jenson', 'Amra' ,'McCay', 'Spinner','Jones')
How about the "long" way:
def check_name(x):
names_to_check = ('Jenson','Amra','McCay','Spinner','Jones')
for i in names_to_check:
if i == x:
return True
return False
Here is what is happening in your code:
x = 'Jenson', since this is what you have passed in.
This line x == ('Jenson' or 'Amra' or 'McCay' or 'Jones') is actually a boolean operation, and the result of it is always Jenson.
Boolean operations check truth values, and a non-empty string in Python is always True. So actually what ('Jenson' or 'Amra' or 'McCay' or 'Jones') is saying is:
"Either Jenson or Amra or McCay or Jones which ever one is True, set the value to that".
Since Jenson is the first item, and its True (that is, its not an empty string), the entire expression is equal to Jenson (which is why it only works when you pass in Jenson).
A simple example:
>>> ('a' or 'b' or 'c')
'a'
>>> ('b' or 'a' or 'c')
'b'
>>> ('' or '' or 'a')
'a'
>>> (0 or 0 or 1)
1
>>> (False or False or True)
True
The last three illustrate the same comparison. I am checking two empty strings and 'a'. Since an empty string is False in Python, the only thing that is "True" is 'a', which is what is returned, just as if I was comparing 0 with 1.
The syntax x==('Jenson' or 'Amra' or 'McCay' or 'Spinner'or'Jones') is wrong.
It should be like Adem says. or maybe
def name(x):
return x=='Jenson' or x== 'Amra' or x == 'McCay' or x == 'Spinner' or x == 'Jones'
I imagine what is happening is that ('Jenson'or'Amra'or'McCay'or'Spinner'or'Jones') is being evaluated first, and is evaluated to 'Jenson'. That is computed before x is even considered because it is in parentheses. Then x is checked for equality against Jenson. You need to either use a more advanced syntax like x in... as in Adem's answer, or else use return x == 'Jenson' or x == 'Amra' or x == 'McCay'... so that each comparison is run one after another.