【发布时间】:2014-02-28 01:12:03
【问题描述】:
这是我的 Python 代码:
# 1)
if (x not in z for z in y):
# 2)
if (x not in y):
其中 y 可以是如下列表:
y = ['1','2','3']
谁能解释一下这两个句子的区别? 谢谢!
【问题讨论】:
标签: python data-structures containers generator membership
这是我的 Python 代码:
# 1)
if (x not in z for z in y):
# 2)
if (x not in y):
其中 y 可以是如下列表:
y = ['1','2','3']
谁能解释一下这两个句子的区别? 谢谢!
【问题讨论】:
标签: python data-structures containers generator membership
首先,(x not in z for z in y) 是一个生成器语句,如果 if 在它前面,它总是返回 True。
if (x not in z for z in y): # Always returns True
这可用于查看任何或所有嵌套迭代是否包含x。
例如
if any(x in z for z in y): # Returns True if any of the z's contain x
if all(x in z for z in y): # Returns True only if all of the z's contain x
所以如果y 是这样的:
y = ['hello','how','are','you']
如果x 是,例如'e',那么上面的any 推导将返回True,但all 推导将返回False。
所以这就是生成器理解中发生的事情:如果 y 是一个列表,并且您使用以下代码进行测试:
(x not in z for z in y)
y 中的 z 必须是可迭代的,以便测试包含哪些字符串,但在这种情况下,您只会看到长度为 1 的字符串中是否存在某些内容。一个更好的例子是使用整数:
y = [1, 2, 3]
和
if (x not in z for z in y):
会失败,因为整数是不可迭代的,但是
if (x not in y):
会成功,因为您可以测试实际列表中的成员资格。
当你有
y = ['1','2','3']
类似的嵌套级别是:
y = [(1,), (2,), (3,)]
与
(x not in z for z in y)
您正在测试 x 是否在其中一个元组中。
这有意义吗?
【讨论】:
x = 'h' > True; x = 'p' > False; x = 'hello' > False
让我们先从简单的开始:
if (x not in y):
括号在那里没有任何意义,所以这等价于:
if x not in y:
in operator 检查某些东西是否包含在其他东西中。在您的情况下,您有一个列表y,因此您正在检查列表y 中是否不包含 (not in) 的内容(x)。所以'1' not in y 将是False,因为'1' 是y 的一个元素,而'4' not in y 将是True,因为'4' 不是y 的一个元素。
另一个是完全不同的东西:
if (x not in z for z in y)
这里有一个generator expression。生成器表达式的格式为(x for z in y),等效于以下代码:
for z in y:
yield x
您之前可能听说过list comprehensions;这些是相似的,但使用方括号而不是括号:[x for z in y]。当他们返回一个列表时,他们更容易理解。它们等价于:
lst = []
for z in y:
lst.append(x)
return lst
本质上,您是在循环y 的元素,在迭代中调用每个元素
z 并为该元素返回 x。在您的情况下,x 本身就是一个表达式:x not in z,这与上面基本相同:您正在检查 x 是否不包含在z 中。
现在,生成器表达式有点复杂,因为它们是在向它请求元素时计算的,所以我们现在假设我们有一个列表推导式
if [x not in z for z in y]:
所以它的作用是为y 中的每个元素z 计算x not in z。所以对于你的y,结果列表是这样的:
[x not in '1', x not in '2', x not in '3']
对于真正的x,这将导致一个包含三个布尔值的列表。现在一个非空列表总是正确的,所以不管这个检查的结果如何,if-check 都会成功。
生成器表达式将返回一个生成器,它是一个比列表更复杂的对象。不过它也很真实,因此无论单个值如何,您的检查也都会成功。
现在想象一下,我们要确保对于列表中的这三个元素,我们希望所有检查的结果都是 True。为此,我们可以使用 all() 函数,它实质上检查列表(或生成器中的值)是否仅包含真值。
if all(x not in z for z in y):
所以如果x 不包含在列表y 的任何元素中,这将成功。另一方面,如果我们想检查列表或生成器中是否至少有一个真实值,那么我们可以改用any() 函数。
【讨论】:
这个
if (x not in z for z in y):
等价于
if True:
因为
>>> (x not in z for z in y)
<generator object <genexpr> at 0x000000E7AE26FB88>
>>> bool(_)
True
这个
if (x not in y):
是一样的
if x not in y:
内部解析为
if not y.__contains__(x):
在第一种情况下,您可能打算这样写:
if any(x not in z for z in y):
# same as
if not all(x in z for z in y):
或:
if all(x not in z for z in y):
# same as
if not any(x in z for z in y):
【讨论】:
我假设这是一个普遍问题,列表中的实际值并不重要。
为:
1) if (x not in z for z in y):
语句中的for 表示您有一个“列表理解”或“生成器表达式”(在括号内)。它将生成一个列表。这是一个带有过滤器的列表理解(x not in z 部分)。但最终结果将是一个可能为空也可能不是空的列表。现在if 语句将评估它的“真实性”,其中空列表被认为是错误的,非空列表是真实的。
2) if (x not in y):
这是一个直接的“包含测试”,直接测试 x 是否包含(或不包含)在可迭代的 y 中,并返回一个布尔值。这可能是一个快速测试,具体取决于 y 是什么类型的对象。
在大多数情况下,第一种形式可能较慢且不必要。第一个必须创建然后销毁一个临时列表。
【讨论】: