函数参数
python允许我们向函数传递参数,参数会变成本地变量存在于函数内部。
def foo(x):
print locals()
foo(1)
{'x': 1}
在Python里有很多的方式来定义和传递参数,完整版可以查看 python官方文档。我们这里简略的说明一下:函数的参数可以是必须的位置参数或者是可选的命名,默认参数。
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处我们定义了函数foo,它有一个位置参数x和一个命名参数y。在#2处我们能够通过常规的方式来调用函数,尽管有一个命名参数,但参数依然可以通过位置传递给函数。在调用函数的时候,对于命名参数y我们也可以完全不管就像#3处所示的一样。如果命名参数没有接收到任何值的话,python会自动使用声明的默认值也就是0。需要注意的是我们不能省略第一个位置参数x, 否则的话就会像#5处所示发生错误。
目前还算简洁清晰吧, 但是接下来可能会有点令人困惑。python支持函数调用时的命名参数(个人觉得应该是命名实参)。看看#5处的函数调用,我们传递的是两个命名实参,这个时候因为有名称标识,参数传递的顺序也就不用在意了。
当然相反的情况也是正确的:函数的第二个形参是y,但是我们通过位置的方式传递值给它。在#2处的函数调用foo(3,1),我们把3传递给了第一个参数,把1传递给了第二个参数,尽管第二个参数是一个命名参数。
桑不起,感觉用了好大一段才说清楚这么一个简单的概念:函数的参数可以有名称和位置。这意味着在函数的定义和调用的时候会稍稍在理解上有点儿不同。我们可以给只定义了位置参数的函数传递命名参数(实参),反之亦然!如果觉得不够可以查看官方文档
嵌套函数
Python允许创建嵌套函数。这意味着我们可以在函数里面定义函数而且现有的作用域和变量生存周期依旧适用。
def outer():
x = 1
def inner():
print x # 1
inner() # 2
outer()
1
这个例子有一点儿复杂,但是看起来也还行。想一想在#1发生了什么:python解释器需找一个叫x的本地变量,查找失败之后会继续在上层的作用域里面寻找,这个上层的作用域定义在另外一个函数里面。对函数outer来说,变量x是一个本地变量,但是如先前提到的一样,函数inner可以访问封闭的作用域(至少可以读和修改)。在#2处,我们调用函数inner,非常重要的一点是,inner也仅仅是一个遵循python变量解析规则的变量名,python解释器会优先在outer的作用域里面对变量名inner查找匹配的变量.
函数是python世界里的一级类对象
显而易见,在python里函数和其他东西一样都是对象。(此处应该大声歌唱)啊!包含变量的函数,你也并不是那么特殊!
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里,函数只是一些普通的值而已和其他的值一毛一样。这就是说你尅一把函数想参数一样传递给其他的函数或者说从函数了里面返回函数!如果你从来没有这么想过,那看看下面这个例子:def add(x, y):
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
这个例子对你来说应该不会很奇怪。add和sub是非常普通的两个python函数,接受两个值,返回一个计算后的结果值。在#1处你们能看到准备接收一个函数的变量只是一个普通的变量而已,和其他变量一样。在#2处我们调用传进来的函数:“()代表着调用的操作并且调用变量包含的值。在#3处,你们也能看到传递函数并没有什么特殊的语法。” 函数的名称只是很其他变量一样的表标识符而已。
你们也许看到过这样的行为:“python把频繁要用的操作变成函数作为参数进行使用,像通过传递一个函数给内置排序函数的key参数从而来自定义排序规则。那把函数当做返回值回事这样的情况呢:
def outer():
def inner():
print "Inside inner"
return inner # 1
foo = outer() #2
foo # doctest:+ELLIPSIS
foo()
Inside inner
这个例子看起来也许会更加的奇怪。在#1处我把恰好是函数标识符的变量inner作为返回值返回出来。这并没有什么特殊的语法:”把函数inner返回出来,否则它根本不可能会被调用到。“还记得变量的生存周期吗?每次函数outer被调用的时候,函数inner都会被重新定义,如果它不被当做变量返回的话,每次执行过后它将不复存在。
在#2处我们捕获住返回值 – 函数inner,将它存在一个新的变量foo里。我们能够看到,当对变量foo进行求值,它确实包含函数inner,而且我们能够对他进行调用。初次看起来可能会觉得有点奇怪,但是理解起来并不困难是吧。坚持住,因为奇怪的转折马上就要来了(嘿嘿嘿嘿,我笑的并不猥琐!)