Cla*_*dio 4 python list-comprehension
L我想在以下代码中翻转循环:
L = [1,2,5,2,1,1,3,4]
L_unique = []
for item in L:
if item not in L_unique:
L_unique.append(item)
Run Code Online (Sandbox Code Playgroud)
列表理解如下:
L_unique = [ item for item in L if item not in ???self??? ]
Run Code Online (Sandbox Code Playgroud)
这在Python中可能吗?如果可能的话,怎样才能做到呢?
Mec*_*Pig 13
列表推导实际上创建了一个匿名函数然后调用它,但是构建的列表不会存储在局部变量字典中,而是存储在Python中维护的堆栈中,因此很少有Python级别的操作可以获得这个列表(这是gc一个疯狂但可行的选择。抱歉)对于我之前的夸张,使用的解决方案gc附在最后):
>>> [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
Run Code Online (Sandbox Code Playgroud)
对于您提供的示例,您可以使用list(dict.fromkeys(L))Python 3.7+ 获得相同的结果。这里我用dict而不是set因为dict可以保留插入顺序:
>>> list(dict.fromkeys(L))
[1, 2, 5, 3, 4]
Run Code Online (Sandbox Code Playgroud)
根据 @KellyBundy ,我找到的当前方法是使用gc.get_objects,但此操作非常昂贵(因为它收集了超过 1000 个对象),并且我无法确定其准确性:
>>> [item for item in L if item not in gc.get_objects(0)[-1]]
[1, 2, 5, 3, 4]
Run Code Online (Sandbox Code Playgroud)
通过缓存降低操作成本:
>>> 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]
Run Code Online (Sandbox Code Playgroud)
Kel*_*ndy 12
这是可能的。这是一个可以做到这一点的黑客,但我不会在实践中使用它,因为它很讨厌并且依赖于可能改变的实现细节,而且我相信它也不是线程安全的。只是为了证明这是可能的。
你的“某处必须存在一个存储理解的当前状态的对象”基本上是正确的(尽管它不一定必须是Python列表对象,Python可以以其他方式存储元素并仅创建列表对象然后)。
我们可以在垃圾回收跟踪的对象中找到新的列表对象。在创建推导式列表之前收集列表的 ID ,然后再次查看并获取之前不存在的列表。
演示:
import gc
L = [1,2,5,2,1,1,3,4]
L_unique = [
item
# the hack to get self
for ids in ({id(o) for o in gc.get_objects() if type(o) is list},)
for self in (o for o in gc.get_objects() if type(o) is list and id(o) not in ids)
for item in L
if item not in self
]
print(L_unique)
Run Code Online (Sandbox Code Playgroud)
输出(在线尝试!):
[1, 2, 5, 3, 4]
Run Code Online (Sandbox Code Playgroud)
在从 Python 3.7 到 Python 3.11 的多个版本中进行了测试和工作。
对于具有您所要求的确切样式的替代方案,仅替换您的???self???,请参阅 Mechanic Pig 的更新答案。