List comprehension actually makes an anonymous function then call it, but the list built will not be stored in local variable dictionary, but in the stack maintained in Python, so few Python level operations can obtain this list (gc
is a crazy but feasible choice. Sorry for my exaggeration before, the solution using gc
is attached at the end):
>>> [locals().copy() for i in range(3)]
[{'.0': <range_iterator at 0x207eeaca730>, 'i': 0}, # does not contain the built list
{'.0': <range_iterator at 0x207eeaca730>, 'i': 1},
{'.0': <range_iterator at 0x207eeaca730>, 'i': 2}]
>>> dis('[i for i in iterable]')
1 0 LOAD_CONST 0 (<code object <listcomp> at 0x00000211FEAFD000, file "<dis>", line 1>)
2 LOAD_CONST 1 ('<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_NAME 0 (iterable)
8 GET_ITER
10 CALL_FUNCTION 1
12 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x00000211FEAFD000, file "<dis>", line 1>:
1 0 BUILD_LIST 0 # build an empty list and push it onto the stack
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 4 (to 14)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LIST_APPEND 2 # get the built list through stack and index
12 JUMP_ABSOLUTE 2 (to 4)
>> 14 RETURN_VALUE
For the example you provided, you can use list(dict.fromkeys(L))
to get the same results in Python 3.7+. Here I use dict
instead of set
because dict
can preserve the insertion order:
>>> list(dict.fromkeys(L))
[1, 2, 5, 3, 4]
According to @KellyBundy , the current method I have found is to use gc.get_objects
, but this operation is very expensive (because it collects more than 1000 objects) and I can't determine its accuracy:
>>> [item for item in L if item not in gc.get_objects(0)[-1]]
[1, 2, 5, 3, 4]
Making operations cheaper through caching:
>>> lst = None
>>> [item for item in L if item not in (lst := gc.get_objects(0)[-1] if lst is None else lst)]
[1, 2, 5, 3, 4]