How do boolean operations work with parentheses in python 2.7? - python

Found this little oddity while playing around.
>>> 'Hello' == ('Hello' or 'World')
True
>>> 'Hello' == ('World' or 'Hello')
False
>>> 'Hello' == ('Hello' and 'World')
False
>>> 'Hello' == ('World' and 'Hello')
True
Is there some trick to this logic that I'm not getting? Why is the order of the strings the determining factor of these queries? Should I not be using parentheses at all? Why does changing to "and" flip the outputs?
Thanks a buncharooni.

In Python, all objects may be considered "truthy" or "falsy". Python uses this fact to create a sneaky shortcut when evaluating boolean logic. If it encounters a value that would allow the logic to "short-circuit", such as a True at the beginning of an or, or a False at the start of an and, it simply returns the definitive value. This works because that value itself evaluates appropriately to be truthy or falsy, and therefore whatever boolean context it's being used in continues to function as expected. In fact, such operations always just return the first value they encounter that allows them to fully evaluate the expression (even if it's the last value).
# "short-circuit" behavior
>>> 2 or 0
2
>>> 0 and 2
0
# "normal" (fully-evaluated) behavior
>>> 'cat' and 'dog'
'dog'
>>> 0 or 2
2

x or y returns the first operand if its truthy, otherwise returns
the second operand.
x and y returns the first operand if its
falsey, otherwise returns the second operand.
For what it looks like you're trying to accomplish you may prefer this:
'Hello' in ['Hello', 'World']

Related

Python: `and` operator does not return a boolean value

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

Why is "is None" ok, but "is True" is not? [duplicate]

Apologies if this has been asked before, but I have searched in vain for an answer to my exact question. Basically, with Python 2.7, I have a program running a series of geoprocessing tools, depended on what is reqested via a series of True/False variables that the user adjusts in the script e.g.
x = True
if x:
run function
However, I have now discovered that x does not need to be literally "True" for the function to run. For example:
In: x = True
if x:
print True
Out: True
In: x = 123
if x:
print True
Out: True
In: x = 'False'
if x:
print True
Out: True
In: x = False
if x:
print True
Out:
So any value other than False appears to evaluate to True, which would not be the case for if x == True or if x is True. Seeing as PEP 8 strongly recommends only using the if x: variant, can anybody explain why this behaviour occurs? It seems that if x: is more a test for "if x is not False" or "if x exists". With that in mind, I believe I should be using if x is True: in this case, despite what PEP 8 has to say.
The following values in Python are false in the context of if and other logical contexts:
False
None
numeric values equal to 0, such as 0, 0.0, -0.0
empty strings: '' and u''
empty containers (such as lists, tuples and dictionaries)
anything that implements __bool__ (in Python3) to return False, or __nonzero__ (in Python2) to return False or 0.
anything that doesn't implement __bool__ (in Python3) or __nonzero__ (in Python2), but does implement __len__ to return a value equal to 0
An object is considered "false" if any of those applies, and "true" otherwise, regardless of whether it's actually equal to or identical with False or True
Now, if you've arranged that x is necessarily one of the objects True or False, then you can safely write if x. If you've arranged that the "trueness" of x indicates whether or not to perform the operation, regardless of type, then you can safely write if x. Where you can write that you should prefer to do so, since it's cleaner to read.
Normally, if it is allowed for x to take the value True then you're in one of those two cases, and so you would not write if x is True. The important thing is to correctly document the meaning of x, so that it reflects the test used in the code.
Python programmers are expected to know what's considered true, so if you just document, "runs the function if x is true", then that expresses what your original code does. Documenting it, "runs the function if x is True" would have a different meaning, and is less commonly used precisely because of the style rule in PEP8 that says to test for trueness rather than the specific value True.
However, if you wanted the code to behave differently in the case where x is an empty container from the case where it is None, then you would write something like if x is not None.
I'd like to add a short example where those 3 tests differ:
def test(x):
print(x, ":", bool(x), x == True, x is True)
test("something")
test(1)
test(True)
The output (pretty formatted):
# "something" : True False False
# 1 : True True False
# True : True True True
x = 'False'
x = 123
Are both True
Other truth values.
The document explains other values.
As far as the PEP8 reason, its far more semantic to read if this_file_is_green
Other falsey values include 0, '', []. You should just use the if x: version.
It goes without saying that you should write code that does what you need. But in most cases, you simply don't need to say == True or is True, because you don't need to distinguish True from other "truthy" values. So it's recommended to leave that out for simplicity.
The case where you definitely should use == True or is True is when you do need to distinguish True from other truthy values.
In your example, do you care about the difference between True and 123? That would tell you which way to code it.
One thing about coding == True or is True: it will raise a minor red flag when other developers read your code. They won't think it's wrong, they will just wonder why it's there and will want to know why it's important to treat True differently from other truthy values in this particular case.
In other words, if you don't need it, it's best not to use it.
The ability to say
if x:
...
is considered a feature. You can also specify when the test should be considered to pass or not for user defined classes (just define the method __nonzero__ in Python 2.x or __bool__ in Python 3).
For example for strings and containers like lists, dictionaries or sets the test if x ... means "if x is not empty".
Note that the rationale is not that this allows less code to write, but that resulting code is easier to read and to understand.
If you like instead to write if x is True ... have you considered to go farther down that path to if (x is True) is True ... or if ((x is True) is True) is True ... ? :-)
In Python 2.7, if a: and if a==True are not giving the same output for values different to 1. Here are some snippets of code to demonstrate the different behaviors:
with a=1
a=1
if a==True:
print (a,"True")
else:
print (a,"Not True")
output> (1,True)
a=1
if a:
print (a,"True")
else:
print (a,"Not True")
output> (1, True)
with a=2
a=2
if a:
print (a,"True")
else:
print (a,"Not True")
output> (2, True)
a=2
if a==True:
print (a,"True")
else:
print (a,"Not True")
output> (2, Not True)
if you use if x ,it means it has to evaluate x for its truth value.But when you use x ==True or x is True.It means checking whether type(x)==bool and whether x is True.
attention : x is True is no equal to bool(x)==True
when you use x is True , you are checking the id of x and True.

