python装饰器详解

一、函数装饰器,装饰函数

 #上面是装饰器,下面是原函数   
def ifren(p):    #p是额外带来的参数,因为要带参数p所以多了一层函数嵌套,如果需要给装饰器本身传递参数,可以使用一个外层函数来封装装饰器。
    def plusnihao(function):
    
        def wraper():  #核心装饰器代码,function代指sayhello函数,是由上一层传入进来的,本层负责增加前后功能
            function()
            print("and nihao")  #添加的功能
            print(p)             #最上层传入进来的,是额外带进来的参数

        return wraper      #返回核心装饰器
    return plusnihao       #因为有参数p,再给核心装饰器装一层皮 返回
     
@ifren(1000)               #额外的参数p。 @后面是装饰器函数名   这句话相当于 ifren(1000)(plusnihao(wraper(sayhello)))
def sayhello():
    print("nihao")

sayhello()           #用原函数运行

再一例子

def decorator(func):
    def wrapper(*args, **kwargs):  # 参数必须和func一样,这样写全能
        # 在这里添加额外的功能
        print("Before calling the function")
        result = func(*args, **kwargs)   #以前什么参数,现在原样执行
        print("After calling the function")
        return result  # 有没有返回不重要

    return wrapper


@decorator
def my_function(a=5, b="fgh"):
    print(f"Hello{a}, this is my {b} function.")


# 调用my_function时,实际上调用的是wrapper函数
my_function()

 

# 使用functools.wraps保留原函数信息
# 在使用装饰器时,原函数的元信息(如函数名、文档字符串等)会被包装函数所替代。为了保留这些信息,可以使用functools.wraps装饰器。

from functools import wraps

def my_decorator(func):
    @wraps(func)   #这个地方保留
    def wrapper(*args, **kwargs):
        print("Something is happening before the function is called.")
        result = func(*args, **kwargs)
        print("Something is happening after the function is called.")
        return result

    return wrapper

@my_decorator
def example():
    """This is an example function."""
    print("Hello from a function.")

print(example.__doc__)  # 输出: This is an example function.

 二、类装饰器,装饰函数

# author:baoshan
# 带参数的类装饰器,和不带参数的类装饰器有很大的不同
# 类装饰器的实现,必须实现__call__和__init__两个内置函数。
# __init__:装饰器带参数时不再接收被装饰函数,而是接收传入参数;没带参数时接受函数为构造函数
# __call__:带参数时接收被装饰函数,再起一层wrapper。不带参数时接受参数*args, **kwargs参数,这时他就是wrapper。

例子:不带参数

from functools import wraps 

class animal:
    def __init__(self, func): #原函数变为类的构造函数
        self.func = func

    # @wraps  保留函数元信息
    def __call__(self, *args, **kwargs):#在Python中,__call__是一个特殊方法,
        #它允许一个类的实例表现得像函数一样,可以被调用。当你调用一个类的实例时,Python会自动执行该实例的__call__方法
        print("working here")
        res = self.func(*args, **kwargs)
        return res


@animal    #类装饰器装饰函数,函数就变为了类的构造函数
def test(name, kind):
    word = f"{name} belongs to {kind}"
    return word


A = test("cow", "mammals")
print(type(test))
print(A)

 

例子:带参数

class animals:
    def __init__(self, prefix):
        self.prefix = prefix  # 装饰器传入的参数变为类的属性

    def __call__(self, func):  # 原传入函数在call函数传入,再起一层wraooer
        def wrapper(*args, **kwds):  # 核心装饰器,参数用通用的这个格式
            print("前置功能" + self.prefix)
            print(func(*args, **kwds))
            print("后置功能")

        return wrapper


@animals("汪汪叫")
def cat(c):
    print(f"叫声是{c}")


cat("喵喵叫")

 

posted @ 2024-12-16 22:49  遥月  阅读(834)  评论(0)    收藏  举报