列表理解语句中的 OR 和 ELSE 是否相似

Is OR and ELSE similar in list comprehension statement

请帮助我理解为什么会这样。下面的代码列出了可迭代对象中的重复项。但是,使用 or 运算符的行为类似于 if..else 语句中的 else..

j = set()
my_list = [1, 2, 3 ,3 , 3 ,4, 4]
j_add = j.add
twice = set(x for x in my_list if x in j or j_add(x))
print list(twice)

预计该行是:

 twice = set(x for x in my_list if x in j else j_add(x))

想法或 returns 布尔值而不是值

or 运算符 returns 最后计算的参数,可能是也可能不是布尔值。

此行为在 Documentation:

中进行了解释

Note that neither and nor or restrict the value and type they return to False and True, but rather return the last evaluated argument. This is sometimes useful, e.g., if s is a string that should be replaced by a default value if it is empty, the expression s or 'foo' yields the desired value.

当然,记住什么被解释为假,什么被解释为真会有所帮助:

[T]he following values are interpreted as false: False, None, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true.

所以在表达式中:

A = B or C

正如@MartijnPieters 在评论中指出的那样,or 表达式短路。如果第一个参数(在本例中为 B)被解释为真,则整个表达式必须为真,因此第二个参数(C)永远不会被计算。因此第一个参数 (B) 是 "the last evaluated argument" 并且是返回的内容。但是,如果第一个参数 (B) 被解释为 false,则仍必须评估第二个参数 (C) 以确定表达式的真实性(不会发生短路)。在这种情况下,"the last evaluated argument" 是第二个参数 (C),无论表达式的计算结果是真还是假,都会返回它。

有效地实现了与Conditional Expression相同的效果:

A = B if B else C

然而,条件表达式仅在 2.5 版中添加到 Python,而布尔运算符行为从一开始就存在(或者至少很长一段时间)。大多数经验丰富的 Python 程序员很容易识别并习惯使用 A = B or C。条件表达式通常保留用于更复杂的条件,这些条件不适用于简单的 or(例如,在 A = B if X else C 中,条件不是基于 B 的真实性,而是 X],可以是从简单值到复杂表达式的任何值)。

但是,您需要小心,因为正如 JaredGoguen 在他的回答中指出的那样,将 OP 示例中的 or 更改为 else 实际上会改变代码的行为。该代码的编写取决于 or 运算符的这种特定行为。您不能只用条件表达式替换对 or 的任何使用。可能还需要额外的重构。

我可能会在这里做一个价值判断,说这不是好的代码,因为它利用了or的短路行为来产生副作用。

考虑给定的条件:if x in j or j_add(x).

x in j时,or短路,跳过条件的j_add(x)部分,求值为True.

x not in j 时,将检查语句 j_add(x) 的真实性。此方法 returns None,它是假的,因此 or 评估为 False.

因此,整个条件的计算结果与 x in j 相同。然而 j_add(x) 有将 x 添加到 j 的副作用!正在利用此副作用来记录唯一​​成员 my_list 快速理解。

or 更改为 else 仍会根据需要构造 j,但会不恰当地添加 None,return 的值 j_add(x), 至 twice.