本文在上一篇文章:python函数式编程基础(一)的基础上继续介绍函数的闭包概念,递归以及高阶函数
python函数式编程基础(一):https://blog.csdn.net/Geroge_lmx/article/details/80740484
回顾:闭包是一个内嵌函数引用了外部嵌套函数的变量,并且外部嵌套函数返回的是内嵌函数
准备知识:局部变量,全局变量以及作用域
一.变量及作用域
局部变量:
1.定义在函数内部的变量,函数的形参也属于局部变量
2.只能在函数内部使用
3.在函数调用时被创建,调用结束后自动销毁
全局变量:
1.定义在函数外部,模块内部的变量
2.所有的函数都可以直接“访问”全局变量
3.对于不可变数据类型,函数内部不能直接通过赋值语句来改变全局变量
4.对于可变数据类型,函数内部可以直接通过赋值语句来改变全局变量
python的作用域:LEGB
做用域也叫命名空间,是访问变量时查找变量名的范围空间
L(local):局部作用域(函数内)
E(Enclosing):外部嵌套函数作用域
G(Globals):全局作用域(模块内)
B(Builtin):python内置模块的作用域
变量名查找顺序:
查找顺序:L --> E --> G --> B
global 语句:
作用:
全局声明,将函数内部赋值的变量映射到全局作用域
语法:
global 变量1, 变量2, ...
说明:
1.在函数内部修改绑定不可变数据类型的全局变量时,必须用global声明,否则将被视为局部变量
2.全局变量在函数内部可以不经过声明直接访问
3.禁止先创建局部变量,再用global声明为全局变量
nonlocal语句:
作用:nonlocal声明,变量不是局部变量,而是外部嵌套函数内的变量
语法:
nonlocal 变量1,变量2
说明:
1.nonlocal语句只能在内嵌函数内使用
2.访问nonlocal变量将对外部嵌套函数作用域内的变量产生影响
3.当有2层或2层以上的函数嵌套时,访问nonlocal变量只对最近一层的变量进行操作
二.闭包
闭包的三个条件:
1.必须有内嵌函数
2.内嵌函数必须引用外部函数中的变量
3.外部函数返回值必须是“内嵌函数”
通常情况下,在函数调用结束后,函数内部变量会自动被释放掉。但闭包不同,如果外部嵌套函数在调用结束后,发现自己的变量在内嵌函数中有使用,则外部函数在调用结束后,在返回内嵌函数的同时,也会将这些变量传递给内嵌函数,一起绑定起来。这样,外部函数调用结束后,内嵌函数被调用时仍可以访问外部嵌套函数作用域内的变量。如下:
def outer(start):
step1 = 1
step2 = [1]
def iner():
#修改enclosing变量必须进行声明,告诉解析器step不是局部变量,而是enclosing变量
nonlocal step1
sum_num1 = start + step1 #仅访问start的值,而不做修改,故start无需声明
sum_num2 = start + step2[0] #对于可变数据类型,无需声明
print('start + step1 = %d' % sum_num1)
print('start + step2[0] = %d' % sum_num2)
step1 += 1
step2[0] += 2
return iner
a1 = outer(10)
a1()
print('-------------------')
a1()
print('-------------------')
a1()
运行结果:
start + step1 = 11
start + step2[0] = 11
-------------------
start + step1 = 12
start + step2[0] = 13
-------------------
start + step1 = 13
start + step2[0] = 15
三.递归函数 Recursion
1.函数直接或间接地调用自身,如:
def func():
'''直接调用自己,进入递归'''
func()
func()
def func1():
'''函数间接调用自身'''
func2()
def func2():
func1()
func1()
print("递归完成")
2.备注:
1.递归一定要控制递归的层数,当符合一定条件时,要终止递归调用;
2.几乎所有的递归,都能用while循环来代替
3.每次调用函数时,都会开辟一块独立的空间
3.优点:
简化问题,思路清晰,代码简洁(在适合使用递归地问题上,使用递归)
4.缺点:
递归因系统环境影响大,当递归深度太大时,可能会得到不可预知的结果
备注:
1.递归深度默认为1000
2.sys.getrecursionlimit()--->可以查看递归深度
3.sys.setrecursionlimit(n)--->可以修改递归深度
5.递归的两个阶段:
递推阶段:
由问题出发,从未知到已知,按递归公式递推,直到满足终止条件。
回归阶段:
由递归终止条件得到的结果出发,逆向逐步代入递归公式,回归问题。
6.递归的实现方法:
先假设函数已经实现
7.实例:
①计算等差数列1,2,3...n的和
def mysum(n):
if n == 1:
return 1
return n + mysum(n-1)
print(mysum(100))
运行结果:
5050
②写一个函数求n的阶乘
def myfac(n):
'''函数递归调用'''
if n==1:
return 1
return n * myfac(n-1)
print('5的阶乘是:', myfac(5))
运行结果:
5的阶乘是: 120
③L = [[3, 5, 8], 10, [[13, 14], 15, 18], 20]
1) 递归打印列表内的所有元素
2) 计算列表中所有元素的和
def print_list(L):
for item in L:
if type(item) is not list:
print(item,end=' ')
else:
print_list(item) #递归的思想
def sum_list(L):
sum_number = 0
for item in L:
if type(item) is not list:
sum_number += item
else:
sum_number += sum_list(item)
return sum_number
L = [[3, 5, 8], 10, [[13, 14], 15, 18], 20]
print_list(L)
print()
print("返回这个列表中所有元素的和:", sum_list(L))