工厂函数
一个能够记住嵌套作用域的变量值的函数,尽管那个作用域或许已经不存在了。
例如,工厂函数有时需要及时生成事件处理、实时对不同情况进行反馈的程序中。例如:
1 | In [1]:def maker(N): |
这定义了一个外表的函数,这个函数简单地生成了一个嵌套的函数,却并不调用这个内嵌的函数。如果我们调用外部的函数:
1 | In [2]:f = maker(2) |
我们得到的是生成的内嵌函数的一个引用。这个内嵌函数是通过运行内嵌的def而创建的。如果现在调用从外表得到的那个函数:
1 | In [4]:f(3) |
实际上,在本地作用域内的N被作为执行的状态信息保留了下来,我们返回其参数的平方运算。现在,如果再调用外层的函数,将得到一个新的有不同状态信息的嵌套函数——得到了参数的三次方而不是平方,但是最初的仍像往常一样是平方。
1 | In [6]:g = maker(3) |
LEGB原则
对于一个def语句:
- 变量名引用分为桑作用域进行查找:首先是本地,之后是函数内(如果有的话),之后全局,最后是内置。
- 在默认情况下,变量名赋值会创建或者改变本地变量。
- 全局声明和非本地声明将赋值的变量名映射到模块文件内部的作用域。
- Python 的变量名解析机制也称为 LEGB 法则,具体如下:当在函数中使用未确定的变量名时,Python 搜索 4 个作用域:本地作用域(L),之后是上一层嵌套结构中def或lambda的本地作用域(E),之后是全局作用域(G),最后是内置作用域(B)。按这个查找原则,在第一处找到的地方停止。如果没有找到,Python会报错的。
特定的参数匹配模型
基础
- 位置:从左到右。通过位置进行匹配把参数值传递给函数头部的参数名称,匹配顺序从左到右。
- 关键字参数:通过参数名进行匹配。调用者可以定义哪一个函数接受这个值,通过在调用时使用参数的变量名,使用
name=Value
这种语法。 - 默认参数:为没有传入值的参数定义参数值。如果调用时传入的值过于少的话,函数能够为参数定义接受的默认值,再一次使用语法
name=value
。 - 可变参数:手机任意多基于位置或者关键字的参数。函数能够使用特定的参数,它们是以字符*开头,收集任意多的额外参数。
- 可变参数解包:传递任意多的基于位置或者关键字的参数。调用者能够再使用
*
语法去将参数集合打散,分成参数。这个*
与在函数头部的*
恰恰相反:在函数头部它意味着收集任意多的参数,而在调用者中意味着传递任意多的参数。 - Keyword-only参数:参数必须按照名称传递。在py3中,函数也可以指定参数,参数必须用带有关键参数的名字(而不是位置)来传递。这样的参数通常用定义世纪参数以外的配置选项。
细节
匹配顺序法则:
- 在函数调用中,参数必须以此顺序出现:任何位置参数(value),后面跟着任何关键字参数(name=value)和
*sequence
形式的组合,后面跟着**dict
形式。 - 在函数头部,参数必须以此顺序出现:任何一般参数(name),紧跟着任何默认参数(name=value),如果有的话,后面是
*name
(或者在py3中是*
)的形式,后面跟着任何name&name=value keyword-only参数(在py3中),后面跟着**
形式。
匹配步骤:
- 通过位置分配非关键字参数。
- 通过匹配变量名分配关键字参数。
- 其他额外的非关键字参数分配到*name元组中。
- 其他额外的关键字参数分配到**name字典中。
- 用默认值分配给头部未得到分配的参数。