目录
一、匿名函数
匿名函数简单理解就是没有名字的函数
匿名函数的定义
lambda 参数列表: 表达式(变量)
匿名函数只能实现一些简单的逻辑
add_ = lambda x, y: x + y
print(add_(1, 2)) # 3
# 上述代码的实质
def test(x, y, func):
add_ = func(x, y)
return add_
print(test(1, 2, lambda x, y: x + y))
记忆内容
匿名函数下面这种使用方式需要记住:
info_dict = [{'name': '小明', 'age': 19, 'gender': '男'},
{'name': '小王', 'age': 20, 'gender': '男'},
{'name': '小红', 'age': 18, 'gender': '女'}]
# 需求:将info_dict列表中的字典进行排序,按照age的大小从小到大排序
info_dict.sort(key=lambda x: x['age'])
print(info_dict)
'''
[{'name': '小红', 'age': 18, 'gender': '女'},
{'name': '小明', 'age': 19, 'gender': '男'},
{'name': '小王', 'age': 20, 'gender': '男'}]
'''
二、闭包
理解引用
def test():
print('hello!')
test() # 调用函数 hello!
res = test
res() # 通过引用调用函数 hello!
print(id(test)) # 2159094682240
print(id(res)) # 2159094682240
test是我们定义的一个函数,函数名就相当于变量名,当我们定义一个变量名res等于函数名test时,res就等于是test函数的引用,指向了和test一样的内存地址
理解闭包
我们先写一个闭包程序
def test_out(num_out):
def test_in(num_in):
print(f'num_out的值为{num_out}')
print(f'num_in的值为{num_in}')
return num_in + num_out
return test_in
# 第一种调用方法
res_ = test_out(10)
print(res_(20))
# 第二种调用方法
print(test_out(10)(20))
逐步分析闭包的逻辑:
1.先将test_out函数加入到内存中
2.res_ = test_out(10):调用test_out函数,并把参数10传给test_out函数,因为test_out函数内部只有test_in函数的定义,所以只会将test_in函数加入内存,不会执行test_in函数
3.在调用test_out函数后,执行 return test_in ,是将test_in函数的引用返回,我们用res_变量进行接收,res_就等于是test_in函数的引用,指向了和test_in一样的内存地址
4.print(res_(20)):res_就等于是test_in函数的引用,res_(20)就等于test_in函数的调用,并给test_in函数传递了参数20,调用了test_in函数,执行print(f'num_out的值为{num_out}'),输出num_out的值10,然后执行print(f'num_in的值为{num_in}'),输出num_in的值20
5.最后执行return num_in + num_out,由于我们直接打印了返回值,所以输出30
我们能否直接调用test_in函数呢?
def test_out(num_out):
def test_in(num_in):
print(f'num_out的值为{num_out}')
print(f'num_in的值为{num_in}')
return num_in + num_out
return test_in
test_in(20) # name 'test_in' is not defined
答案是不能,程序会报错,name 'test_in' is not defined
我们可以这么理解:
程序:我们先调用test_out函数,拿到test_in函数的引用,才能调用test_in函数
理解:我们进入客厅,拿到进入卧室的钥匙,才能进入钥匙
定义:定义一个函数,在函数内部在定义一个函数,并且这个函数用到了外部函数的局部变量,那么这个函数以及用到的变量称之为闭包
闭包三要素:
1.函数的嵌套
2.外部函数返回内部函数的引用
3.内部函数用到了外部函数的局部变量
闭包实例
需求:计算y = kx + b 的值(k,b,x不定)
def line_conf(k, b):
def line(x):
return k * x + b
return line
print(line_conf(4, 5)(2))
# y = 4 * x + 5 , y = 4 * 2 + 5
三、装饰器
装饰器的理解
def f1(func):
def f2():
print('hello')
func()
return f2
@f1 # 语法糖
def f3():
print('world')
f3()
'''
执行结果:
hello
world
'''
python代码从上到下执行,先将f1函数加载到内存中,然后执行到@f1,这条语句会调用f1函数,并且将下面的函数(代码中是f3函数)作为参数传递给f1函数,即形参func = f3,然后f2函数中的形参func也变成f3函数
def f1(f3):
def f2():
print('hello')
f3()
return f2
因为@f1调用了f1函数并且将f3作为传输传递给了f1函数,在f1调用过程中:把f2函数加载到了内存中(并没有调用f2函数),执行return f2,此时f2已经变成了
def f1(f3):
def f2():
print('hello')
print('world')
return f2
print('world')是因为调用了f3函数,我们可以理解为 直接把f3函数内部的代码加到f2函数中
返回的f2函数由f3函数接收,f3函数变成变化后的f2函数
def f2():
print('hello')
print('world')
所以我们在后面调用f3函数时就等于调用了f2函数
def f2():
print('hello')
print('world')
装饰器实例
需求:在xml格式的数据中,通常可以看见类似这样的形式:<app> <id>Chrome</id> </app>
如果我们只有中间部分的字符串,如何通过装饰器给字符串加上上面形式的标签呢?
def makeAPP(fn):
def wrapped():
return '<app>' + fn() + '</app>'
return wrapped
def makeID(fn):
def wrapped():
return '<id>' + fn() + '</id>'
return wrapped
@makeAPP
@makeID
def slogan():
return 'Chrome'
print(slogan()) # <app><id>Chrome</id></app>
代码中我们使用了两个装饰器,解释器从上到下执行,装饰器从下向上执行
先执行@makeID,变成<id>Chrome</id>,再执行@makeAPP,变成<app><id>Chrome</id></app>
当被装饰的函数有参数时,被装饰的函数有几个形参,装饰器的内函数就必须有几个参数