Here is an example of a set comprehension:
inp = [1,2,3,4,4,3,5]
s_comp = {element for element in inp}
# {1, 2, 3, 4, 5}
Does python know to convert the below into an immediate set comprehension (skipping over the initial list?) or does this first do a list comprehension and then convert the resulting list into a set (in other words, it's just a waste of resources using this notation to create a set).
s_comp = set([element for element in inp])
# {1, 2, 3, 4, 5}
Note, from cProfile
it seems like it first does a list comprehension for the latter. Though each of them have the same amount of steps (I would imagine the first one should have one step less?).
>>> cProfile.run('{element for element in [1,2,3,4,4,3,5]}')
4 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 <string>:1(<setcomp>)
1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
>>> cProfile.run('set([element for element in [1,2,3,4,4,3,5]])')
4 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <string>:1(<listcomp>) # list not set
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
If you have an iterable it is a waste of resources using a list comprehension []
instead of a set comprehension directly {}
.
If you look at the bytecode of func A below you'll see that Python is building a List and passing it as a parameter to set() function.
In the bytecode of Func B Python is optimized to build a Set directly.
I have used the following code to do an analysis.
from dis import dis
def a():
return set([x for x in range(1, 10)])
def b():
return {x for x in range(1, 10)}
print('Dis Func A\n')
print(dis(a))
print('Dis Func B\n')
print(dis(b))
Dis Func A
5 0 LOAD_GLOBAL 0 (set)
2 LOAD_CONST 1 (<code object <listcomp> at 0x00000249F64B2EA0, file "c:\Projects\stack-overflow\asd.py", line 5>)
4 LOAD_CONST 2 ('a.<locals>.<listcomp>')
6 MAKE_FUNCTION 0
8 LOAD_GLOBAL 1 (range)
10 LOAD_CONST 3 (1)
12 LOAD_CONST 4 (10)
14 CALL_FUNCTION 2
16 GET_ITER
18 CALL_FUNCTION 1
20 CALL_FUNCTION 1
22 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x00000249F64B2EA0, file "c:\Projects\stack-overflow\asd.py", line 5>:
5 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 8 (to 14)
6 STORE_FAST 1 (x)
8 LOAD_FAST 1 (x)
10 LIST_APPEND 2
12 JUMP_ABSOLUTE 4
>> 14 RETURN_VALUE
Dis Func B
9 0 LOAD_CONST 1 (<code object <setcomp> at 0x00000249F64CE030, file "c:\Projects\stack-overflow\asd.py", line 9>)
2 LOAD_CONST 2 ('b.<locals>.<setcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (1)
10 LOAD_CONST 4 (10)
12 CALL_FUNCTION 2
14 GET_ITER
16 CALL_FUNCTION 1
18 RETURN_VALUE
Disassembly of <code object <setcomp> at 0x00000249F64CE030, file "c:\Projects\stack-overflow\asd.py", line 9>:
9 0 BUILD_SET 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 8 (to 14)
6 STORE_FAST 1 (x)
8 LOAD_FAST 1 (x)
10 SET_ADD 2
12 JUMP_ABSOLUTE 4
>> 14 RETURN_VALUE