python中不一致的变量范围

时间:2014-04-28 05:59:20

标签: python

似乎字符串和字符串在python中的行为根本不同。当我将一个字符串传递给一个函数时,它只在本地函数的作用域中被修改,但是当我对dict做同样的事情时,它会在函数范围之外被修改:

def change_str(s):
    s += " qwe"

def change_arr(a):
    a[1] = "qwe"

ss = "asd"
change_str(ss)
print ss
# prints:
# asd

aa = {0:"asd"}
change_arr(aa)
print aa
# prints:
# {0: 'asd', 1: 'qwe'}

这种行为是故意的,如果是,那么为什么?

3 个答案:

答案 0 :(得分:5)

这是故意行为。字符串在python中是不可变的,因此基本上所有字符串操作都返回一个新的字符串,并且由于您的函数不返回任何内容,因此您无法看到新字符串asd qwe。您可以在本地范围之外更改可变容器的内容,而无需将其声明为全局。

您可以在pythons data model的官方文档中阅读有关可变类型的更多信息。

答案 1 :(得分:1)

是的,这是故意的。每种类型都决定了运营商如何处理它。设置dict类型,以便a[1] = "qwe"修改dict对象。这些更改将在引用该对象的任何代码中看到。设置字符串类型,以便s += "qwe" 修改对象,但返回一个新对象。因此,引用原始对象的其他代码将看不到任何更改。

说法的简写方式是字符串是不可变的,而且字符串是可变的。但是,值得注意的是" dicts是可变的"并不是行为发生的全部原因。原因是项目赋值(someDict[item] = val)是一个动作突变dict的操作。

答案 2 :(得分:1)

不要让'赋值'操作符欺骗你。这就是每个功能中真正发生的事情:

def change_str(s):
    # operation has been split into 2 steps for clarity
    t = s.__iadd__("qwe") # creates a new string object
    s = t # as you know, without the `global` keyword, this `s` is local.

def change_arr(a):
    a.__setitem__(1, "qwe")

如您所见,这些函数中只有一个实际上具有赋值操作。 []=是(或等效于).__setitem__()的缩写。