1.作用域
变量到底是什么呢?可将其视为指向值的名称。
>>>x=1
>>>scope=vars()
>>>scope['x']
>1
>>>scope['x']+=1
>>>x
>2
执行赋值语句x=1后,名称x指向值1,和使用字典差不多,只是看不见而已。实际上,有一个vars的内置函数,它返回这个不可见的字典。
⚠️⚠️⚠️
警告:一般而言,不应修改vars返回的字典。(据Python官方文档的说法,这样做可能得不到你想要的结果。)
这种“看不见的字典”称为命名空间或作用域。
除全局作用域外,每个函数调用都将创建一个。
>>>def foo():x=42
...
>>>x=1
>>>foo()
>>>x
>1
在这里,函数foo修改(重新关联)了变量x,但当你最终查看时,它根本没变。这是因为调用foo时创建一个新的命名空间,供foo中的代码块使用。
赋值语句x=42是在这个内部作用域(局部命名空间)中执行的,不影响外部(全局)作用域内的x。在函数内使用的变量称为局部变量。参数类似于局部变量,
⚠️⚠️⚠️
务必慎用全局变量,像下面这样访问全局变量是众多Bug的根源
>>>def combine(parameter):print(parameter+external)
...
>>>external='berry'
>>>combine('Shrub')
Shrubberry
重新关联全局变量是另一码事。在函数内部给变量赋值值,该变量默认为局部变量,除非你明确告知Python它是全局变量。
>>>x=1
>>>def change_global():
global x
x+=1
...
>>>change_global()
>>>x
2
作用域嵌套
嵌套通常作用不大,但有一个很突出的用途:使用一个函数来创建另一个函数。
>>>def multiplier(factor):
def multiplyByFactor(number):
return number*factor
return multiplyByFactor
在这里,一个函数位于另一个函数中,且外面的函数**返回里面的函数。**即返回一个函数 而不是调用它。返回的函数能够访问其定义所在的作用域。换而言之,它携带着自己所在的环境(和相关的局部变量)!
每当外部函数被调用时,都将重新定义内部的函数,而变量factor的值也可能不同。由于Python的嵌套作用域,可在内部函数中访问这个来自外部局部作用域(multiplier)的变量,
>>>def multiplier(factor):
def multiplyByFactor(number):
return number*factor
return multiplyByFactor
...
>>>double=multiplier(2)
>>>double(5)
10
>>>triple=multiplier(3)
>>>triple(5)
15
>>>multiplier(2)(6)
12
像multiplyByFactor这样存储其所在作用域的函数被称为闭包。
如果一定要给外部作用域内的变量赋值,可使用关键字nonlocal。它的用法和global很像,让你能给外部作用域(非全局作用域)内的变量赋值。
2.递归
简单的来说:递归就是引用自身
def recursion():
return recursion()
像上面这个函数,其内的递归被称为**无限递归。**理论上来讲永远都不会结束。实际上因为内存空间等原因会导致程序终止并报错。
基线条件:满足这种条件时函数将直接返回一个值
递归条件:包含一个或多个调用,这些调用皆在解决问题的一部分。
如何让函数调用自身呢?
每次调用函数都会创建一个新的命名空间。所以当函数调用自身时,是两个命名空间不同的相同函数在交流。你可以视为两个属于相同物种的动物在交流。