Why do these two functions have the same bytecode when disassembled under dis.dis?Python: analyze a list comprehension with disIs it possible to call a function from within a list comprehension without the overhead of calling the function?Speed comparison with Project Euler: C vs Python vs Erlang vs HaskellWhy do some functions have underscores “__” before and after the function name?Is list join really faster than string concatenation in python?Why is my 'xmap' function not any faster than built-in 'map'?Are list-comprehensions and functional functions faster than “for loops”?Why doesn't Python optimize away temporary variables?Python: why is one generator faster than other with `yield` inside?Why is this loop faster than a dictionary comprehension for creating a dictionary?How do I get LOAD_CLASSDEREF instruction after dis.dis?
Boot Windows from SAN
How much does Commander Data weigh?
"fF" letter combination seems to be typeset strangely or incorrectly
How to check whether a sublist exist in a huge database lists in a fast way?
What does "rel" in `mathrel` and `stackrel` stands for?
Where can/should I, as a high schooler, publish a paper regarding the derivation of a formula?
If someone uses the Command spell and says "drop", what happens?
Nothing like a good ol' game of ModTen
Why doesn't 'd /= d' throw a division by zero exception?
Evaluated vs. unevaluated Association
The Wires Underground
Are the players on the same team as the DM?
How were medieval castles built in swamps or marshes without draining them?
When calculating a force, why do I get different result when I try to calculate via torque vs via sum of forces at an axis?
Can $! cause race conditions when used in scripts running in parallel?
Why is the UK so keen to remove the "backstop" when their leadership seems to think that no border will be needed in Northern Ireland?
Another solution to create a set with two conditions
What are the occurences of total war in the Native Americans?
"There were either twelve sexes or none."
What is the right path to be followed on Chess.com for learning Chess?
How to gently end involvement with an online community?
How many birds in the bush?
How can I download a file through 2 SSH connections?
Redacting URLs as an email-phishing preventative?
Why do these two functions have the same bytecode when disassembled under dis.dis?
Python: analyze a list comprehension with disIs it possible to call a function from within a list comprehension without the overhead of calling the function?Speed comparison with Project Euler: C vs Python vs Erlang vs HaskellWhy do some functions have underscores “__” before and after the function name?Is list join really faster than string concatenation in python?Why is my 'xmap' function not any faster than built-in 'map'?Are list-comprehensions and functional functions faster than “for loops”?Why doesn't Python optimize away temporary variables?Python: why is one generator faster than other with `yield` inside?Why is this loop faster than a dictionary comprehension for creating a dictionary?How do I get LOAD_CLASSDEREF instruction after dis.dis?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
What follows is four functions that have the same output, but either written with a list comprehension or a tight loop, and a function call to vs an inline condition.
Interestingly, a
and b
have the same bytecode when disassembled, however b
is much faster than a
.
Moreover, d
, which uses a tight loop with no function call, is faster than a
which uses a list comprehension with a function call.
Why do functions a and b have the same bytecode, and why does b perform much better than a given the same bytecode?
import dis
def my_filter(n):
return n < 5
def a():
# list comprehension with function call
return [i for i in range(10) if my_filter(i)]
def b():
# list comprehension without function call
return [i for i in range(10) if i < 5]
def c():
# tight loop with function call
values = []
for i in range(10):
if my_filter(i):
values.append(i)
return values
def d():
# tight loop without function call
values = []
for i in range(10):
if i < 5:
values.append(i)
return values
assert a() == b() == c() == d()
import sys
>>> sys.version_info[:]
(3, 6, 5, 'final', 0)
# list comprehension with function call
>>> dis.dis(a)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBE8B300, file "<stdin>", line 2>)
2 LOAD_CONST 2 ('a.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
# list comprehension without function call
>>> dis.dis(b)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBB64270, file "<stdin>", line 2>)
2 LOAD_CONST 2 ('b.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
# a and b have the same byte code?
# Why doesn't a have a LOAD_GLOBAL (my_filter) and CALL_FUNCTION?
# c below has both of these
# tight loop with function call
>>> dis.dis(c)
2 0 BUILD_LIST 0
2 STORE_FAST 0 (values)
3 4 SETUP_LOOP 34 (to 40)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 1 (10)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 22 (to 38)
16 STORE_FAST 1 (i)
4 18 LOAD_GLOBAL 1 (my_filter)
20 LOAD_FAST 1 (i)
22 CALL_FUNCTION 1
24 POP_JUMP_IF_FALSE 14
5 26 LOAD_FAST 0 (values)
28 LOAD_ATTR 2 (append)
30 LOAD_FAST 1 (i)
32 CALL_FUNCTION 1
34 POP_TOP
36 JUMP_ABSOLUTE 14
>> 38 POP_BLOCK
6 >> 40 LOAD_FAST 0 (values)
42 RETURN_VALUE
# tight loop without function call
>>> dis.dis(d)
2 0 BUILD_LIST 0
2 STORE_FAST 0 (values)
3 4 SETUP_LOOP 34 (to 40)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 1 (10)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 22 (to 38)
16 STORE_FAST 1 (i)
4 18 LOAD_FAST 1 (i)
20 LOAD_CONST 2 (5)
22 COMPARE_OP 0 (<)
24 POP_JUMP_IF_FALSE 14
5 26 LOAD_FAST 0 (values)
28 LOAD_ATTR 1 (append)
30 LOAD_FAST 1 (i)
32 CALL_FUNCTION 1
34 POP_TOP
36 JUMP_ABSOLUTE 14
>> 38 POP_BLOCK
6 >> 40 LOAD_FAST 0 (values)
42 RETURN_VALUE
import timeit
>>> timeit.timeit(a) # list comprehension with my_filter
1.2435139456834463
>>> timeit.timeit(b) # list comprehension without my_filter
0.6717423789164627
>>> timeit.timeit(c) # no list comprehension with my_filter
1.326850592144865
>>> timeit.timeit(d) # no list comprehension no my_filter
0.7743895521070954
Why do a
and b
have the same byte code when disassembled? I would have expected b
to have better looking bytecode. Notably I would have thought that a
would need a LOAD_GLOBAL ? (my_filter)
and a CALL FUNCTION
. For example, c
is the same as a
but without the list comprehension, and it uses these bytecodes these on addresses 18 and 22.
However, even with the same bytecode, b
performs much better than a
. What's going on here?
Even more interesting, d
, which uses a tight loop but does not have the call to my_filter
, is faster than b
which uses the list comprehension but has the call to my_filter
. It looks like the overhead of using a function outweighs the overhead of a tight loop.
My goal here is to try to figure out if I can factor out conditions of a list comprehension into a function to make the list comprehension easier to read.
python python-3.x python-3.6 bytecode
add a comment |
What follows is four functions that have the same output, but either written with a list comprehension or a tight loop, and a function call to vs an inline condition.
Interestingly, a
and b
have the same bytecode when disassembled, however b
is much faster than a
.
Moreover, d
, which uses a tight loop with no function call, is faster than a
which uses a list comprehension with a function call.
Why do functions a and b have the same bytecode, and why does b perform much better than a given the same bytecode?
import dis
def my_filter(n):
return n < 5
def a():
# list comprehension with function call
return [i for i in range(10) if my_filter(i)]
def b():
# list comprehension without function call
return [i for i in range(10) if i < 5]
def c():
# tight loop with function call
values = []
for i in range(10):
if my_filter(i):
values.append(i)
return values
def d():
# tight loop without function call
values = []
for i in range(10):
if i < 5:
values.append(i)
return values
assert a() == b() == c() == d()
import sys
>>> sys.version_info[:]
(3, 6, 5, 'final', 0)
# list comprehension with function call
>>> dis.dis(a)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBE8B300, file "<stdin>", line 2>)
2 LOAD_CONST 2 ('a.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
# list comprehension without function call
>>> dis.dis(b)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBB64270, file "<stdin>", line 2>)
2 LOAD_CONST 2 ('b.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
# a and b have the same byte code?
# Why doesn't a have a LOAD_GLOBAL (my_filter) and CALL_FUNCTION?
# c below has both of these
# tight loop with function call
>>> dis.dis(c)
2 0 BUILD_LIST 0
2 STORE_FAST 0 (values)
3 4 SETUP_LOOP 34 (to 40)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 1 (10)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 22 (to 38)
16 STORE_FAST 1 (i)
4 18 LOAD_GLOBAL 1 (my_filter)
20 LOAD_FAST 1 (i)
22 CALL_FUNCTION 1
24 POP_JUMP_IF_FALSE 14
5 26 LOAD_FAST 0 (values)
28 LOAD_ATTR 2 (append)
30 LOAD_FAST 1 (i)
32 CALL_FUNCTION 1
34 POP_TOP
36 JUMP_ABSOLUTE 14
>> 38 POP_BLOCK
6 >> 40 LOAD_FAST 0 (values)
42 RETURN_VALUE
# tight loop without function call
>>> dis.dis(d)
2 0 BUILD_LIST 0
2 STORE_FAST 0 (values)
3 4 SETUP_LOOP 34 (to 40)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 1 (10)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 22 (to 38)
16 STORE_FAST 1 (i)
4 18 LOAD_FAST 1 (i)
20 LOAD_CONST 2 (5)
22 COMPARE_OP 0 (<)
24 POP_JUMP_IF_FALSE 14
5 26 LOAD_FAST 0 (values)
28 LOAD_ATTR 1 (append)
30 LOAD_FAST 1 (i)
32 CALL_FUNCTION 1
34 POP_TOP
36 JUMP_ABSOLUTE 14
>> 38 POP_BLOCK
6 >> 40 LOAD_FAST 0 (values)
42 RETURN_VALUE
import timeit
>>> timeit.timeit(a) # list comprehension with my_filter
1.2435139456834463
>>> timeit.timeit(b) # list comprehension without my_filter
0.6717423789164627
>>> timeit.timeit(c) # no list comprehension with my_filter
1.326850592144865
>>> timeit.timeit(d) # no list comprehension no my_filter
0.7743895521070954
Why do a
and b
have the same byte code when disassembled? I would have expected b
to have better looking bytecode. Notably I would have thought that a
would need a LOAD_GLOBAL ? (my_filter)
and a CALL FUNCTION
. For example, c
is the same as a
but without the list comprehension, and it uses these bytecodes these on addresses 18 and 22.
However, even with the same bytecode, b
performs much better than a
. What's going on here?
Even more interesting, d
, which uses a tight loop but does not have the call to my_filter
, is faster than b
which uses the list comprehension but has the call to my_filter
. It looks like the overhead of using a function outweighs the overhead of a tight loop.
My goal here is to try to figure out if I can factor out conditions of a list comprehension into a function to make the list comprehension easier to read.
python python-3.x python-3.6 bytecode
2
What's your python version? In 3.7, it also disassembles the<listcomp>
itself, which is of course quite different for your two functions.
– georg
8 hours ago
@georg I'm on Python 3.6.5
– Matthew Moisen
8 hours ago
1
The body of a list comprehension is compiled as if it were a nested function. Note the complete lack of any reference tomy_filter()
ina()
, you're obviously not seeing everything in the disassembly.
– jasonharper
8 hours ago
@georg Got it. Would you like to make an answer?dis.dis(a.__code__.co_consts[1])
anddis.dis(b.__code__.co_consts[1])
shows the difference. If you could show what it looks like in 3.7 that would be great as well.
– Matthew Moisen
8 hours ago
add a comment |
What follows is four functions that have the same output, but either written with a list comprehension or a tight loop, and a function call to vs an inline condition.
Interestingly, a
and b
have the same bytecode when disassembled, however b
is much faster than a
.
Moreover, d
, which uses a tight loop with no function call, is faster than a
which uses a list comprehension with a function call.
Why do functions a and b have the same bytecode, and why does b perform much better than a given the same bytecode?
import dis
def my_filter(n):
return n < 5
def a():
# list comprehension with function call
return [i for i in range(10) if my_filter(i)]
def b():
# list comprehension without function call
return [i for i in range(10) if i < 5]
def c():
# tight loop with function call
values = []
for i in range(10):
if my_filter(i):
values.append(i)
return values
def d():
# tight loop without function call
values = []
for i in range(10):
if i < 5:
values.append(i)
return values
assert a() == b() == c() == d()
import sys
>>> sys.version_info[:]
(3, 6, 5, 'final', 0)
# list comprehension with function call
>>> dis.dis(a)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBE8B300, file "<stdin>", line 2>)
2 LOAD_CONST 2 ('a.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
# list comprehension without function call
>>> dis.dis(b)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBB64270, file "<stdin>", line 2>)
2 LOAD_CONST 2 ('b.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
# a and b have the same byte code?
# Why doesn't a have a LOAD_GLOBAL (my_filter) and CALL_FUNCTION?
# c below has both of these
# tight loop with function call
>>> dis.dis(c)
2 0 BUILD_LIST 0
2 STORE_FAST 0 (values)
3 4 SETUP_LOOP 34 (to 40)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 1 (10)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 22 (to 38)
16 STORE_FAST 1 (i)
4 18 LOAD_GLOBAL 1 (my_filter)
20 LOAD_FAST 1 (i)
22 CALL_FUNCTION 1
24 POP_JUMP_IF_FALSE 14
5 26 LOAD_FAST 0 (values)
28 LOAD_ATTR 2 (append)
30 LOAD_FAST 1 (i)
32 CALL_FUNCTION 1
34 POP_TOP
36 JUMP_ABSOLUTE 14
>> 38 POP_BLOCK
6 >> 40 LOAD_FAST 0 (values)
42 RETURN_VALUE
# tight loop without function call
>>> dis.dis(d)
2 0 BUILD_LIST 0
2 STORE_FAST 0 (values)
3 4 SETUP_LOOP 34 (to 40)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 1 (10)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 22 (to 38)
16 STORE_FAST 1 (i)
4 18 LOAD_FAST 1 (i)
20 LOAD_CONST 2 (5)
22 COMPARE_OP 0 (<)
24 POP_JUMP_IF_FALSE 14
5 26 LOAD_FAST 0 (values)
28 LOAD_ATTR 1 (append)
30 LOAD_FAST 1 (i)
32 CALL_FUNCTION 1
34 POP_TOP
36 JUMP_ABSOLUTE 14
>> 38 POP_BLOCK
6 >> 40 LOAD_FAST 0 (values)
42 RETURN_VALUE
import timeit
>>> timeit.timeit(a) # list comprehension with my_filter
1.2435139456834463
>>> timeit.timeit(b) # list comprehension without my_filter
0.6717423789164627
>>> timeit.timeit(c) # no list comprehension with my_filter
1.326850592144865
>>> timeit.timeit(d) # no list comprehension no my_filter
0.7743895521070954
Why do a
and b
have the same byte code when disassembled? I would have expected b
to have better looking bytecode. Notably I would have thought that a
would need a LOAD_GLOBAL ? (my_filter)
and a CALL FUNCTION
. For example, c
is the same as a
but without the list comprehension, and it uses these bytecodes these on addresses 18 and 22.
However, even with the same bytecode, b
performs much better than a
. What's going on here?
Even more interesting, d
, which uses a tight loop but does not have the call to my_filter
, is faster than b
which uses the list comprehension but has the call to my_filter
. It looks like the overhead of using a function outweighs the overhead of a tight loop.
My goal here is to try to figure out if I can factor out conditions of a list comprehension into a function to make the list comprehension easier to read.
python python-3.x python-3.6 bytecode
What follows is four functions that have the same output, but either written with a list comprehension or a tight loop, and a function call to vs an inline condition.
Interestingly, a
and b
have the same bytecode when disassembled, however b
is much faster than a
.
Moreover, d
, which uses a tight loop with no function call, is faster than a
which uses a list comprehension with a function call.
Why do functions a and b have the same bytecode, and why does b perform much better than a given the same bytecode?
import dis
def my_filter(n):
return n < 5
def a():
# list comprehension with function call
return [i for i in range(10) if my_filter(i)]
def b():
# list comprehension without function call
return [i for i in range(10) if i < 5]
def c():
# tight loop with function call
values = []
for i in range(10):
if my_filter(i):
values.append(i)
return values
def d():
# tight loop without function call
values = []
for i in range(10):
if i < 5:
values.append(i)
return values
assert a() == b() == c() == d()
import sys
>>> sys.version_info[:]
(3, 6, 5, 'final', 0)
# list comprehension with function call
>>> dis.dis(a)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBE8B300, file "<stdin>", line 2>)
2 LOAD_CONST 2 ('a.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
# list comprehension without function call
>>> dis.dis(b)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBB64270, file "<stdin>", line 2>)
2 LOAD_CONST 2 ('b.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
# a and b have the same byte code?
# Why doesn't a have a LOAD_GLOBAL (my_filter) and CALL_FUNCTION?
# c below has both of these
# tight loop with function call
>>> dis.dis(c)
2 0 BUILD_LIST 0
2 STORE_FAST 0 (values)
3 4 SETUP_LOOP 34 (to 40)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 1 (10)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 22 (to 38)
16 STORE_FAST 1 (i)
4 18 LOAD_GLOBAL 1 (my_filter)
20 LOAD_FAST 1 (i)
22 CALL_FUNCTION 1
24 POP_JUMP_IF_FALSE 14
5 26 LOAD_FAST 0 (values)
28 LOAD_ATTR 2 (append)
30 LOAD_FAST 1 (i)
32 CALL_FUNCTION 1
34 POP_TOP
36 JUMP_ABSOLUTE 14
>> 38 POP_BLOCK
6 >> 40 LOAD_FAST 0 (values)
42 RETURN_VALUE
# tight loop without function call
>>> dis.dis(d)
2 0 BUILD_LIST 0
2 STORE_FAST 0 (values)
3 4 SETUP_LOOP 34 (to 40)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 1 (10)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 22 (to 38)
16 STORE_FAST 1 (i)
4 18 LOAD_FAST 1 (i)
20 LOAD_CONST 2 (5)
22 COMPARE_OP 0 (<)
24 POP_JUMP_IF_FALSE 14
5 26 LOAD_FAST 0 (values)
28 LOAD_ATTR 1 (append)
30 LOAD_FAST 1 (i)
32 CALL_FUNCTION 1
34 POP_TOP
36 JUMP_ABSOLUTE 14
>> 38 POP_BLOCK
6 >> 40 LOAD_FAST 0 (values)
42 RETURN_VALUE
import timeit
>>> timeit.timeit(a) # list comprehension with my_filter
1.2435139456834463
>>> timeit.timeit(b) # list comprehension without my_filter
0.6717423789164627
>>> timeit.timeit(c) # no list comprehension with my_filter
1.326850592144865
>>> timeit.timeit(d) # no list comprehension no my_filter
0.7743895521070954
Why do a
and b
have the same byte code when disassembled? I would have expected b
to have better looking bytecode. Notably I would have thought that a
would need a LOAD_GLOBAL ? (my_filter)
and a CALL FUNCTION
. For example, c
is the same as a
but without the list comprehension, and it uses these bytecodes these on addresses 18 and 22.
However, even with the same bytecode, b
performs much better than a
. What's going on here?
Even more interesting, d
, which uses a tight loop but does not have the call to my_filter
, is faster than b
which uses the list comprehension but has the call to my_filter
. It looks like the overhead of using a function outweighs the overhead of a tight loop.
My goal here is to try to figure out if I can factor out conditions of a list comprehension into a function to make the list comprehension easier to read.
python python-3.x python-3.6 bytecode
python python-3.x python-3.6 bytecode
edited 8 hours ago
Matthew Moisen
asked 8 hours ago
Matthew MoisenMatthew Moisen
5,38916 gold badges68 silver badges140 bronze badges
5,38916 gold badges68 silver badges140 bronze badges
2
What's your python version? In 3.7, it also disassembles the<listcomp>
itself, which is of course quite different for your two functions.
– georg
8 hours ago
@georg I'm on Python 3.6.5
– Matthew Moisen
8 hours ago
1
The body of a list comprehension is compiled as if it were a nested function. Note the complete lack of any reference tomy_filter()
ina()
, you're obviously not seeing everything in the disassembly.
– jasonharper
8 hours ago
@georg Got it. Would you like to make an answer?dis.dis(a.__code__.co_consts[1])
anddis.dis(b.__code__.co_consts[1])
shows the difference. If you could show what it looks like in 3.7 that would be great as well.
– Matthew Moisen
8 hours ago
add a comment |
2
What's your python version? In 3.7, it also disassembles the<listcomp>
itself, which is of course quite different for your two functions.
– georg
8 hours ago
@georg I'm on Python 3.6.5
– Matthew Moisen
8 hours ago
1
The body of a list comprehension is compiled as if it were a nested function. Note the complete lack of any reference tomy_filter()
ina()
, you're obviously not seeing everything in the disassembly.
– jasonharper
8 hours ago
@georg Got it. Would you like to make an answer?dis.dis(a.__code__.co_consts[1])
anddis.dis(b.__code__.co_consts[1])
shows the difference. If you could show what it looks like in 3.7 that would be great as well.
– Matthew Moisen
8 hours ago
2
2
What's your python version? In 3.7, it also disassembles the
<listcomp>
itself, which is of course quite different for your two functions.– georg
8 hours ago
What's your python version? In 3.7, it also disassembles the
<listcomp>
itself, which is of course quite different for your two functions.– georg
8 hours ago
@georg I'm on Python 3.6.5
– Matthew Moisen
8 hours ago
@georg I'm on Python 3.6.5
– Matthew Moisen
8 hours ago
1
1
The body of a list comprehension is compiled as if it were a nested function. Note the complete lack of any reference to
my_filter()
in a()
, you're obviously not seeing everything in the disassembly.– jasonharper
8 hours ago
The body of a list comprehension is compiled as if it were a nested function. Note the complete lack of any reference to
my_filter()
in a()
, you're obviously not seeing everything in the disassembly.– jasonharper
8 hours ago
@georg Got it. Would you like to make an answer?
dis.dis(a.__code__.co_consts[1])
and dis.dis(b.__code__.co_consts[1])
shows the difference. If you could show what it looks like in 3.7 that would be great as well.– Matthew Moisen
8 hours ago
@georg Got it. Would you like to make an answer?
dis.dis(a.__code__.co_consts[1])
and dis.dis(b.__code__.co_consts[1])
shows the difference. If you could show what it looks like in 3.7 that would be great as well.– Matthew Moisen
8 hours ago
add a comment |
2 Answers
2
active
oldest
votes
Note that both bytecodes for a
and b
only run <listcomp>
objects defined elsewhere.
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBE8B300, file "<stdin>", line 2>)
Since the wrapper functions a
and b
are identical, their bytecodes are the same, only the addresses of listcomps are different.
In python 3.7 the dis module also prints the listcomps, here's the complete code and the output:
import sys
import dis
def my_filter(n):
return n < 5
def a():
# list comprehension with function call
return [i for i in range(10) if my_filter(i)]
def b():
# list comprehension without function call
return [i for i in range(10) if i < 5]
print(sys.version)
print('-' * 70)
dis.dis(a)
print('-' * 70)
dis.dis(b)
--
3.7.3 (default, May 19 2019, 21:16:26)
[Clang 10.0.1 (clang-1001.0.46.4)]
----------------------------------------------------------------------
9 0 LOAD_CONST 1 (<code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>)
2 LOAD_CONST 2 ('a.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>:
9 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
----------------------------------------------------------------------
13 0 LOAD_CONST 1 (<code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>)
2 LOAD_CONST 2 ('b.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>:
13 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
For pythons < 3.7. see Python: analyze a list comprehension with dis
I have a follow-up Hail Mary here - would you mind taking a look?
– Matthew Moisen
7 hours ago
add a comment |
List-Comprehensions are converted to inner functions, because they built a separate namespace. The inner functions for the LC in a
and b
differ:
>>> dis.dis(a.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
>>> dis.dis(b.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
There you see the function call in a
and the comparision in b
.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57647670%2fwhy-do-these-two-functions-have-the-same-bytecode-when-disassembled-under-dis-di%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Note that both bytecodes for a
and b
only run <listcomp>
objects defined elsewhere.
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBE8B300, file "<stdin>", line 2>)
Since the wrapper functions a
and b
are identical, their bytecodes are the same, only the addresses of listcomps are different.
In python 3.7 the dis module also prints the listcomps, here's the complete code and the output:
import sys
import dis
def my_filter(n):
return n < 5
def a():
# list comprehension with function call
return [i for i in range(10) if my_filter(i)]
def b():
# list comprehension without function call
return [i for i in range(10) if i < 5]
print(sys.version)
print('-' * 70)
dis.dis(a)
print('-' * 70)
dis.dis(b)
--
3.7.3 (default, May 19 2019, 21:16:26)
[Clang 10.0.1 (clang-1001.0.46.4)]
----------------------------------------------------------------------
9 0 LOAD_CONST 1 (<code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>)
2 LOAD_CONST 2 ('a.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>:
9 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
----------------------------------------------------------------------
13 0 LOAD_CONST 1 (<code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>)
2 LOAD_CONST 2 ('b.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>:
13 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
For pythons < 3.7. see Python: analyze a list comprehension with dis
I have a follow-up Hail Mary here - would you mind taking a look?
– Matthew Moisen
7 hours ago
add a comment |
Note that both bytecodes for a
and b
only run <listcomp>
objects defined elsewhere.
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBE8B300, file "<stdin>", line 2>)
Since the wrapper functions a
and b
are identical, their bytecodes are the same, only the addresses of listcomps are different.
In python 3.7 the dis module also prints the listcomps, here's the complete code and the output:
import sys
import dis
def my_filter(n):
return n < 5
def a():
# list comprehension with function call
return [i for i in range(10) if my_filter(i)]
def b():
# list comprehension without function call
return [i for i in range(10) if i < 5]
print(sys.version)
print('-' * 70)
dis.dis(a)
print('-' * 70)
dis.dis(b)
--
3.7.3 (default, May 19 2019, 21:16:26)
[Clang 10.0.1 (clang-1001.0.46.4)]
----------------------------------------------------------------------
9 0 LOAD_CONST 1 (<code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>)
2 LOAD_CONST 2 ('a.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>:
9 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
----------------------------------------------------------------------
13 0 LOAD_CONST 1 (<code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>)
2 LOAD_CONST 2 ('b.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>:
13 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
For pythons < 3.7. see Python: analyze a list comprehension with dis
I have a follow-up Hail Mary here - would you mind taking a look?
– Matthew Moisen
7 hours ago
add a comment |
Note that both bytecodes for a
and b
only run <listcomp>
objects defined elsewhere.
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBE8B300, file "<stdin>", line 2>)
Since the wrapper functions a
and b
are identical, their bytecodes are the same, only the addresses of listcomps are different.
In python 3.7 the dis module also prints the listcomps, here's the complete code and the output:
import sys
import dis
def my_filter(n):
return n < 5
def a():
# list comprehension with function call
return [i for i in range(10) if my_filter(i)]
def b():
# list comprehension without function call
return [i for i in range(10) if i < 5]
print(sys.version)
print('-' * 70)
dis.dis(a)
print('-' * 70)
dis.dis(b)
--
3.7.3 (default, May 19 2019, 21:16:26)
[Clang 10.0.1 (clang-1001.0.46.4)]
----------------------------------------------------------------------
9 0 LOAD_CONST 1 (<code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>)
2 LOAD_CONST 2 ('a.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>:
9 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
----------------------------------------------------------------------
13 0 LOAD_CONST 1 (<code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>)
2 LOAD_CONST 2 ('b.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>:
13 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
For pythons < 3.7. see Python: analyze a list comprehension with dis
Note that both bytecodes for a
and b
only run <listcomp>
objects defined elsewhere.
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x00000211CBE8B300, file "<stdin>", line 2>)
Since the wrapper functions a
and b
are identical, their bytecodes are the same, only the addresses of listcomps are different.
In python 3.7 the dis module also prints the listcomps, here's the complete code and the output:
import sys
import dis
def my_filter(n):
return n < 5
def a():
# list comprehension with function call
return [i for i in range(10) if my_filter(i)]
def b():
# list comprehension without function call
return [i for i in range(10) if i < 5]
print(sys.version)
print('-' * 70)
dis.dis(a)
print('-' * 70)
dis.dis(b)
--
3.7.3 (default, May 19 2019, 21:16:26)
[Clang 10.0.1 (clang-1001.0.46.4)]
----------------------------------------------------------------------
9 0 LOAD_CONST 1 (<code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>)
2 LOAD_CONST 2 ('a.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1065c61e0, file "/w/test/x.py", line 9>:
9 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
----------------------------------------------------------------------
13 0 LOAD_CONST 1 (<code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>)
2 LOAD_CONST 2 ('b.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x1066188a0, file "/w/test/x.py", line 13>:
13 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
For pythons < 3.7. see Python: analyze a list comprehension with dis
answered 7 hours ago
georggeorg
164k36 gold badges220 silver badges320 bronze badges
164k36 gold badges220 silver badges320 bronze badges
I have a follow-up Hail Mary here - would you mind taking a look?
– Matthew Moisen
7 hours ago
add a comment |
I have a follow-up Hail Mary here - would you mind taking a look?
– Matthew Moisen
7 hours ago
I have a follow-up Hail Mary here - would you mind taking a look?
– Matthew Moisen
7 hours ago
I have a follow-up Hail Mary here - would you mind taking a look?
– Matthew Moisen
7 hours ago
add a comment |
List-Comprehensions are converted to inner functions, because they built a separate namespace. The inner functions for the LC in a
and b
differ:
>>> dis.dis(a.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
>>> dis.dis(b.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
There you see the function call in a
and the comparision in b
.
add a comment |
List-Comprehensions are converted to inner functions, because they built a separate namespace. The inner functions for the LC in a
and b
differ:
>>> dis.dis(a.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
>>> dis.dis(b.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
There you see the function call in a
and the comparision in b
.
add a comment |
List-Comprehensions are converted to inner functions, because they built a separate namespace. The inner functions for the LC in a
and b
differ:
>>> dis.dis(a.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
>>> dis.dis(b.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
There you see the function call in a
and the comparision in b
.
List-Comprehensions are converted to inner functions, because they built a separate namespace. The inner functions for the LC in a
and b
differ:
>>> dis.dis(a.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_GLOBAL 0 (my_filter)
10 LOAD_FAST 1 (i)
12 CALL_FUNCTION 1
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
>>> dis.dis(b.__code__.co_consts[1])
3 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 16 (to 22)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LOAD_CONST 0 (5)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 4
16 LOAD_FAST 1 (i)
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
>> 22 RETURN_VALUE
There you see the function call in a
and the comparision in b
.
answered 8 hours ago
DanielDaniel
33.8k4 gold badges32 silver badges63 bronze badges
33.8k4 gold badges32 silver badges63 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57647670%2fwhy-do-these-two-functions-have-the-same-bytecode-when-disassembled-under-dis-di%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
What's your python version? In 3.7, it also disassembles the
<listcomp>
itself, which is of course quite different for your two functions.– georg
8 hours ago
@georg I'm on Python 3.6.5
– Matthew Moisen
8 hours ago
1
The body of a list comprehension is compiled as if it were a nested function. Note the complete lack of any reference to
my_filter()
ina()
, you're obviously not seeing everything in the disassembly.– jasonharper
8 hours ago
@georg Got it. Would you like to make an answer?
dis.dis(a.__code__.co_consts[1])
anddis.dis(b.__code__.co_consts[1])
shows the difference. If you could show what it looks like in 3.7 that would be great as well.– Matthew Moisen
8 hours ago