Python函数和函数式编程
Python的过程就是函数,因为解释器会隐式地返回默认值None。实际编程中大部分偏函数更接近过程,不显示地返回任何东西。当没有显示地返回元素或者如果返回None时,python会返回一个None。
* 元组 ** 字典
def子句的剩余部分包括了一个虽然可选但是强烈推荐的文档字串和必须的函数体。
函数的子句由声明的标题行以及随后的定义体组成。
装饰器是在函数调用之上的修饰。
装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。紧跟着装饰器声明的是被修饰的函数和装饰函数的可选参数。
@decorator(dec_opt_args)
def func2Bdecorated(func_opt_args):
:
装饰器可以如函数调用一样“堆叠”起来。
@g
@f
def foo():
:
...与foo=g(f(foo))相同
@deco1(deco_arg)
@deco2
def func():pass
这等价于:
func=deco1(deco_arg)(deco2(func))
装饰器实际就是函数。他们接收函数对象。
在装饰器中置入通用功能的代码来降低程序复杂度。
·引入日志
·增加计时逻辑来检测性能
·给函数加入事务的能力
函数式是可以被引用的,也作为参数传入函数,以及作为列表和字典等容器对象的元素函数有一个独一无二的特征使它同其他对象区分开来,那就是函数式可调用的。
所有的对象都是通过引用来传递的,函数也不例外。
foo 函数对象的引用
foo() 函数对象的调用
如果没有值传递给那个参数,那么这个参数将取默认值。
所有必须的参数都要在默认参数之前。
在函数调用时,接受一个不定(非固定)数目的参数。
“*”操作符之后的形参将作为元组传递给函数,元组保存了所有传递给函数的“额外”的参数。如果没有给出额外的参数,元组为空。
def function_name([formal_args,] *vargs_tuple):
"function_documentation_string"
function_body_suite
使用字典保存参数名与参数值。“**”是被重载了的以便不与幂运算发生混淆。关键字变量参数应该为函数定义的最后一个参数,带“**”。
def function_name([formal_args,] [*vargst,] **vargsd):
"function_documentation_string"
function_body_suite
关键字和非关键字可变参数都有可能用在同一个函数中,只要关键字字典是最后一个参数并且非关键字元组先于它之前出现。
元组和字典参数仅仅是被调函数中最终接收的元组和字典的子集。
匿名函数与lambda
lambda [arg1[,arg2,...argN]]:expression
这个表达式的定义体必须和声明放在同一行。参数是可选的。
lambda语句由于性能的原因,在调用时绕过函数的栈分配。lambda表达式运作起来就像一个函数,当被调用时,创建一个框架对象。
偏函数应用
一个带n个参数,curried的函数固化第一个参数为固定参数,并返回另一个带n-1个参数函数对象。这种函数将任意数量(顺序)的参数的函数转化成另一个带剩余参数的函数对象。
当调用带许多参数的函数的时候,PFA是最好的方法。
如果你创建了不带base关键字的偏函数,这可能会让参数以错误的顺序传入int()。
关键字参数总是出现在形参之后。
变量作用域
标识符的作用域是定义为其声明在程序里的可应用范围,或者即是我们所说的变量可见性。变量可以是局部域或者全局域。
定义在函数内的变量有局部作用域,在一个模块中最高级别的变量有全局作用域。
声明适用的程序的范围被称为了声明的作用域。在一个过程中,如果名字在过程的声明之内,它的出现即为过程的局部变量;否则的话,出现即为非局部。
一个变量的作用域和它寄住的名称空间相关。
在全局或者内建的名称空间内,可以覆盖任何匹配的名字。
如果将全局变量的名字声明在一个函数体内的时候,全局变量的名字能被局部变量给覆盖掉。
为了明确地引用一个已命名的全局变量,必须使用global语句。
虽然存在多个函数的嵌套,但你不能访问超过两个作用域。
如果在一个内部函数里,对在外部作用域的变量进行引用,那么内部函数就被认为是闭包。定义在外部函数内的但由内部函数引用或者使用的变量被称为自由变量。
闭包将内部函数自己的代码和作用域以及外部函数的作用结合起来。
闭包对于安装计算、隐藏状态和在函数对象和作用域中随意地切换是很有用的。
一个lambda表达式定义了新的作用域,所以这个作用域除了局部lambda函数,对于程序其他部分,该作用域都是不能对进行访问的。
在lambda语句中的表达式有和函数相同的作用域。
任何时候,总有一个或者两个活动的作用域。
在任何给定的时间,存在两个或者三个的活动的名称空间。从函数内部,局部作用域包围了局部名称空间,第一个搜寻名字的地方。如果名字存在的话,那么将跳过检查全局作用域。
如果函数包含了对其自身的调用,该函数就是递归的。如果一个新的调用能在相同过程中较早的调用结束之前开始,那么该过程就是递归。