*args:负责将多余的位置实参汇总,赋值给args
**kwargs:负责将多余的关键字实参汇总,赋值给kwargs
命名空间与作用域
函数对象:
函数的嵌套定义:在函数内定义函数
闭包函数:父函数的返回值为一个函数,被返回的函数调用了父函数的局部变量,且该函数可以在父函数外部执行
装饰器:定义一个为其他函数添加功能的函数
为什么要使用装饰器?
装饰器实现
# 需求:不修改源代码,计算代码执行时间 # 源代码 import time def func0(x): time.sleep(1) print(x) func0(0) # 方案一:实现了计算代码执行时间的功能,但修改了源代码,不符合要求 def func1(x): start = time.time() time.sleep(1) print(x) end = time.time() print('方案一 运行时间:{}'.format(end - start)) func1(1) # 方案二:满足要求,但代码不具备重用性 start = time.time() func0(2) end = time.time() print('方案二 运行时间:{}'.format(end - start)) # 方案三:将方案二封装为函数,但修改了函数的调用方式,不符合要求 def wrapper(): start = time.time() func0(3) end = time.time() print('方案三 运行时间:{}'.format(end - start)) wrapper() # 方案四:不修改原函数的调用方式 def wrapper(x): start = time.time() func0(x) end = time.time() print('方案四 运行时间:{}'.format(end - start)) wrapper(4) # 方案五:方案四参数被写死,优化方案四 def wrapper(*args, **kwargs): start = time.time() func0(*args, **kwargs) end = time.time() print('方案五 运行时间:{}'.format(end - start)) wrapper(5) # 方案六:方案五函数被写死,优化方案五,但修改了源代码的调用方式 def outter(a): def wrapper(*args, **kwargs): start = time.time() a(*args, **kwargs) end = time.time() print('方案六 运行时间:{}'.format(end - start)) return wrapper f = outter(func0) f(6) # 方案七:优化方案六(outter即为装饰器,用于装饰func0) def outter(a): def wrapper(*args, **kwargs): start = time.time() a(*args, **kwargs) end = time.time() print('方案七 运行时间:{}'.format(end - start)) return wrapper func0 = outter(func0) # 偷梁换柱,调用者无感知 func0(7)
运行结果:
0
1
方案一 运行时间:1.001857042312622
2
方案二 运行时间:1.0040733814239502
3
方案三 运行时间:1.0017154216766357
4
方案四 运行时间:1.007995367050171
5
方案五 运行时间:1.0145602226257324
6
方案六 运行时间:1.0046615600585938
7
方案七 运行时间:1.0094060897827148
# 不使用语法糖 import time def func0(x): time.sleep(1) print(x) # func0(0) def outter(a): def wrapper(*args, **kwargs): start = time.time() a(*args, **kwargs) end = time.time() print('运行时间:{}'.format(end - start)) return wrapper func0 = outter(func0) func0('hello')
# 使用语法糖 import time def outter(a): def wrapper(*args, **kwargs): start = time.time() a(*args, **kwargs) end = time.time() print('运行时间:{}'.format(end - start)) return wrapper @outter # 语法糖,等价于该行func0 = outter(func0) def func0(x): time.sleep(1) print(x) func0('hello') print(func0.__name__)
运行结果
hello
运行时间:1.0050427913665771
wrapper
# 装饰器模板 def decorator_name(x): def wrapper(*args, **kwargs): # ...新添加的功能... # 下为调用原函数的格式 x(*args, **kwargs) return wrapper @decorator_name def func_name(): pass
# 不使用装饰器 import time def func0(x): time.sleep(1) print(x) func0('hello') print(func0.__name__) # 查看函数名 print(help(func0)) # 查看帮助信息(主要为注释内容)
运行结果:
hello
func0
Help on function func0 in module main:func0(x)
这是函数None
import time def outter(a): def wrapper(*args, **kwargs): '''这是装饰器''' start = time.time() a(*args, **kwargs) end = time.time() print('运行时间:{}'.format(end - start)) return wrapper @outter # func0 = outter(func0) def func0(x): '''这是函数''' time.sleep(1) print(x) func0('hello') print(func0.__name__) print(help(func0))
运行结果:
hello
运行时间:1.011878490447998
wrapper
Help on function wrapper in module main:wrapper(*args, **kwargs)
这是装饰器None
呕吼,露馅了
import time def outter(a): def wrapper(*args, **kwargs): '''这是装饰器''' start = time.time() a(*args, **kwargs) end = time.time() print('运行时间:{}'.format(end - start)) wrapper.__name__ = a.__name__ wrapper.__doc__ = a.__doc__ return wrapper @outter # func0 = outter(func0) def func0(x): '''这是函数''' time.sleep(1) print(x) func0('hello') print(func0.__name__) print(help(func0))
运行结果:
hello
运行时间:1.0030155181884766
func0
Help on function func0 in module main:func0(*args, **kwargs)
这是函数None
但是,函数有很多属性和方法,一个一个手动修改过于麻烦,甚至可能会遗漏,但python也提供了解决方法
import time from functools import wraps def outter(a): @wraps(a) def wrapper(*args, **kwargs): '''这是装饰器''' start = time.time() a(*args, **kwargs) end = time.time() print('运行时间:{}'.format(end - start)) # wrapper.__name__ = a.__name__ # wrapper.__doc__ = a.__doc__ return wrapper @outter # func0 = outter(func0) def func0(x): '''这是函数''' time.sleep(1) print(x) func0('hello') print(func0.__name__) print(help(func0))
运行结果:
hello
运行时间:1.0114128589630127
func0
Help on function func0 in module main:func0(x)
这是函数None
def outter(db_type): # 装饰器auth def auth(x): def wrapper(*args, **kwargs): if db_type == 'file': name = input('请输入姓名:') passwd = input('请输入密码:') if name == 'zhangsan' and passwd == '123': x(*args, **kwargs) print('基于文件认证') else: print('用户名或密码错误,认证失败') elif db_type == 'mysql': x(*args, **kwargs) print('基于数据库认证') else: print('未知认证方式,不支持') return wrapper return auth # 函数 auth = outter(db_type='file') @auth def file(): print('hello') auth = outter(db_type='mysql') @auth def mysql(): print('world') msg = input('请选择认证方式(1=file|2=mysql):').strip() if msg =='1': file() elif msg == '2': mysql() else: print('不支持')
def outter(db_type): # 装饰器auth def auth(x): def wrapper(*args, **kwargs): if db_type == 'file': name = input('请输入姓名:') passwd = input('请输入密码:') if name == 'zhangsan' and passwd == '123': x(*args, **kwargs) print('基于文件认证') else: print('用户名或密码错误,认证失败') elif db_type == 'mysql': x(*args, **kwargs) print('基于数据库认证') else: print('未知认证方式,不支持') return wrapper return auth # 函数 # auth = outter(db_type='file') # @auth @outter(db_type='file') def file(): print('hello') # auth = outter(db_type='mysql') # @auth @outter(db_type='mysql') def mysql(): print('world') msg = input('请选择认证方式(1=file|2=mysql):').strip() if msg =='1': file() elif msg == '2': mysql() else: print('不支持')
# 有参装饰器模板 def out_decorator_name(x,y,z): def decorator_name(a): def wrapper(*args, **kwargs): # ...新添加的功能... # 下为调用原函数的格式 a(*args, **kwargs) return wrapper return decorator_name @out_decorator_name(x,y,z=1) def func_name(): pass