3

我正在阅读一篇关于 python 删除列表中重复元素的文章。有一个函数定义为:

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 for x in seq if x not in seen and not seen.add(x)]的语法

这是什么语法?我怎么读?

谢谢你。

4

3 回答 3

3

它被称为列表推导,它们提供了一种语法上更紧凑、更有效的方式来编写基于普通 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
于 2013-06-18T06:40:50.753 回答
3

该构造称为列表推导 [x for x in seq if some_condition]。在这种情况下,条件是它x不在结果列表中。您在运行时无法检查列表推导的结果,因此它使用名为的集合跟踪其中的项目seen

这里的这种情况有点棘手,因为它依赖于副作用

not in seen and not seen.add(x)

seen.add()总是返回None。如果看到该项目

not in seenFalse,所以and短路。

如果没有看到该项目,

not in seenisTruenot seen.add(x)is also True,因此该项目被包括在内,并且作为副作用,它被添加到seen集合中

虽然这种类型的事情可能很有趣,但这并不是表达意图的特别清晰的方式。

我认为不那么棘手的方式更具可读性

def f8(seq):
    seen = set()
    result = []
    for x in seq:
        if x not in seen:
            result.append(x)
            seen.add(x)
    return result
于 2013-06-18T06:41:40.257 回答
3

首先,列表推导通常很容易阅读,这里有一个简单的例子:

[x for x in seq if x != 2]

翻译为:

result = []
for x in seq:
    if x != 2:
        result.append(x)

您无法阅读此代码的原因是因为它不是我在此问题中所述的可读和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 的列表理解速度优化。

None如果 Python 方法修改了数据结构,它们通常会返回(pop是例外之一)

我还注意到,当前接受的执行此操作 ( 2.7+) 的方式更易读且不使用hack,如下所示:

>>> from collections import OrderedDict
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(OrderedDict.fromkeys(items))
[1, 2, 0, 3]

字典键必须是唯一的,因此会过滤掉重复项。

于 2013-06-18T06:48:13.313 回答