python装饰器

装饰器(decorator)并不复杂、并不神秘,可以转化成一种公式的方式来理解

python装饰器是用于拓展原来函数功能的一种函数,不过是一个输入和输出都是函数的函数(python一切皆对象包括类、函数……)

使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。使用时在需要的函数前加上@demo即可。

正文:

  • 装饰器
  • 类装饰器
  • 装饰器类

装饰器:输入和输出都是函数的函数

复制代码
# 示例1
def dec(func):
    pass

@dec  # 语法糖
def double(x):
    return x * 2

double = dec(double)  # 完全等价
复制代码
复制代码
# 示例2,装饰器不带参数
import
time # 定义一个装饰器函数 def sayLocal(func): def wrapper(): curTime = func() return f"当地时间:{curTime}" return wrapper @sayLocal # 语法糖写法 def getXXXTime(): print(‘ ’) return time.strftime('%Y_%m_%d %H:%M:%S',time.localtime()) # 相当于将函数getXXXTime()作为一个参数传递给了函数sayLocal(),函数sayLocal()又返回了一个函数wrapper # 同时将这个返回的函数wrapper赋值给了函数getXXXTime getXXXTime = sayLocal(getXXXTime) # 完全等价 print(getXXXTime())
复制代码
复制代码
# 示例3,装饰器带参数
import time

def timeit(num):
    def outwrapper(func):
        def wrapper(*args, **kwargs):
            start = time.time()
            ret = func(*args, **kwargs)
            print('函数执行时间:', time.time() - start)
       return ret
return wrapper print('装饰器传递的参数:', num) return outwrapper @timeit(10) def double(x): return '计算结果:', x * 2 # timeit(10)打印了装饰器的参数,并返回一个函数outwrapper,这个函数outwrapper接受了一个参数函数func即函数double
# 并且在函数wrapper里面执行了函数double,然后返回了一个函数ret,ret被wrapper返回,函数wrapper又被outwrapper接受并返回
double = timeit(10)(double)  # 完全等价 print(double(2))
复制代码

类装饰器:可以当做装饰器的类

前提知识:

对于类而言,__new__方法的执行是由创建对象触发的,即:对象=类名();

而__call__方法的执行是由对象后加括号触发的,即:对象() 或者 类名()()

复制代码
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import time

# 装饰器类
class Timer:

    def __init__(self, func):
        self.func = func

    # 让所有这个类的实例,都变成一个callable,即类的实例类的对象都可以当做函数用。
    def __call__(self, *args, **kwargs):
        start = time.time()
        ret = self.func(*args, **kwargs)
        print(f"Time:{time.time()-start}")
        return ret

@Timer
def add(a, b):
    return a + b


# add函数作为参数传递进了Timer,变成了一个Timer类对象,然后add被传进了它的__init__函数里,
# __init__函数实例化了一个属性self.func,add作为一个参数被保存在了self.func里,然后整个这个Timer对象被保存在了add这个名字里面。
add = Timer(add)  # 完全等价 print(type(add))  # add变成了一个类class # add(2,3)执行调用了Timer对象的__call__函数,2和3就被传到了这个__call__里面,
# 所以它就运行了start等于时间,并拿到一个返回值ret
# self.func就是原来的add函数,把a和b加起来 然后返回到了ret里,然后打印了消耗的时间,再返回这个值ret,最后这个值再被print出来 print(add(2, 3)) # 类名()()会执行__call__方法,add(2,3)=Timer(add)(2,3)
复制代码
复制代码
# 装饰器类,带参数
class Timer:

    def __init__(self, prefix):
        self.prefix = prefix

    def __call__(self, func):
        start = time.time()
        ret = func()
        print(self.prefix+f"Time:{time.time()-start}")
        return ret


@Timer(prefix='curr_time: ')
def add():
    return '函数执行时间'

# prefix作为参数通过__init__函数转递给了实例对象self.prefix,而add作为了调用类方法(即类名()())__call__方法的一个参数func
add = Timer(prefix='curr_time: ')(add)   # 完全等价

print(add)
# 执行结果:
# curr_time: Time:0.0
# 函数执行时间
复制代码

装饰器类(类的装饰器):可以装饰类的装饰器

前提知识:

print(类)时会执行类的__str__函数

复制代码
#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 装饰类的 装饰器
# 这个装饰器本质上就是重载了一下这个类的__str__函数
def add_str(cls):

    def __str__(self):  # 自定义的__str__函数返回的self.__dict__的string形式
        return str(self.__dict__)
    cls.__str__ = __str__  # 把class的__str__函数,给替代成了它的自定义的__str__函数
    return cls

@add_str
class MyObject:

    def __init__(self, a, b):
        self.a = a
        self.b = b


# add_str函数的参数是类class,返回值也是类class,并在这个函数add_str中重写了一下类MyObject的__str__函数
MyObject = add_str(MyObject)  # 完全等价

o = MyObject(1, 2)  # add_str(MyObject)(1,2)
print(o)
# 输出结果:
# {'a': 1, 'b': 2}
复制代码

 

posted @   天才九少  阅读(37)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示