装饰器

装饰器模式( 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
posted @ 2022-06-22 21:41  店里最会撒谎白玉汤  阅读(47)  评论(0)    收藏  举报