列表理解和循环的结果不一样

时间:2014-01-11 05:46:01

标签: python

我试图通过将其ascii值移动2来改变字符串中的字符(使用ord())。 这就是我使用for循环的方式:

s='cde'
for i in s:
    i=chr(ord(i)-2)
print s

这只是给了我原始字符串 - 'cde'而不是'abc'。然而,使用列表理解给了我正确的答案:

str='cde'
str=''.join([chr(ord(i)-2) for i in str])
print str

结果:'abc'。这两个代码都不是一样的吗?为什么没有第一个工作?

4 个答案:

答案 0 :(得分:3)

在for循环块中,

for i in s:
    i=chr(ord(i)-2)

i指向可迭代对象s的每个元素。但是当您为i分配内容时,它只会指向已分配的项目,而原始项目保持不变。您可以使用此程序进行确认。

s='cde'
for i in s:
    print id(i)
    i=chr(ord(i)-2)
    print id(i)
print map(id, s)

id函数返回python对象的唯一ID。在每次迭代时,它会打印两个ID。第一个对应于字符串中元素的id,但第二个对应于指定的元素。

另一方面,list comprehension创建一个新列表并加入。这就是为什么改变会反映在那里。

答案 1 :(得分:3)

在你的例子中

s='cde'
for i in s:
    i=chr(ord(i)-2)
print s

变量i接收字符串项的副本(读取:"字符")。更改i不会更改该字符串项。

答案 2 :(得分:2)

字符串是不可变的,但是不是 for循环中赋值失败的原因,请参阅下面的代码:

In [272]: l=list('asdf')

In [273]: l
Out[273]: ['a', 's', 'd', 'f']

In [274]: for i in l:
     ...:     i=chr(ord(i)+1)
     ...:     

In [275]: l
Out[275]: ['a', 's', 'd', 'f']

列表对象是可变的,但是分配仍然将没有更改为l,因为i=chr(ord(i)+1)只是让i引用另一个字符串

<强> 2。在这种情况下,我们如何更改/替换列表中的值?

列表是可变的,您可以使用l[i]来引用l中的项目,使用enumerate可以在迭代时获取索引:

In [299]: for i, v in enumerate(l):
     ...:     l[i]+='z'
     ...:     

In [300]: l
Out[300]: ['az', 'sz', 'dz', 'fz']

注意通过l是可变的,l[0]仍然是不可变的:

In [301]: l=list('asdf')

In [302]: id(l[0])
Out[302]: 33639888

In [303]: for i, v in enumerate(l):
     ...:     l[i]+='z'

In [304]: l
Out[304]: ['az', 'sz', 'dz', 'fz']

In [305]: id(l[0])  #what l[0] refers to has been changed
Out[305]: 110316288

答案 3 :(得分:0)

您的第一个不修改字符串。循环变量(在您的情况下为i)不会引用它生成的字符串,因此更改它不会反映在字符串中(这是不可变的)可能有点棘手。例如:

s = "abc"
for index, char in enumerate(s):
    char = 'z'           #we assign tp the loop variable. the actual string is unchanged.
    print(char)          #prints 'z'
    print(s[index])      #prints the original char from the string, a -> b -> c

您的第二个示例直接指定给字符串,因此会更改。

为了使您的第一项技术有效,请尝试以下方法:

s='cde'
temp = ''
for i in s:
    temp = str.join([temp, chr(ord(i)-2)])
s = temp