装饰器
装饰器模式( Decorator Pattern )允许向一个现有的事物添加新的功能,同时又不改变其结构。
闭包:能够访问上层局部变量的内层函数
函数内部的局部变量在外部是无法访问的,闭包就是为了可以在函数外部访问函数内部的局部变量或让函数内部变量保存在内存中
def outer(tag):
"""给content添加标签,读取上层函数的局部变量tag"""
def inner(content):
print(f"<{tag}>{content}<{tag}>")
return inner
tag = "span"
content = "hello"
add_tag = outer(tag) # 把内部局部变量绑定到内部函数中,并返回内部函数赋值给全局变量add_tag
add_tag(content) # 在outer函数的外部使用了内部局部变量tag
hello
def create(pos=[0,0]):
def inner(direction, steps):
pos[0] = pos[0]+ direction[0]*steps
pos[1] = pos[1]+ direction[1]*steps
return pos
return inner
player = create() # create返回内部函数并将内部函数赋值给了全局变量
# 内部函数依赖上层局部变量pos,所以上层局部变量pos和全局变量player一样一直在内存中不会被回收
print(player([0,1], 10)) # [0, 10]
print(player([1,0], 10)) # [10, 10]
装饰器
装饰器就是在闭包的基础上实现的,外部函数接收一个函数作为参数。在不改变内部代码的情况下,增加代码的功能。
def dec1(func):
def inner(*args, **kwargs):
print(f"装饰函数{func.__name__}")
return func(*args, **kwargs)
return inner
@dec1
def sum_(a, b):
return a+b
print(sum_(1,2))
带参装饰器
def dec2(text):
"""带参装饰器,返回一个装饰器的函数,嵌套的装饰器"""
def wrapper(func):
def inner(*args, **kwargs):
print(f"装饰函数{func.__name__},装饰器参数:{text}")
return func(*args, **kwargs)
return inner
return wrapper
@dec2("2020")
def sum_(a, b):
return a+b
print(sum_(1,2))
functools.wraps
被装饰的函数的名称、模块、描述、都会变成装饰器函数的内容
def sum_(a,b):
"""sum函数的描述,求和运算"""
return a+b
print(sum_.__name__, sum_.__module__, sum_.__doc__) # sum_ __main__ sum函数的描述,求和运算
def dec3(func):
"""dec3——"""
def inner(*args, **kwargs):
"""inner装饰器函数的描述"""
return func(*args, **kwargs)
return inner
@dec3
def test():
print("test")
print(test.__name__, test.__module__, test.__doc__) # inner __main__ inner装饰器函数的描述
使用functools.wraps可以解决
import functools
def dec3(func):
@functools.wraps(func)
def inner(*args, **kwargs):
"""inner装饰器函数的描述"""
return func(*args, **kwargs)
return inner
@dec3
def test():
"""test的描述"""
print("test")
print(test.__name__, test.__module__, test.__doc__) # test __main__ test的描述
基于类实现的装饰器
装饰器函数接收一个callable对象,返回一个callable对象
不带参的装饰器
构造函数接收函数,__call__相当于装饰器函数
class dec:
def __init__(self, func):
"""init"""
self.func = func
def __call__(self, *args, **kwargs):
"""call"""
print("装饰",self.func.__name__)
return self.func(*args, **kwargs)
@dec
def test():
"""test的描述"""
print("test")
test()
带参类装饰器
构造函数接收参数,call接收函数
class dec2:
def __init__(self, text):
self.text = text
def __call__(self, func):
"""call"""
@functools.wraps(func) # 让被装饰函数的name,doc,module保持原有的值
def wrap(*args, **kwargs):
"""wrap"""
return func(*args, **kwargs)
return wrap
@dec2('text')
def test():
"""test的描述"""
print("test")
test()
装饰器实现单例模式
def singleton(cls):
instance = {}
def get_instance(*args,**kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return get_instance
@singleton
class A:
def __init__(self):
pass
a = A()
b = A()
print(a is b) # True
装饰类
# 给每个对象添加创造时间
import time
def decc(cls):
def wrap(*args, **kwargs):
obj = cls(*args,**kwargs)
obj.creat_time = time.time()
return obj
return wrap
@decc
class temp:
def __init__(self):
pass
def get_c(self):
return self.creat_time