When testing for membership, we can use:
x not in y
Or alternatively:
not x in y
There can be many possible contexts for this expression depending on x and y. It could be for a substring check, list membership, dict key existence, for example.
Are the two forms always equivalent?
Is there a preferred syntax?
They always give the same result.
In fact, not 'ham' in 'spam and eggs' appears to be special cased to perform a single "not in" operation, rather than an "in" operation and then negating the result:
>>> import dis
>>> def notin():
'ham' not in 'spam and eggs'
>>> dis.dis(notin)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 7 (not in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def not_in():
not 'ham' in 'spam and eggs'
>>> dis.dis(not_in)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 7 (not in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def not__in():
not ('ham' in 'spam and eggs')
>>> dis.dis(not__in)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 7 (not in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def noteq():
not 'ham' == 'spam and eggs'
>>> dis.dis(noteq)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 2 (==)
9 UNARY_NOT
10 POP_TOP
11 LOAD_CONST 0 (None)
14 RETURN_VALUE
I had thought at first that they always gave the same result, but that not on its own was simply a low precedence logical negation operator, which could be applied to a in b just as easily as any other boolean expression, whereas not in was a separate operator for convenience and clarity.
The disassembly above was revealing! It seems that while not obviously is a logical negation operator, the form not a in b is special cased so that it's not actually using the general operator. This makes not a in b literally the same expression as a not in b, rather than merely an expression that results in the same value.
No, there is no difference.
The operator not in is defined to have the inverse true value of in.
—Python documentation
I would assume not in is preferred because it is more obvious and they added a special case for it.
They are identical in meaning, but the pycodestyle Python style guide checker (formerly called pep8) prefers the not in operator in rule E713:
E713: test for membership should be not in
See also "Python if x is not None or if not x is None?" for a very similar choice of style.
Others have already made it very clear that the two statements are, down to a quite low level, equivalent.
However, I don't think that anyone yet has stressed enough that since this leaves the choice up to you, you should
choose the form that makes your code as readable as possible.
And not necessarily as readable as possible to anyone, even if that's of course a nice thing to aim for. No, make sure the code is as readable as possible to you, since you are the one who is the most likely to come back to this code later and try to read it.
In Python, there is no difference. And there is no preference.
Syntactically they're the same statement. I would be quick to state that 'ham' not in 'spam and eggs' conveys clearer intent, but I've seen code and scenarios in which not 'ham' in 'spam and eggs' conveys a clearer meaning than the other.
Related
Why is it that according to the timeit.timeit function the code boolean = True if foo else False runs faster than the code boolean = bool(foo)?
How is it that the if statement is able to determine the trueness of foo faster then the bool function itself?
Why doesn't the bool function simply use the same mechanic?
And what is the purpose of the bool function when it can be outperformed by a factor of four by a different technique?
Or, is it so that I am misusing the timeit function and that bool(foo) is, in fact, faster?
>>> timeit.timeit("boolean = True if foo else False", setup="foo='zon-zero'")
0.021019499999965774
>>> timeit.timeit("boolean = bool(foo)", setup="foo='zon-zero'")
0.0684856000000309
>>> timeit.timeit("boolean = True if foo else False", setup="foo=''")
0.019911300000103438
>>> timeit.timeit("boolean = bool(foo)", setup="foo=''")
0.09232059999999365
Looking at these results, True if foo else False seems to be four to five times faster than bool(foo).
I suspect that the difference in speed is caused by the overhead of calling a function and that does indeed seem to be the case when I use the dis module.
>>> dis.dis("boolean = True if foo else False")
1 0 LOAD_NAME 0 (foo)
2 POP_JUMP_IF_FALSE 8
4 LOAD_CONST 0 (True)
6 JUMP_FORWARD 2 (to 10)
>> 8 LOAD_CONST 1 (False)
>> 10 STORE_NAME 1 (boolean)
12 LOAD_CONST 2 (None)
14 RETURN_VALUE
>>> dis.dis("boolean = bool(foo)")
1 0 LOAD_NAME 0 (bool)
2 LOAD_NAME 1 (foo)
4 CALL_FUNCTION 1
6 STORE_NAME 2 (boolean)
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
According to the dis module, than the difference between the two techniques is:
2 POP_JUMP_IF_FALSE 8
4 LOAD_CONST 0 (True)
6 JUMP_FORWARD 2 (to 10)
>> 8 LOAD_CONST 1 (False)
versus
0 LOAD_NAME 1 (bool)
4 CALL_FUNCTION 1
which makes it look like either the call to a function is far too expensive for something as simple as determining a boolean value or the bool function has been written very inefficiently.
But that actually makes me wonder why anyone would use the bool function when it is this much slower and why the bool function even exists when python does not even seem to use it internally.
So, is the bool function slower because it has been written inefficiently, because of the function overhead, or because of a different reason?
And why would anyone use the bool function when a much faster and equally clear alternative is available?
As per Python documentation :
class bool( [ x ] )
Return a Boolean value, i.e. one of True or False. x is converted using the standard truth testing
procedure. If x is false or omitted, this returns False; otherwise it returns True. The bool class is a
subclass of int (see Numeric Types — int, float, complex). It cannot be subclassed further. Its only
instances are False and True
So, when you directly use the object itself (like foo), the interpreter uses its foo.__bool__ property. But the bool function is a wrapper that again calls foo.__bool__
As you said, calling the function made it expensive.
And the use of bool is, there are certain situations where you need the boolean value of an object and need to refer it by a variable.
x = bool(my_object)
Writing x = my_object doesn't work.
Here its useful.
Sometimes bool(foo) is more readable where you can ignore small time lags.
You might be also interested in knowing that
x = {}
is faster than
x = dict()
Find out why... :)
I'm writing a Python program for a guessing game and the current way I'm implementing the main loop works, but it feels wrong:
# Guess Loop
while not(guess(ans)):
pass
It will work but I was wondering if this is bad practice (I assume it is).
There is nothing against this in PEP-8, Python's de facto coding standard. This is exactly what while loops are for.
I think you're concerned because the while loop is empty, but in a non-trivial program it wouldn't be, and you'd have something to put there.
I'd prefer
while True:
if guess(ans):
break
but your code
while not(guess(ans)):
pass
functions identically. It may even be slightly more performant!
from dis import dis
from random import choice
def foo(): return choice([True, False]) # flip a coin
# My code
def bar1():
while True:
if foo(): break
# Your code
def bar2():
while not(foo()):
pass
>>> dis(bar1)
2 0 SETUP_LOOP 12 (to 14)
3 >> 2 LOAD_GLOBAL 0 (foo)
4 CALL_FUNCTION 0
6 POP_JUMP_IF_FALSE 2
8 BREAK_LOOP
10 JUMP_ABSOLUTE 2
12 POP_BLOCK
>> 14 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>> dis(bar2)
2 0 SETUP_LOOP 10 (to 12)
>> 2 LOAD_GLOBAL 0 (foo)
4 CALL_FUNCTION 0
6 POP_JUMP_IF_TRUE 10
3 8 JUMP_ABSOLUTE 2
>> 10 POP_BLOCK
>> 12 LOAD_CONST 0 (None)
14 RETURN_VALUE
Your snippet can omit the "BREAK_LOOP" there, which might improve performance. Of course the POP_JUMP_IF_TRUE might also be slightly harder than the POP_JUMP_IF_FALSE. Or vice-versa.
Regardless, they function identically. Use whichever one you like. I prefer the look of "Loop forever, and if guess(ans) is true, break" to "Loop until the negation of guess(ans) is false."
There are multiple ways to handle this idea - any issues with looping (specifically the bugs that can occur of a while(true) loop) wouldn't be true here, but maybe would come up in other languages, which is maybe what gave you pause.
I was wondering, what code runs faster? For example, we have variable x:
if x!=0 : return
or
if x: return
I tried to check with timeit, and here are results:
>>> def a():
... if 0 == 0: return
...
>>> def b():
... if 0: return
...>>> timeit(a)
0.18059834650234943
>>> timeit(b)
0.13115053638194007
>>>
I can't quite understand it.
This is too hard to show in a comment: there's more (or less ;-) ) going on here than any of the comments so far noted. With a() and b() defined as you showed, let's go on:
>>> from dis import dis
>>> dis(b)
2 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
What happens is that when the CPython compiler sees if 0: or if 1:, it evaluates them at compile time, and doesn't generate any code to do the testing at run time. So the code for b() just loads None and returns it.
But the code generated for a() is much more involved:
>>> dis(a)
2 0 LOAD_CONST 1 (0)
3 LOAD_CONST 1 (0)
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_FALSE 16
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
>> 16 LOAD_CONST 0 (None)
19 RETURN_VALUE
Nothing is evaluated at compile time in this case - it's all done at run time. That's why a() is much slower.
Beyond that, I endorse #Charles Duffy's comment: worrying about micro-optimization is usually counterproductive in Python. But, if you must ;-) , learn how to use dis.dis so you're not fooled by gross differences in generated code, as happened in this specific case.
This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 9 years ago.
I have a question related to change in program behavior
the absence of return statement leads to in a python method.
The count method below prints number of digits in a given integer.
With the below chunk of code I get the result as 4, which is
the expected result.
def count(x,acc=0):
if x==0:
return acc
return count(x/10,acc+1)
print "Count is %s" %(count(1234))
Result: Count is 4
If I modify the above method so that the last statement does not contain
the 'return' statement the result I get is 'None'.
def count(x,acc=0):
if x==0:
return acc
count(x/10,acc+1)
print "Count is %s" %(count(1234))
Result: Count is None
(The version of Python I used is: 2.7.3)
Does the above behavior results due to the fact that Python doesn't do tail call optimization or is there any other reasoning involved ?
A similar chunk of code in perl (which AFAIK doesn't do tail call optimization) provides
the expected result without 'return' being part of the last statement.
sub counter {
my ($n,$acc) = #_;
return $acc if ($n==0);
counter(int($n/10), $acc+1);
}
print "Count is:" . counter(1234,0) ."\n"
Result: Count is:4
(The versions of Perl I ran above code chunk are : 5.14.4 and 5.8.5).
My questions are:
Is Tail Call optimization the reason for the behavior shown in above chunk of Python code.
If that were the case then why behavior of perl code differs, which doesn't do TCO either.
Doesn't have to do with the missing of tail optimization at all. Functions in Python need the keyword return explicitly, otherwise is assumed their return None.
I know Ruby doesn't behave that way, it returns the value of the last executed expression. With Perl it must be the same.
It is nothing that clever, just the fact that Python programs behave that way :)
See the disassembly for both Python functions. You may see how the one having the return value actually calls the function and return the value on top of the stack. The one that doesn't have it, see that have two instructions after the funciont call, which load constant None and return it.
def count(x,acc=0):
if x==0:
return acc
return count(x/10,acc+1)
def count2(x,acc=0):
if x==0:
return acc
count(x/10,acc+1)
In [7]: import dis
In [8]: dis.dis(count)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (0)
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_FALSE 16
3 12 LOAD_FAST 1 (acc)
15 RETURN_VALUE
4 >> 16 LOAD_GLOBAL 0 (count)
19 LOAD_FAST 0 (x)
22 LOAD_CONST 2 (10)
25 BINARY_DIVIDE
26 LOAD_FAST 1 (acc)
29 LOAD_CONST 3 (1)
32 BINARY_ADD
33 CALL_FUNCTION 2
36 RETURN_VALUE
In [9]: dis.dis(count2)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (0)
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_FALSE 16
3 12 LOAD_FAST 1 (acc)
15 RETURN_VALUE
4 >> 16 LOAD_GLOBAL 0 (count)
19 LOAD_FAST 0 (x)
22 LOAD_CONST 2 (10)
25 BINARY_DIVIDE
26 LOAD_FAST 1 (acc)
29 LOAD_CONST 3 (1)
32 BINARY_ADD
33 CALL_FUNCTION 2
36 POP_TOP
37 LOAD_CONST 0 (None)
40 RETURN_VALUE
Without the return, the only case where your return something if when acc == 0; for any other call to your count recursive method, you don't return anything, hence the None received.
Unlike other languages (scala, apparently perl as well, probably others), python does not return the last statement by default, you have to call return explicitely.
Tail call elimination does not prevent Perl's semantics (though without Perl semantics, you'd have far fewer tail calls since every function would implicitly end with return;). It's purely a language design choice. The reason Perl and Python differ is that they weren't designed by the same people.
The syntax for returning a value varies by language simply due to choice. The designers of Python opted to require an explicit return statement. In QBasic, you had to assign the value to return to a variable that shared the same name as the function.
Functions in Python without a return statement return the value None.
In this case, you are only returning a value when x == 0, therefore the None that you get. Check the Python tutorial for more info: http://docs.python.org/2/tutorial/controlflow.html#defining-functions
I actually use Python and Flask for my devblog. I know that depending of the language, it is advisable to use a explicit else when it is not obligatory, but I don't know how it's work in Python.
By example, I have a a function with a if that return something if the statement is true. So, The else is not necessary because with or without it, the execution continue normally.
def foo(bar):
if not isinstance(foo, list):
return "an error"
else: # not necessary
return "something"
So, I should use it like this, or like :
def foo(bar):
if not isinstance(foo, list):
return "an error"
return "something"
In the first case, Python will add an explicit return None to the end of the function - even though we can see it's not really needed. In the second case it doesn't.
I don't see any advantage to having the else: there
>>> import dis
>>> def f():
... if 1>2:
... return 2
... return 3
...
>>> def g():
... if 1>2:
... return 2
... else:
... return 3
...
>>> dis.dis(f)
2 0 LOAD_CONST 1 (1)
3 LOAD_CONST 2 (2)
6 COMPARE_OP 4 (>)
9 POP_JUMP_IF_FALSE 16
3 12 LOAD_CONST 2 (2)
15 RETURN_VALUE
4 >> 16 LOAD_CONST 3 (3)
19 RETURN_VALUE
>>> dis.dis(g)
2 0 LOAD_CONST 1 (1)
3 LOAD_CONST 2 (2)
6 COMPARE_OP 4 (>)
9 POP_JUMP_IF_FALSE 16
3 12 LOAD_CONST 2 (2)
15 RETURN_VALUE
5 >> 16 LOAD_CONST 3 (3)
19 RETURN_VALUE
20 LOAD_CONST 0 (None)
23 RETURN_VALUE
This has already been discussed here: If-Else-Return or just if-Return?
Essentially, the two forms are equivalent in terms of efficiency because the machine has to make a jump anyway. So it boils down to coding style and you'll have to decide that on your own (or with your team).
Personally, I prefer with the else statement for readability.
It really makes no difference. Either way will do the same thing.
I prefer the latter, because it's one less line of code.
Je préfère cette dernière
From Chromium's style guide:
Don't use else after return:
# Bad
if (foo)
return 1;
else
return 2;
# Good
if (foo)
return 1;
return 2;
return foo ? 1 : 2;
I am quite new to programming, and in the context of this question I was reminded that there is often the case where I am not sure if I should use an "else" or "elif", e.g., in a scenario like that.
1)
if numA < numB:
print('numA is smaller')
elif numB < numA:
print('numB is smaller')
else:
print('both numbers are equal')
2)
if numA < numB:
print('numA is smaller')
elif numB < numA:
print('numB is smaller')
elif numA == numB:
print('both numbers are equal')
I think it would not make a huge difference, or am I wrong? In other examples the second variant might be more "robust" in general, I think.