我正在阅读有关python的article删除列表中的重复元素。 有一个函数定义为:
def f8(seq): # Dave Kirby
# Order preserving
seen = set()
return [x for x in seq if x not in seen and not seen.add(x)]
但是,我真的不懂语法 [x代表x,如果x未见,且未见过.add(x)]
这是什么语法?我怎么看?
谢谢。答案 0 :(得分:3)
它被称为list comprehension,它们提供了一种语法上更紧凑,更有效的方法来编写基于正常for循环的解决方案。
def f8(seq): # Dave Kirby
# Order preserving
seen = set()
return [x for x in seq if x not in seen and not seen.add(x)]
上述列表理解大致相当于:
def f8(seq):
seen = set()
lis =[]
for x in seq:
if x not in seen:
lis.append(x)
seen.add(x)
return lis
答案 1 :(得分:3)
该构造称为列表理解
[x for x in seq if some_condition]
。在这种情况下,条件是x
不在结果列表中。在运行列表推导时,您无法检查列表推导的结果,因此它使用名为seen
这种情况有点棘手,因为它依赖于副作用
not in seen and not seen.add(x)
seen.add()
始终返回None
。如果看到 项
not in seen
为False
,因此and
短路。
如果中的项,
not in seen
为True
而not seen.add(x)
也为True
,因此该项目已包含在内,作为副作用,它会被添加到{{1}设置
虽然这类事情很有趣,但表达意图并不是特别明确的方式。
我认为不那么棘手的方式更具可读性
seen
答案 2 :(得分:3)
首先,列表推导通常易于阅读,这是一个简单的例子:
[x for x in seq if x != 2]
转换为:
result = []
for x in seq:
if x != 2:
result.append(x)
你无法阅读这段代码的原因是因为它不是我所说的in this question可读和hacky代码:
def f8(seq):
seen = set()
return [x for x in seq if x not in seen and not seen.add(x)]
转换为:
def f8(seq):
seen = set()
result = []
for x in seq:
if x not in seen and not seen.add(x): # not seen.add(...) always True
result.append(x)
并且依赖于set.add
是一种始终返回None
的就地方法,因此not None
评估为True
的事实。
>>> s = set()
>>> y = s.add(1) # methods usually return None
>>> print s, y
set([1]) None
代码编写的原因是偷偷利用Python的列表理解速度优化。
Python方法通常会返回None
,如果他们修改了数据结构(pop
是例外情况之一)
我还注意到当前接受的这种方式(2.7+
)更易读并且不使用 hack ,如下所示:
>>> from collections import OrderedDict
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(OrderedDict.fromkeys(items))
[1, 2, 0, 3]
字典键必须是唯一的,因此过滤掉了重复项。