首页 > Python基础教程 >
-
一步步教你理解Python装饰器(2)
在#1处不仅因为作用域规则引发了问题(尽管这是出现了NameError的原因),而且也出于在Python和许多其它语言里的函数调用实现的原因。此处,我们没有任何可用的语法来获取变量x的值——字面上是不存在的。每次当调用foo函数时,它的namespace被重新构建,并且当函数结束时被销毁。
5、函数的参数(Function parameters)
Python允许我们向函数传递参数。参数名成为了该函数的local变量。
1
2
3
4
|
>>> def foo(x): ... print locals() >>> foo(1) { 'x' : 1} |
Python有许多不同的定义和传递函数参数的方法。要想更详细深入地了解请参照the Python documentation on defining functions。这里我展示一个简版:函数参数既可以是强制的位置参数(positional parameters)或者是命名参数,参数的默认值是可选的。
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> def foo(x, y=0): # 1 ... return x - y >>> foo(3, 1) # 2 2 >>> foo(3) # 3 3 >>> foo() # 4 Traceback (most recent call last): ... TypeError: foo() takes at least 1 argument (0 given) >>> foo(y=1, x=3) # 5 2 |
在#1处我们定义了一个带有一个位置参数x和一个命名参数y的函数。正如我们看到的,在#2处我们可以通过普通的值传递来调用函数,即使一个参数(译者注:这里指参数y)在函数定义里被定义为一个命名参数。在#3处我们可以看到,我们甚至可以不为命名参数传递任何值就可以调用函数——如果foo函数没有接收到传给命名参数y的值,Python将会用我们声明的默认值0来调用函数。当然,我们不能漏掉第一个(强制的,定好位置的)参数——#4以一个异常描述了这种错误。
都很清晰和直接,不是吗?下面变得有点儿让人疑惑——Python也支持函数调用时的命名参数而不只是在函数定义时。请看#5处,这里我们用两个命名参数调用函数,尽管这个函数是以一个命名和一个位置参数来定义的。因为我们的参数有名字,所以我们传递的参数的位置不会产生任何影响。 相反的情形当然也是正确的。我们的函数的一个参数被定义为一个命名参数但是我们通过位置传递参数—— #4处的调用foo(3, 1)将一个3作为第一个参数传递给我们排好序的参数x并将第二个参数(整数1)传递给第二个参数,尽管它被定义为一个命名参数。
Whoo!这就像用很多话来描述一个非常简单的概念:函数的参数可以有名称或者位置。
6、内嵌函数(Nested functions)
Python允许创建嵌套函数,这意味着我们可以在函数内声明函数并且所有的作用域和声明周期规则也同样适用。
1
2
3
4
5
6
7
8
|
>>> def outer(): ... x = 1 ... def inner(): ... print x # 1 ... inner() # 2 ... >>> outer() 1 |
这看起来稍显复杂,但其行为仍相当直接,易于理解。考虑一下在#1处发生了什么——Python寻找一个名为x的local变量,失败了,然后在最邻近的外层作用域里搜寻,这个作用域是另一个函数!变量x是函数outer的local变量,但是和前文提到的一样,inner函数拥有对外层作用域的访问权限(最起码有读和修改的权限)。在#2处我们调用了inner函数。请记住inner也只是一个变量名,它也遵从Python的变量查找规则——Python首先在outer的作用域里查找之,找到了一个名为inner的local变量。
7、函数是一等公民(Functions are first class objects in Python)
在Python中,这是一个常识,函数是和其它任何东西一样的对象。呃,函数包含变量,它不是那么的特殊!
1
2
3
4
5
6
|
>>> issubclass(int, object) # all objects in Python inherit from a common baseclass True >>> def foo(): ... pass >>> foo.__class__ # 1>>> issubclass(foo.__class__, object) True |
你也许从没想到过函数也有属性,但是在Python中,和其它任何东西一样,函数是对象。(如果你发觉这令你感到困惑,请等一下,知道你了解到在Python中像其它任何东西一样,class也是对象!)也许正是因为这一点使Python多少有点“学术”的意味——在Python中像其它任何值一样只是常规的值而已。这意味着你可以将函数作为参数传递给函数或者在函数中将函数作为返回值返回!如果你从未考虑过这种事情请考虑下如下的合法Python代码:
1
2
3
4
5
6
7
8
9
10
|
>>> def add(x, y): ... return x + y >>> def sub(x, y): ... return x - y >>> def apply(func, x, y): # 1 ... return func(x, y) # 2 >>> apply(add, 2, 1) # 3 3 >>> apply(sub, 2, 1) 1 |