/ PYTHON

python装饰器及魔法函数

一. 装饰器

python的装饰器其实就是在某个函数外面再嵌套一个函数,用以达到增强该函数功能的效果。其实就是套娃

特点:

  • 装饰器输入参数:函数
  • 装饰器输出:函数
  • 装饰器能使代码使用上更加简洁

比如下面的例子:

def wrapper(f):
    def a(*args, **kwargs):
        print(*args, **kwargs)
        f(*args, **kwargs)
    return a

# 1. 未使用装饰器情况下
def call(name):
    print(f'name:{name}')

wrapper(call('张三'))

# 2. 使用装饰器
@wrapper
def call(name):
    print(f'name:{name}')

call('张三')

1.1 classmethod装饰器

一般来说,使用一个类的方法,必须先实例化该类,再调用方法。但是@staticmethod则可以直接使用类名.方法()。

特点:

  1. 方法内部参数不能有self。
  2. 类的其他方法调用本方法需要加入self.方法()
  3. 在方法内部调用类其他属性为 类名.属性,调用方法则需要先实例化。
class A:
    c = 'c'
    
    @staticmethod
    def a(a = 1):
        print(a)
        print(A.c)
        A().cc() # 需要实例化

    def b(self):
        self.a() # 正常调用

    def cc(self):
        print(self.c)

A.a() # 不用实例,即可外部调用

1.2 classmethod装饰器

和staticmethod一样,可以不需要实例,直接直接使用类名.方法()。

特点:

  1. classmethod没有类实例化对象的self参数,而是指代类本身的cls参数。
  2. 类的其他方法调用本方法需要加入self.方法()
  3. 在方法内部调用类其他属性为 cls.属性,调用方法则需要先实例化 cls.方法()。
class A:
    c = 'c'

    @classmethod
    def a(cls,a = 1):
        print(a)
        print(cls.c)
        cls().cc() # 需要实例化

    def b(self):
        self.a() # 正常调用

    def cc(self):
        print(self.c)

A.a()

1.3 property 装饰器

作用: 修饰方法,将方法当作类的只读属性一样访问,能防止属性被修改。

class A:
    aaa = 1

    @property
    def a(self): 
        return self.aaa
    
    def b(self): 
        return self.aaa

a = A()
print(a.a) 
print(a.b())

二. 魔法函数

2.1 __new__函数

场景:一般需要使用单例模式下(比如数据库连接等),需要确保只有单个对象被创建情况下,都需要用到new函数

class A:
    _instance = None

    def __new__(cls, *args, **kwargs):
        print('__new__')
        # 单例模式下,先判断是否存在实例,没有则创建
        if cls._instance is None:
            cls._instance = object.__new__(cls)
        return cls._instance

    def __init__(self):
        print('__init__')


# 仅允许一个实例被创建,就算创建其他实例,本质指向的还是同一个实例
a = A()
b = A() # a ==> b

# 打印结果:先是 __new__ 后是__init__。说明new是在实例创建之前,而init则是在实例创建之后

2.2 __call__函数

场景:将一个类当作一个函数进行使用,在流水线式的数据处理时可以更好的进行封装。

class A:
    def __call__(self, *args, **kwargs):
        return self.compute(*args, **kwargs)

    def a1(self,a,b):
        return a + b

    def a2(self,a,b):
        return a * b
    
    def compute(self,a,b,c):
        return self.a1(a,c) + self.a2(a,b)

a = A()
rs = a(1,2,3) # 首先需要实例化,之后可以直接像函数一样使用

2.3 属性操作__add__

场景: 需要对2个实例进行运算操作时

class A:
    def __init__(self, a) :
        self.a = a
    def __add__(self, other_a):
        return self.a + other_a.a

a1 = A(1)
a2 = A(2)
aa = a1 + a2