"A is not B" vs "A is (not B)"

I'm a little bit scared about the "is not" operator and the possibility that "is not X" is interpreted when "is (not X)" was intended. Do exist some expressions A and B such that:
A is not B
is different from
A is (not B)
?
addendum.
Is it considered good practice to use this operator? Should't not (A is B) be preferred?
They're definitely different. The latter case evaluates not X in a boolean context first and then checks to see if the two objects are the same object (either True or False).
Consider:
False is not []
This expression is trivially True since False and [] are quite clearly different objects. 1
vs.
False is (not [])
This expression is False since not [] evalutes to True and False and True are different objects.
Of course, this is just one example. It gets even easier to find examples if you don't use False and True explicitly as the second expression will always be False and the first expression will (almost) always be True...
3 is not 0 # True
3 is (not 0) # False
1Note that is not is a single operator in the same vein as not in.
Yes:
A = 0
B = 1
Try it and you'll be really scared:
>>> A = 0
>>> B = 1
>>> A is not B
True
>>> A is (not B)
False

Why do I get 0 when I run "0 and True" or "0 and False"

consider this code:
>>> 0 and True
0
>>> 0 and False
0
Why do I get 0 when I run the above commands in Python?
When the first condition of an and evaluates to False (which 0 does in Python), the second argument is not evaluated at all, because the and will never become true. This is called short-circuiting. In that case, the result of the expression is the first operand, in your case 0.
Because 0 is a false value (all numeric 0 values are, as well as empty containers, and None and False).
The and operator short-curcuits; if the left-hand expression evaluates to a false value, it is returned, otherwise the right-hand expression outcome is returned.
The or operator does the same, but for a true left-hand value; 1 or False returns 1.
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.
The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.
You can make handy use of this:
foo = None
if something_or_other:
foo = lambda arg: arg * 3
outcome = foo and foo('bar')
outcome = foo or expensive_call()
where foo is only called if it is actually defined and not still None; the expensive_call() is only invoked if foo is not yet bound to a true value.
You are ANDing with zero. You should get zero always.
this is because, logical operators are evaluated from left to right. So, for or if True find rest of the expression not evaluated:
>>> True or "one"
True
>>> False or "one"
'one'
Similarly for and, if False found rest of the expression ignored:
>>> True and "one"
'one'
>>> False and "one"
False
In compiler design, this concept is called short-circuiting and this is same design for most of compilers.
most of programming languages have this feature, it's fast branch detection, in your case and if first condition is false, evaluation is fail and second (other) condition never check
in other case or if first condition return true second (other) condition never check and result will be true
it's really cool feature look this sample for example:
if( list != null and !list.isEmpty() ) {
// do stuff
}
if this feature does not exists this if statement cause exception, but now !list.isEmpty() will never runs when list is null

Python - function to do string comparison

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.

Categories

Resources