最近在刷题的时候碰到个奇怪的问题。例子大概是这样似的:python
In [1]: a = 100 In [2]: def func(): ...: print(a) ...: In [3]: func() 100 In [4]: def another_func(): ...: a += 100 ...: print(a) ...: In [5]: another_func() --------------------------------------------------------------------------- UnboundLocalError Traceback (most recent call last) <ipython-input-5-464bd62798b3> in <module>() ----> 1 another_func() <ipython-input-4-1674a1f57571> in another_func() 1 def another_func(): ----> 2 a += 100 3 print(a) 4 UnboundLocalError: local variable 'a' referenced before assignment
为何直接用print能够输出a,可是调用a的话就报错说变量a未分配?这是Python语言的特性,不一样于C语言的是**Python函数中的变量(在定义前直接调用时)会优先引用局部变量,查找不到时再去引用全局变量。**可是第二个函数怎么解释呢?这里是由于Python函数中的变量第一次出如今等号右边时会被当作一个新的局部变量(提早用global声明过的全局变量除外)。在函数中直接运算a += 100并不会像直接打印a同样调用全局变量,而调用的是还没来得及赋值的局部变量a,因此才会报错。app
In [1]: def func(num): ...: num += 1 ...: print(id(num)) ...: In [2]: num = 0 In [3]: id(num) Out[3]: 1953497520 In [4]: func(num) 1953497552 In [5]: lists = [1,2,3] In [6]: def list_handle(lists): ...: lists.append(4) ...: In [7]: list_handle(lists) In [8]: lists Out[8]: [1, 2, 3, 4] In [9]: string = 'hello' In [10]: print(id(string)) 1861356044448 In [11]: def string_handle(string): ...: string = ' '.join([string, 'world']) ...: print(id(string)) ...: In [12]: string_handle(string) 1861357160816
如上述代码所示,若是用形参的方式向函数传值时原理与C语言相似,是将实参的值复制给函数中的局部变量(本质上是增长新局部变量来引用实参的值)。当实参为可变对象时可原地修改传入对象的内容,实参为不可变对象时修改的只是局部变量的值而对传入的实参内容没有影响。函数
In [13]: def list_append(li=[], num=None): ...: li.append(num) ...: print(li) ...: In [14]: list_append(num=1) [1] In [15]: list_append(num=2) [1, 2]
另外还有一点须要注意的是,若是定义函数时设定形参默认值为可变对象,那么会出现上面这种状况。当屡次使用默认值调用函数时并无每次都建立新list并append值进去,而一直操做的是以前的那个list。这是由于Python的函数在初次编译时,为可变类型的形参分配一个固定地址,之后在使用缺省值时就一直操做这块地址,想要避免这种状况就尽可能不要设置形参的默认值为可变对象或每次使用时不要用缺省值,也能够用如下方式:code
In [16]: def list_append(li=None, num=None): ...: if not li: ...: li = [] ...: li.append(num) ...: return li ...: In [17]: list_append(num=1) Out[17]: [1] In [18]: list_append(num=2) Out[18]: [2]