2014-04-28 50 views
1

似乎python中的字符串和字符串的行为基本上不同。当我一个字符串传递给它得到仅在局部函数的范围修改的功能,但是当我做同样的一个快译通,它的范围被修改超越功能:python中不一致的变量范围

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'} 

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

+0

[Python函数参数范围(字典与字符串)]可能的重复](http://stackoverflow.com/questions/2951112/python-function-argument-scope-dictionaries-v-strings) – devnull

+0

@devnull:虽然问题是相似的,我认为这个问题有独立的兴趣,因为'+ ='和'[] ='是可以在某些类型上完成的操作,而不是这些特定类型。另一个问题是将项目分配与裸名分配进行比较,该分配永远不会改变。 – BrenBarn

回答

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__()的简写。

+0

谢谢。这对了解发生的事情最有用。 – mulllhausen

5

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

你可以在python的官方文档data model中阅读更多关于可变类型的信息。

+0

很酷。有没有办法宣布一个不可改变的字典? – mulllhausen

+0

@mulllhausen如果你这样做,你不能添加任何东西。那是你要的吗? – SethMMorton

+0

@mullhausen并不是真的,因为这种方式打破了字典的目的。你不能添加项目。 – msvalkon

1

是的,这是故意的。每种类型都决定了操作员如何使用它。字典类型设置为a[1] = "qwe"修改字典对象。这些更改将在任何引用该对象的代码中看到。字符串类型设置为s += "qwe"确实不是修改对象,但返回一个新的对象。因此,引用原始对象的其他代码将不会看到任何更改。

这是一种速记方式,即字符串是不可变的,字典是可变的。然而,值得注意的是,“字典是可变的”不是行为发生的全部原因。原因是项目分配(someDict[item] = val)是一个操作,可以有效地改变字典。