Python一行中的for和if

60
我遇到了Python的问题。 我创建了一个简单的列表:
>>> my_list = ["one","two","three"]

我希望创建一行代码来查找字符串。

例如,我有以下代码:

>>> [(i) for i in my_list if i=="two"]
['two']

但是当我观察变量时,它是错误的(我发现我的列表的最后一个值):

>>> print i
three

为什么我的变量包含的是最后一个元素,而不是我想要找到的那个元素?


4
如果你想找到符合某些条件的项目列表,则使用[i for i in my_list if ...]。如果你想要找到符合某些条件的一个项目,考虑使用next; 例如:x = next(i for i in my_list if ...) - khelwood
我不会包含该值,它仍将被分配所有值。结果只包含符合条件的值。 - matt
你没有错,你的解释器也没有错。只是循环会一直执行到最后一个值,即使条件不满足,所以你得到了“three”。为了避免这种情况,你可以按照@khelwood所说的去做。 - The6thSense
为什么不使用"two" in mylist(它将返回一个布尔值)或者mylist.index("two")(它将返回找到的字符串所在的位置)?既然你已经拥有了你要查找的字符串,那么重复返回它的搜索结果是毫无意义的,不是吗? - Tim Pietzcker
8个回答

76

您正在使用列表推导式生成过滤后的列表。即使已经从生成的列表中进行了筛选,i 仍然绑定到每个元素上,并且最后一个元素仍然是 'three'

您不应该使用列表推导式来挑选一个元素。只需使用一个for循环,并使用break结束它:

for elem in my_list:
    if elem == 'two':
        break

如果你必须使用一行代码(这与Python的哲学相悖,其中可读性至关重要),请使用next()函数和生成器表达式:

i = next((elem for elem in my_list if elem == 'two'), None)

如果没有找到匹配的元素,则会将i设置为None

上述示例并不是很有用的筛选器;本质上您正在测试值'two'是否在列表中。您可以使用in进行操作:

elem = 'two' if 'two' in my_list else None

67

当您执行操作时

>>> [(i) for i in my_list if i=="two"]

i 被迭代遍历 my_list。当列表解析完成评估时,i 被赋值为迭代中的最后一项,即 "three"


1
嗨,我用这段代码解决了这个问题:res = [(i) for i in my_list if i=="two"]!它正确吗? - rostonik
1
我认为值得一提的是,在旧版本(3.x 之前)的 Python 中,i 只被赋值给了 old 中的最后一个项目。在 Python 3.x 中,变量作用域仅限于列表推导式内部,因此在推导式外部,您将看到 i 的先前值,或者如果它没有先前值,则未定义。 - Duncan
1
@Cong Ma,您拒绝了一次编辑,该编辑实际上解决了问题,即 OP 没有将结果分配给一个值。 - matt
他问:“为什么……”,这是一个答案。如果有必要,他可以自行决定是否将其分配给任何东西。 - Cong Ma
4
“else” 怎么样? - Dee

24

在列表推导式中,循环变量i会变为全局变量。在for循环迭代之后,它成为指向列表中最后一个元素的引用。

如果你想要所有匹配项,那么将列表赋值给一个变量:

在列表推导式中,循环变量i会变为全局变量。在for循环迭代之后,它成为指向列表中最后一个元素的引用。

如果你想要获取所有匹配项,则将列表分配给一个变量:

filtered =  [ i for i in my_list if i=='two']
如果你只想要第一个匹配项,可以使用函数生成器。
try:
     m = next( i for i in my_list if i=='two' )
except StopIteration:
     m = None

8

简短回答:

  1. 带有if语句的一行循环
my_list = [1, 2, 3]
[i for i in my_list if i==2]
  1. 在一行循环中同时使用if和else语句。 不幸的是,我们无法像上面那样将if-else语句放在末尾。
[i if i==2 else "wrong" for i in my_list]

5

在Python3中,当您尝试打印变量i时,它将超出作用域。

为了获得您想要的值,您应该将操作的结果存储在一个新变量中:

my_list = ["one","two","three"]
result=[ i for i in my_list if i=="two"]
print(result)

然后您将得到以下输出

['two']

3
打印出 "three" 的原因是你没有定义数组。与你所做的相当的代码如下:
arr = []
for i in array :
    if i == "two" :
        arr.push(i)
print(i)

你正在询问它所查找的最后一个元素,这不是你应该做的。你需要将数组存储到一个变量中,以获取元素。
你正在做的相当于以下英文表述:
You: "I need you to print all the elements in this array that equal two, but in an array. And each time you cycle through the list, define the current element as I."
Computer: "Here: ["two"]"
You: "Now tell me 'i'"
Computer: "'i' is equal to "three"
You: "Why?"

'i'等于"three"的原因是因为"three"是上一次定义为I的内容

计算机执行了以下操作:

i = "one"
i = "two"
i = "three"

print(["two"])

因为你要求它这么做。

如果你想要索引,请点击这里。 如果你想要数组中的值,请定义数组,例如:

MyArray = [(i) for i in my_list if i=="two"]

1

Found this one:

[x for (i,x) in enumerate(my_list) if my_list[i] == "two"]

将打印出以下内容:
["two"]

我能不能不用 [ ] 来做这件事?!! - Yasmine

0

你的代码

[(i) for i in my_list if i=="two"]

等于

a=[]
for i in my_list:
  if i=="two":
    a.append(i)

所以它遍历整个 my_list 并命中最后一个项目 "three",但仅返回等于 "two" 的内容并放入新列表中


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接