*运维架构师-Python 自动化运维开发-025
十四、高阶函数介绍
1、特点把一个函数的函数名当做实参传给另一个函数
函数本身可以作为另外一个函数的返回值
def foo():
return 10
def func(bar):
print(id(bar), bar)
func(foo())
#def func(foo):
# print(id(foo),foo)
# 直接打印原函数的 id
print(id(foo))
# 调用函数 并把 foo 作为实参传递进去,查看传输的函数的 id
func(foo())
在调用函数 func(foo) 时,如下图:可以看出被传入的函数和原函数是一个对象
2、内部函数
在一个函数内部定义的函数
def outer():
def inner():
x = 10函数 inner 就是一个内部函数
3、 闭包
是一个函数动态生成的另一个函数,并且返回一个 包含了外部作用域而非全局作用域变量名称的函数。这个函数可以使用外部作用域的变量。
闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)
python语言中形成闭包的三个条件,缺一不可:1)必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套2)内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量3)外部函数必须返回内嵌函数——必须返回那个内部函数
# 什么是闭包
# 定义一个函数
def test(number):
# 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
def test_in(number_in):
print("in test_in 函数, number_in is%d" % number_in)
return number+number_in
# 其实这里返回的就是闭包的结果
return test_in
# 给test函数赋值,这个20就是给参数number
ret = test(20)
# 注意这里的100其实给参数number_in
print(ret(100))
# 注意这里的200其实给参数number_in
print(ret(200))
# 运行结果:
in test_in 函数, number_in is 100
120
in test_in 函数, number_in is 200
220
#_*_ coding:utf-8 _*_
# def test():
# x = 10
# def test_in(num_in):
# print("在test_in函数, num_in is %d" % num_in)
# return x + num_in
# print(x)
# return test_in
#test()
# 1. 调用test函数,开始执行函数
# 2,产生局部变量 x = 10
# 3,定义一个函数(没有调用,不执行),只有test_in函数方法
# 4, 打印输出变量x
# 5,把定义的test_in 这个函数返回给调用者(test函数调用的)
# 6,最后获取的的值 test_in 函数
# ret = test()
# 把返回的test_in函数重命名为ret(类似于变量赋值)
# print(ret)
# 打印输出一下test_in函数方法,返回test_in 函数方法
# print(ret(1000))
# 相当于调用了 test_in函数,返回 test_in 返回值(相加的结果)
def test(arg):
def test_in(num_in):
print("在test_in函数, num_in is%d" % num_in)
return arg + num_in
print(arg)
return test_in
test(10) # 打印了一下arg ===》10
print(test(10)) # 打印10 并放回test_in 函数
ret1 = test(10) # 把test函数的返回值赋值给ret1
print(id(ret1)) # 打印ret1的函数内存位置(也就是test_in这个函数的内存位置)
print(ret1(100)) # 调用了test_in函数,返回了结果 arg ===>10 + num_in ===》100 ===》110
#函数可以作为另一个函数的参数或返回值,可以赋给一个变量。函数可以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题。如:
def outer(f):
def inner():
print(f)
return inner
really_inner = outer(10)
really_inner()
上面的 f 可以是任何的 python 对象,当然也可以是给函数。
def foo():
pass
def outer(f)
def inner():
print(f)
return inner
really_inner = outer(foo)
此时, really_inner 就是闭包, 其本质就是 inner 函数对象, 并且包含了 foo 这个函数对象。
创造一个闭包:
def line_conf():
def line(x):
return 2*x+1
return line # 返回line 函数对象
my_line = line_conf()
print(my_line(5))
def line_conf():
b = 15
def line(x):
return 2*x+b
return line # 返回line 函数对象
b = 5
my_line = line_conf()
print(my_line(5)) # 返回25
# 在内部函数中只能对外部函数的局部变量进行访问,但是不能修改,如果需要修改则需要用到nonlocal关键字,委屈求全可以使用“容器类型”代替
def line_conf():
b = 15
def line(x):
nonlocal b
b=20
return 2*x+b
return line # return a function object
b = 5
my_line = line_conf()
print(my_line(5)) #返回30
def line_conf():
b = [15]
def line(x):
b[0]=20
return 2*x+b[0]
return line # return a function object
my_line = line_conf()
print(my_line(5)) #返回30
我们根据上面的三准则创造了一个函数,其中的funy就是所谓的闭包,而funy内部所引用过的x就是所谓的闭包变量。
闭包有什么用
在交互式模式下,对函数进行简单的测试:
def funx():
x=5
def funy(): # 内部函数中只能对外部函数的局部变量进行访问,不能修改
nonlocal x # 如果需要修改则需要用到 nonlocal关键字
x+=1
return x
return funy
>>> a=funx()
>>> a()
6
>>> a()
7
>>> a()
8
>>> a()
9
>>> x
Traceback (most recent call last):
File "", line 1, in
x
NameError: name 'x' is not defined
>>>
funx中的x变量原本仅仅是funx的一个局部变量。但是形成了闭包之后,它的行为就好像是一个全局变量一样。但是最后的错误说明x并不是一个全局变量。其实这就是闭包的一个十分浅显的作用,形成闭包之后,闭包变量能够随着闭包函数的调用而实时更新,就好像是一个全局变量那样。(注意我们上面的a=funx(),a实际上应该是funy,所以a称为闭包)
4、 装饰器
1、原始方式实现(老的方式)
def echo():
print('欢迎来到千锋云计算')
def outer(arg): # arg = echo ---> arg()===echo()
def inner():
print("*" * 20)
arg() # echo() 原函数
print("*" * 20)
return inner
echo = outer(echo) # 最终的结果是inner()函数
# def outer(echo):
# def inner():
# print("*" * 20)
# echo()
# print("*" * 20)
# return inner
echo()
# 执行流程
# 1,运行echo()函数 (放进内存)
# 2,运行outer(arg)函数 (放进内存)
# 3,重新赋值后调用 outer(arg)函数,
# 4,运行inner()函数 (放进内存)
# 5,调用inner()函数并返回结果
# 6,echo()得到新结果
# 7,业务线的调用echo()函数的方式没有变,但功能添加了
# 8,业务线调用新的echo()函数,就开始执行inner函数
# 9,根据函数执行顺序,包含了原来的echo()函数和添加的功能
2、语法糖实现(目前使用此种方式)
def outer(arg): # arg = echo()
def inner():
print("*" * 20)
arg() # echo 原函数
print("*" * 20)
return inner
@outer
# 1, 执行outer函数 outer(echo),
# 2,获取outer的返回值,并把返回值赋值给被装饰的函数的函数名,echo = outer(echo) 最终 echo=inner()
def echo():
print('欢迎来到千锋云计算')
echo()
# 执行装饰器,对被装饰的的函数进行重新赋值
使用装饰器的理由
在软件开发领域有个规则:
在开发时,需要遵循 开放封闭原则,就是对扩展开放,对修改封闭。
扩展开放,就是可以对原来的函数功能进行扩展。
修改封闭,就是给原来的函数添加功能的时候,不可以直接修改原来的函数。
装饰器的作用是什么
装饰器时装饰其他对象的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:不修改被装饰对象的源代码
不修改被装饰对象的调用方式
装饰器的目标:
在遵循1和2的前提下,为被装饰对象添加上新功能
3、补充内置函数 枚举 enumerate
li = ["hello","world", 'len', 'network']
#
# for idx, item in enumerate(li):
# print(idx, item)
# for idx, item in enumerate(li, 1):
# print(idx, item)
欢迎访问磊哥B站主页:千锋云计算磊哥
喜欢文章的话,欢迎点赞收藏评论互动哦~