最近遇到了函数闭包(函数嵌套)使用,但是不是很懂调用过程,参考资料以后,进行了如下总结(顺便将python基础函数相关知识进行了复习和总结)。

一、python函数定义


  • 使用"def"关键字,后接函数名与括号"()",注意末尾":"
  • "[]“表示可以省略,参数由”,"分隔,可以省略
  • return表示返回值给调用者,可省略,表示返回None
def function_name([param1, param2...]):
    function_body
    [return [expression]]

二、python函数调用与参数传递


python中,包括可更改(mutable)与不可更改(immutable)对象。
string(字符串)、tuple(元组)、number(数值)都是不可更改对象,而list(列表)、dict(字典)等则是可修改的对象。

不可变类型:例如:变量赋值a=5后再赋值a=10,实质为新生成一个int对象10,再让a指向它,而5被丢弃。并不是改变了a的值,其实相当于新生成了a。
可变类型:变量赋值a=[1,2,3,4]后再赋值a[2]=5,只是将a[2]元素值修改。

当作为参数传递时,不可变类型相当于值传递,可变类型相当于引用传递。下面简单举两个例子:

  1. 传递不可变类型参数示例:
def ChangeInt(a):
    a = 10
b = 2
print(ChangeInt(b))  # 结果是 2
  1. 若想获得改变后的参数值,可以使用return返回。
def ChangeInt(a):
    a = 10
    return a # 将a返回给调用
b = 2
b = ChangeInt(b) # 创建新的b接受已改变的返回值
print(b)  # 结果是 10
  1. 传递可变类型参数示例:
def ChangeList(mylist):
     mylist.append(40)
     print("函数内取值: ", mylist)
 mylist = [10, 20, 30]
 ChangeList(mylist)
 print("函数外取值: ", mylist)

三、python参数


在进行函数调用时,定义函数时的参数列表中的参数包括必需参数和非必需参数(默认参数),还有关键字参数和可变长参数。

  1. 必需参数
    必需参数顾名思义,即在函数调用时必须给出相应参数值,否则会报错。
def printme(str):
    print (str)
printme() # 会报错
printme("传入了参数") # 正确调用
  1. 非必需参数(默认参数)
    即在函数定义时,在参数列表指定相应参数值,在函数调用时,则可不必传该参数。即若未传递该参数,则使用默认值。
def printinfo(name, age=35):
     print("名字: ", name)
     print("年龄: ", age)
 printinfo("runoob")
  1. 关键字参数
    使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为Python解释器能够用参数名匹配参数值。将上例函数调用改为:
printinfo(age=50, name="runoob")
  1. 不定长参数
    加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
def functionname([formal_args,] *var_args_tuple ):
    function_suite
    return [expression]
  1. 例如:
def printinfo(arg1, *vartuple):
    print(arg1)
    for var in vartuple:
        print (var)
printinfo(70, 60, 50)
  1. 其输出结果为:70 60 50。其中还有**vartuple作为参数的形式,加了两个星号**的参数会以字典的形式导入,例如:
def printinfo( arg1, **vardict ):
    print (arg1)
    print (vardict)
printinfo(1, a=2,b=3)
  1. 其输出结果为:1 {‘a’: 2, ‘b’: 3},若后面不是以key=value形式传参,会报错。

四、匿名函数


python使用lambda来创建匿名函数。
需要注意的是,lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。其语法格式为:

lambda [arg1 [,arg2,.....argn]]:expression

示例如下:

sum = lambda arg1, arg2: arg1 + arg2
print("相加后的值为 : ", sum(10, 20))
print((lambda arg1, arg2: arg1 + arg2)(10,20))

五、Global与nonlocal关键字


当内部作用域修改外部作用域变量时,需要使用该关键字。
1.global:示例如下所示,注释掉global关键字声明后,输出结果为“2 1”,因为fun()num拥有局部作用域。当取消注释后,输出结果为“2 2”,因为该关键字使得num有了全局作用域。

num = 1
def fun():
    #global num  # global 关键字声明
    num = 2
    print(num)
fun()
print(num)

注意:当对num进行修改时,不加global会报错,或者可将变量进行参数传递。
2. nonlocal:若修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要nonlocal关键字。

def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal关键字声明
        num = 100
        print(num)
    inner()
    print(num)
outer()

上面的例子输出"100 100",若注释掉nonlocal,输出"100 10"。将其改为global,和不加结果相同,即global不起作用。

六、python函数闭包(函数嵌套)


上一节已经接触了函数嵌套,接下来进行详细介绍:
首先,进行闭包格式介绍:

def 外层函数(参数1):
    def 内层函数(参数2):
        print("内层函数参数", 参数1)
        print("外层函数参数", 参数2)
    return 内层函数

内层函数的引用 = 外层函数("传入参数")
内层函数的引用(参数2)

注意:调用外层函数返回的是内层函数的引用。举例如下:

def func(a, b):
    print("外层函数调用")
    def line(x):
        print("内层函数调用:a=%d\tx=%d" % (a, x))
        return a * x - b
    return line

line = func(2, 3)
print(line(5))

参考文档: