Python的函数可以返回一个值或者对象。若无返回值,默认返回None。若返回多个对象,实际返回一个元组。

函数是通过赋值(对象引用)传递的。调用者以及函数通过引用共享对象,但是不需要别名。改变函数中的参数名并不会改变调用者中的变量名,但是改变传递的可变对象可以改变调用者共享的那个对象。

函数名是一个对象的引用,可以自由地把这个对象赋给其他的名称并且通过任何引用调用它。


变量作用域:

函数定义了本地作用域,而模块定义的是全局作用域。变量分别对应三种不同的作用域:

1、若一个变量在def内赋值,它被定位在这个函数内。

2、若一个变量在一个嵌套的def中赋值,对于嵌套的函数,它是非本地的

3、若在def外赋值,它就是整个文件全局的。

如果需要给一个在函数内部却位于模块文件顶层的变量名赋值,需要在函数内部通过global语句声明。注意在原处改变对象并不会把变量划分为本地变量,实际上只有对变量名赋值才可以。例如L在顶层被赋值为一个列表,在函数内部像L.append(x)并不会将L划分为本地变量,而L=x却可以。记住:修改一个对象并不是对一个名称赋值。

在函数内对变量名赋值将会将其划分为本地变量,本地变量在引用前需定义!!!

变量名引用分为三个作用域进行查找:首先是本地,之后是函数内,之后全局,最后是内置。(LEGB)

当在函数中给一个变量名赋值时(而不是在一个表达式中对其进行引用),Python总是创建或改变本地作用域的变量名,除非它已经在那个函数中声明为全局变量。

lambda:Python允许用lambda关键字创造匿名函数,用合适的表达式(而非语句)调用lambda生成一个可以像其他函数一样使用的函数对象。lambda表达式引入了新的本地作用域。

在一个函数内定义一个函数被称为闭包。如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包。定义在外部函数内的但由内部函数引用或者使用的变量被称为自由变量。eg:

def maker(N):
    def action(X):
        return X ** N
    return action
    
f=maker(2)  #f : 
f(3)  #9

#外部函数maker生成并返回了一个嵌套的函数,却并不调用这个内嵌的函数。内嵌的函数记住了N的值。
#实际上,本地作用域内的N作为状态信息被保留下来

也可以用类来替代闭包。


函数参数:

func(value)
调用者
常规参数:通过位置进行匹配
func(name=value)
调用者
关键字参数:通过变量名匹配
func(*seq)
调用者
传递所有对象,并作为独立的基于位置的参数(解包)
func(**dict)
调用者
成对的传递所有关键字/值,并作为独立的关键字参数(解包)
def func(name)
函数
常规参数:通过位置或变量名匹配
def func(name=value)
函数

默认参数

def func(*name)
函数
匹配并收集所有包含位置的参数,并作为元组传递给函数(收集)
def func(**name)
函数
匹配并收集所有包含位置的参数,并作为字典传递给函数(收集)

Python中允许的函数调用的完整语句为:

func(value,name=value,*seq,**dict)

函数定义头部的完整语句为:

def func(name,name=value,*name,**name)


关于A函数调用B函数,两者的声明顺序:B函数无论是在A函数之前声明还是在之后声明都可以,只要保证调用A函数的语句在B函数的声明之后就可以。

函数属性:在函数外可以向函数附加用户定义的属性。eg:函数func,func.count=0。像count这种变量的名称对于一个函数来说是本地的,但是,其值在函数退出后仍然保留。


内建函数:

apply(func[,nkw][,kw]):用可选的参数来调用func,nkw为非关键字函数,kw为关键字函数;返回值是函数调用的返回值。

filter(func,seq):调用一个布尔函数来迭代遍历每个seq中的元素;返回一个使函数返回值为True的元素的序列。

map(func,seq1[,seq2...]):将函数作用于给定序列的每个元素,并用一个列表来提供返回值;若func为None,func表现为一个身份函数,返回一个含有每个序列中元素集合的n个元组的列表(同zip)。

reduce(func,seq[,int]):将二元函数作用于seq序列的元素,每次携带一对(先前的结果以及下一个序列元素)连续地将现有的结果和下一个值作用在获得的随后的结果上,最后减少我们的序列为一个单一的返回值;如果初始值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素。


偏函数应用:固化第一个参数为固定参数,并返回另一个带n-1个参数函数对象。

from operator import add
from functools import partial
add1=partial(add,1)  #add1(x)==add(1,x)

使用偏函数时注意关键字参数。


Python是静态检测Python的本地变量,当编译def代码时,不是通过发现赋值语句在运行时进行检测的。也就是说,在函数中一旦发现赋值语句就将其变量视为本地变量,即使赋值在引用之后。(如果赋值在引用之后,若无global声明,则引用会报错)