Python的日常:函数

Python中使用def语句来定义函数,它实际是创建了一个对象,然后令变量名(函数名)去引用这个对象。第一行的字符串是文档字符串(若要跨行,用三引号),使用funcName.__doc__来调用,是非必要部分。

使用return语句返回内容,返回多个对象,需用逗号隔开,函数会将它们组织成一个元组返回。无return的函数,默认返回None对象。

有四类函数:

  • 全局函数:直接定义在模块(文件)中。
  • 局部函数:在函数内部定义的函数。

    一种特殊情况是,func1直接返回了func2对象。

    正常情况下,当func1调用结束,其中的局部变量将不复存在。但这种情况下,func1中供内嵌函数func2使用的那些局部变量,将会被保存,仍旧可以访问,Python的这种机制叫做“闭包”(lexical closure),外层函数func1中的变量构成了内层函数func2的运行环境。
  • 匿名函数:用lambda定义,实际上是表达式,可以用表达式的地方都可以使用,比普通函数要灵活。
  • 方法:对象内置的函数,与对象内部的属性(数据)相关联。

7.1. 作用域

函数对应的是本地/局部作用域,如不做特殊说明,函数体内进行的操作,都是针对的本地/局部变量。

在函数中操作某个变量,首先会在该函数本地作用域内寻找该变量,若找不到,则向其外层函数的作用域中寻找,如果它有外层函数的话。如果还是找不到,就再向外找。

在函数作用域内可以访问全局变量,但不能对其进行修改。若要修改全局变量,必须用global显式声明:

7.2. 参数

参数其实是对被传入对象的引用。对于可修改对象,例如列表,在函数内基于参数进行的修改操作,实际上会修改到原列表。若只想在函数内对列表的值进行处理,应该向函数传入列表的“数值”而非列表本身。

另外,默认情况下,参数是按序从左到右进行匹配的,叫做:位置参数。调用函数时,传入参数的位置及数量都要与函数参数表相匹配才行。

除了位置参数的方式,还有关键字参数,默认参数,可变参数,可变参数解包。

  • 关键字参数:传参时,显式指定传递目标。

  • 默认参数:定义函数的时候,设定参数默认值。注意,有默认值的参数必须处于右侧。

  • 可变参数:定义函数时,以*运算符开头的参数,可以收集任意多个参数。注意,可变参数必须处于右侧。
    若使用单个*开头,传入参数会被处理成一个元组:
    若使用两个*开头,传入参数会被处理成一个字典:

  • 可变参数解包:是“可变参数”方式的逆过程,在调用函数时以*开头传入参数。它将一个集合打散(参数分解),传给多个参数。

7.3. 匿名函数

匿名函数,用lambda运算符完成定义,不需要给出函数名。匿名函数主要用于指定小型回调函数。

其中的params是参数列表,冒号后面是表达式。lambda会返回一个函数对象,将返回值赋值给一个变量,就可以像使用普通函数一样,去使用这个匿名函数了。

将匿名函数放到序列中,遍历序列,逐个调用:

7.4. 生成器

一些复杂的生成规则,用通常的生成器表达式是无法描述的。这个时候可以用函数来定制生成器。

基本示例:

每遇到yield就会停下,直到生成器对象发生迭代操作再继续执行。

7.5. 装饰器

装饰器是用来增强被装饰函数功能的函数。装饰器的基本形式跟闭包类似。

其中,外层的decorator和内层的wrap函数,名字均是自定义的,无特殊要求。在定义被包装函数的时候,要使用@加包装器名字(@decorator)发起。

上述操作中,被包装函数f()并无参数,若为带参函数,其参数应在内层的wrap函数形参表中指定:

<== index ==>