当前位置: 首页 > news >正文

Python 装饰器 (面向切面编程,语法糖,AOP)

intro

        本文主要记录Python decorator相关的知识。最近想要使用插桩去对一些库进行魔改的时候,发现某些库并没有提供显式的插桩接口。但是这些库函数的代码又确实十分复杂,于是就想到了直接在函数层面进行插桩,这样虽然自动化程度变低了,但是控制粒度更加精细。笔者之前曾经学习过关于Spring框架的相关知识,于是就想Python中是否也有类似的AOP机制,了解之后发现,原来就是decorator,纵观这些玩意有各种名字,但是本质思想其实一模一样。

理解Python中函数的本质

        本着万物皆可对象的原则,函数实际上也是一种Object!所以其实函数本身也可以当做一种参被各种操作!比如:

def add(a):return a+1def addplus(func):def wrap(a):print("Test!")res=func(a)return resreturn wrapprint(addplus(add)(1))

Decorator函数

        以上代码可以看出,这么去对函数进行加工然后调用不免有点麻烦,所以就可以用更轻松地机制。使用@就可以轻松完成对函数的改造。

def addplus(func):def wrapper(*args,**kwargs):print("Test!")res=func(*args,**kwargs)return resreturn wrapper@addplus
def add(a):return a+1print(add(1))

        在上面这个示例中,@addplus的的效果等同于:

add=addplus(add)

        然后就会有人想到既然函数能作为一个普通的object被传来传去,那能不能来个套娃,像下面这样:

def addpp(str1):def addplus(func):def wrapper(*args,**kwargs):print(str1)res=func(*args,**kwargs)return resreturn wrapperreturn addplus@addpp("Test")   
def add1(a):return a+1print(add1(1))

其实这种形式就相当于给decorator套了一层decorator,所以等价于:

add1=addpp("Test")(add1)

Decorator 类

根据前面说的,其实装饰器的本质就是定义函数的时候把定义的函数当成一种参数,毕竟它自己本身就是一种对象。然后传递给一个Decorator函数,那么就能够想到类的初始化的时候,是不是也可以接受函数作为它的一个成员呢,并且我们再定义一个__call__不就能达到相同的效果了吗?

class addcls:def __init__(self,func):self.func=funcdef __call__(self,*args,**kwargs):print("Test!")res=self.func(*args,*kwargs)return res@addcls    
def add2(a):return a+1print(add2(1))

其实这就相当于,add2变成了一个addcls的对象!

adds=addcls(add2)

当然也可以这么去实现:这时候add2就相当于是一个class里边定义的wrapper函数

class addcls:def __init__(self,str1):self.str1=str1def __call__(self,func):def wrapper(*args,**kwargs):print(self.str1)res=func(*args,**kwargs)return resreturn wrapper@addcls("Test")    
def add2(a):return a+1print(add2(1))

类的Decorator

既然函数能被当做对象,那么类本身也可以被当做一个对象被作为参数传递给函数。注意这里是类,并不是实例化后的对象!这样说比较抽象,不妨就把类当成一堆代码块就好,我们可以对代码块进行一些操作。所以也会有类的Decorator,以下是一个例子:

def addclsfunc(cls):def __str__(self):return str(self.__dict__)cls.__str__=__str__return cls@addclsfunc
class addcls2:def __init__(self,a,b):self.a=aself.b=bAddcls2=addcls2(1,2)
print(Addcls2)

在类中定义Decorator:

这个问题稍微就比较复杂一点,首先让我么来了解两点:

1. @staticmethod(静态方法)

@staticmethod 用于定义不依赖实例或类的函数。它不需要传入 self(实例)或 cls(类)参数,因此只能访问方法内部的局部变量,不能访问类属性或实例属性。使用类或者实例均可调用!

使用场景:当方法只是一个工具函数,不需要访问或修改类或实例的状态时,适合用静态方法。例如,进行一些数学运算或辅助性的操作。

2. @classmethod(类方法)

@classmethod 用于定义绑定在类上的方法。类方法的第一个参数是 cls,代表类本身。类方法可以访问和修改类属性(而不是实例属性)。

使用场景:当需要创建工厂方法或想对类级别的属性进行访问或修改时,使用类方法比较合适。例如,通过类方法提供另一种创建实例的方式,或者用于管理类的状态。

一定要理解在python中类和对象是两个不同的概念,是两种不同的object!类的成员和类实例化对象的成员是独立的!

class test:a=1def __init__(self,a):self.a=at=test(2)
print(t.a)
print(test.a)

在类中定义Decorator的形式有如下几种:

最后这种形式无论是对象调用或者类调用都能正常工作!


http://www.mrgr.cn/news/67004.html

相关文章:

  • python批量合并excel文件
  • Linux上python离线安装教程
  • Hadoop期末复习(完整版)
  • MySQL45讲 第八讲 事务到底是隔离的还是不隔离的?
  • Rust 力扣 - 1343. 大小为 K 且平均值大于等于阈值的子数组数目
  • 惊呆:where 1=1 可能严重影响性能,差了10多倍,快去排查你的 sql
  • PySpark 本地开发环境搭建与实践
  • 对自动化测试的一些展望与理解
  • Linux(CentOS)安装 MySQL
  • 伊莱亚斯 M. 斯坦恩(Elias M. Stein)《复分析》与《实分析》教材
  • APP 后台广告位配置的关键要素与策略
  • 浏览器是如何渲染页面的? - 2024最新版前端秋招面试短期突击面试题
  • 编程语言越来越多,为什么C/C++还没有被现在的时代淘汰呢?
  • 智合同丨买卖合同纠纷中,起诉关联公司需要准备些什么?
  • JVM 内存结构中哪些区域可能发生 OOM
  • 红队-linux基础(1)
  • linux利用环境变量提权以及如何防范
  • 基本开关电源电路分析
  • Axure设计之三级联动选择器教程(中继器)
  • 大家知道输电线路微风振动在线监测有哪些先进技术?
  • docker 入门教程
  • 什么是广告联盟?
  • ABC378
  • 字段值为null就不返回的注解
  • 运动控制 编码器测速
  • JDK 安装、环境变量配置、nano 和 vim 的使用