为什么Python的字典迭代似乎使用了副本?

7 投票
3 回答
4453 浏览
提问于 2025-04-16 23:19

我对Python是怎么遍历这个字典的感到困惑。从Python的文档来看,itervalues会返回一个字典值的迭代器。

dict = {"hello" : "wonderful", "today is" : "sunny", "more text" : "is always good"}

for x in dict.itervalues():
    x = x[2:]   

print dict

这段代码打印出来的字典和原来的一样,没有变化。为什么会这样呢?如果我说位置x的值是“blabla”,为什么没有被设置呢?

3 个回答

1

正如Sven Marnach所提到的,字符串是不可变的,也就是说你不能改变它的内容。你只是把x重新指向了一个通过切片操作创建的新字符串。你可以用id来证明x确实指向字典中的同一个对象:

>>> obj = 'hello'

>>> id(obj)
<<< 4318531232

>>> d = {'key': obj}   

>>> [id(v) for v in d.values()]
<<< [4318531232]

>>> [id(v) for v in d.itervalues()]
<<< [4318531232]

>>> [(k, id(v)) for k, v in d.items()]
<<< [('key', 4318531232)]

>>> [(k, id(v)) for k, v in d.iteritems()]
<<< [('key', 4318531232)]

你可以使用iteritems来同时遍历键和值,这样就能实现你想要的功能:

for k,v in dict.iteritems():
    dict[k] = v[2:]
5

这行代码

x = x[2:]

只是创建了一个字符串的切片 x[2:],并把名字 x 重新指向这个新的字符串。它并没有改变之前 x 指向的字符串。(在Python中,字符串是不可变的,不能被修改。)

要实现你真正想要的效果,你需要让字典中的条目指向这个通过切片创建的新字符串对象:

for k, v in my_dict.iteritems():
    my_dict[k] = v[2:] 
7

这和字符串或列表没有关系。关键在于for是怎么展开的。

for x in d.iteritems():
    # loop body

基本上等同于做

iter = d.itervalues()
while True:
    try:
        x = next(iter)
        # loop body
    except StopIteration:
        break

所以考虑到这一点,我们很容易看出,我们只是在重新给x赋值,而x保存的是一个函数调用的结果。

iter = d.itervalues()
while True:
    try:
        x = next(iter)

        x = 5 # There is nothing in this line about changing the values of d
    except StopIteration:
        break

撰写回答