为什么这两种迭代形式产生不同的结果?

时间:2016-03-07 02:23:52

标签: python

alist = ['1', '2', '3']
blist = alist[:]

for x in alist:
    if not "@gmail.com" in alist:
        x = x + "@gmail.com"

for x in range(len(blist)):
    if not "@gmail.com" in blist[x]:
        blist[x] = blist[x] + "@gmail.com"

第一个代码块没有实现我需要的东西,但是第二个代码块没有实现。

这两个代码块之间有什么区别?

4 个答案:

答案 0 :(得分:2)

Shorty:在第一个示例中,您没有改变列表值,在第二个示例中,这样做。

在第一个循环中,您修改了x,它实际上是列表项的副本,但不是该项,在第二个示例中,您通过索引访问它来修改列表项。请参阅Immutable vs Mutable types以获取有关可变和不可变类型的更多信息

但是,如果要在列表中应用包含可变类型的循环,则for循环将修改这些项:

alist = [['1'], ['2'], ['3']]
blist = [['1'], ['2'], ['3']]

for x in alist:
    x.append("@gmail.com")
print alist    

for x in range(len(blist)):
    blist[x].append("@gmail.com")
print blist

答案 1 :(得分:2)

当您在代码的第一个版本中执行x = x + "@gmail.com"时,您将创建一个新值并重新绑定名称x以引用它。这对alist没有影响,即使这是前一个x值的来源。

另一方面,当您执行blist[x] = blist[x] + "@gmail.com"时,您将明确修改列表。您正在重新绑定blist[x]以引用新值。

请注意,对于不同的列表内容,您可能已经能够使用“就地”修改使代码的第一个版本工作。字符串是不可变的,因此没有就地操作。但是,如果alist包含list等可变项,则x += ["foo"]之类的代码会扩展内部列表。如果对象的类型支持(+=方法),__iadd__运算符将尝试进行就地添加。但是对于不支持inplace操作的类型,它与x = x + y相同,它会遇到与您遇到的相同的问题。

答案 2 :(得分:1)

你的拳头循环可以固定为:

for i, x in enumerate(alist):
    if "@gmail.com" not in x:
        alist[i] = x + "@gmail.com"

或者,更简洁:

email="@gmail.com"
alist=[x+email if email not in x else x for x in alist]

如果该字符串在字符串中的任何位置,in将返回true,则在上述两种情况下都优先使用not x.endswith("@gmail.com")

答案 3 :(得分:0)

因为字符串是不可变的:

https://docs.python.org/2/reference/datamodel.html

  

值可以改变的对象被认为是可变的;对象的   一旦创建它们,值就不可更改,称为不可变。 (该   包含对a的引用的不可变容器对象的值   当后者的值改变时,可变对象可以改变;然而   容器仍然被认为是不可变的,因为收集了   它包含的对象无法更改。所以,不变性不是   与具有不可改变的值严格相同,它更加微妙。)   对象的可变性由其类型决定;例如,   数字,字符串和元组是不可变的,而词典和   列表是可变的。

在第一个示例中,每次将其他值连接到它时,您将创建一个名为x new 变量。

我是第二个例子,但您只需更改list的相同索引处的值。