函数进阶以及知识点补充
主要内容
1,通用装饰器回顾
2,函数的有用信息
3,带参数的装饰器
4,多个装饰器同时装饰一个函数
一,通用装饰器的回顾
开闭原则:对增加功能开放,对修改代码封闭
装饰器的作用:在不改变源代码的基础上给一个函数增加功能
通用装饰器的写法:
def wrapper(func):
def inner(*args, **kwargs):
print("目标函数执行之前要执行的内容")
ret = func(*args, **kwargs)
print("目标函数执行之后要执行的内容")
return ret
return inner
@wrapper
def func1():
print("我爱祖国")
func1()
执行过程:
1,程序从上向下,当执行到@wrapper的时候,把函数作为参数传递给wrapper函数,得到inner函数,重新赋值给func1
2,当执行到func1的时候,我们实际执行的是inner函数.inner函数会执行目标函数之前的代码,然后在执行你的目标函数,执行完目标函数最后执行的是目标函数之后的代码
二,函数的有用信息
1,如何给函数添加注释
def chi(food, drink):
'''
这里是函数的注释,先写一下当前函数是干什么的,比如我们这个函数就是一个吃
:param food: 参数food是社么意思
:param drink: 参数drink是什么意思
:return: 返回的值是什么
'''
print(food, drink)
return 'very good'
def chi(food, drink):
'''
这里是函数的注释,先写一下当前函数是干什么的,比如我们这个函数就是一个吃
:param food: 参数food是社么意思
:param drink: 参数drink是什么意思
:return: 返回的值是什么
'''
print(food, drink)
'''
这个可以获取到么
'''
print(chi.__doc__) # 获取函数的文档注释
print(chi.__name__) # 获取到函数名称
return 'very good'
chi('吃嘛嘛香', '我不想吃')
print(chi.__doc__)
print(chi.__name__)
函数名.__name__可以查看函数的名字
函数名.__doc__可以查看函数的文档注释
接下来看下被装饰器装饰之后的函数名:
def wrapper(func):
def inner(*args, **kwargs):
print('目标函数之前执行的内容')
ret = func(*args, **kwargs)
print('目标函数之后执行的内容')
return ret
return inner
@wrapper
def func1():
print("我爱我的祖国")
func1()
print(func1.__name__) # inner
# 分析:虽然执行的是func1函数,但是装饰器经过func1 = wrapper(func1),返回的值是inner,所以实际执行的是inner
问题来了,我们虽然访问的是func1函数.但实际上执行的是inner函数,这样就会给下游程序员带来困惑,之前不是一直执行的是func1么,为什么突然换成了inner.接下来的实现方案:
from functools import wraps
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs):
print("目标函数执行之前执行的内容")
ret = func(*args, **kwargs)
print('目标函数执行之后执行的内容')
return ret
return inner
@wrapper
def func1():
print("我爱我的祖国")
func1()
print(func1.__name__) # func1
PS: *args和**kwargs什么时候打散,什么时候聚合
1,接收参数的时候是聚合,参数声明
2,传递参数的时候是打散,给函数传递实参
def wrapper(func):
def inner(*args, **kwargs): # 这里是聚合
print("目标函数执行之前执行的内容")
ret = func(*args, **kwargs) # 这里是打散
print("目标函数执行之后执行的内容")
return ret
return inner
三,装饰器传参
给装饰器设置一个开关,可以控制装饰器是否运行
from functools import wraps
def wrapper_out(flag):
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs):
if flag:
print('目标函数执行之前执行的内容')
ret = func(*args, **kwargs)
print('目标函数执行之后执行的内容')
return ret
else:
ret = func(*args, **kwargs)
return ret
return inner
return wrapper
@wrapper_out(False)
def func1():
print("我爱我的祖国")
func1()
四,多个装饰器装饰同一个函数
def wrapper(func):
def inner(*args, **kwargs):
print("目标函数执行之前的内容1")
ret = func(*args, **kwargs)
print("目标函数执行之后的内容2")
return ret
return inner
def wrapper1(func):
def inner(*args, **kwargs):
print("目标函数执行之前的内容3")
ret = func(*args, **kwargs)
print("目标函数执行之后的内容4")
return ret
return inner
@wrapper1
@wrapper
def func1():
print("我爱我的祖国")
func1()
# 结果
# 目标函数执行之前的内容3
# 目标函数执行之前的内容1
# 我爱我的祖国
# 目标函数执行之后的内容2
# 目标函数执行之后的内容4
执行顺序:首先@wrapper装饰起来,然后获取到一个新函数是wrapper中的inner.然后执行@wrapper1.这个时候wrapper1装饰的就是wrapper中的inner了.所以,执行顺序就是像:第二层装饰器前(第一层装饰器前(目标)第一层装饰器后)第二层装饰器后.程序从左往右执行起来就是我们看到的结果
小知识点补充:
枚举,编码,解码 lst = ['周杰伦', '李嘉诚', '奥特曼', '小怪兽'] for index, element in enumerate(lst): print(index, element) # 0 周杰伦 # 1 李嘉诚 # 2 奥特曼 # 3 小怪兽 s = "明天就要过端午节了" bys = s.encode('utf-8') print(bys) #b'\xe6\x98\x8e\xe5\xa4\xa9\xe5\xb0\xb1\xe8\xa6\x81\xe8\xbf\x87\xe7\xab\xaf\xe5\x8d\x88\xe8\x8a\x82\xe4\xba\x86' s1 = bys.decode('utf-8') print(s1) # 明天就要过端午节了

浙公网安备 33010602011771号