轻松创建函数和方法装饰器,采用面向对象风格。
项目描述
Classy Decorators
轻松创建函数和方法装饰器,采用面向对象风格。
特性
- 一个装饰器统治所有;它适用于函数、方法、类方法和静态方法。
- 使用类似于dataclass的注释属性语法轻松定义参数。
- 装饰器参数的运行时类型检查。
- 对于具有所有默认值或无参数的装饰器,括号是可选的:
@spam() == @spam
- 支持继承。
- 任何装饰器参数和实例属性在绑定方法中也是可访问的(作为副本);无需担心那些讨厌的描述符。
- 与MyPy兼容且100%覆盖率。
依赖关系
Python 3.8或3.9。
安装
pip install classy-decorators
以获得更好的运行时类型检查
pip install classy-decorators[typeguard]
用法
以下代码也可以在示例中找到。
通过从classy_decorators.Decorator
派生来创建装饰器。您可以使用__call_inner__
方法(__call__
仅用于内部使用,不应用于此)重写被装饰的函数或方法。
简单装饰器
from classy_decorators import Decorator
class Double(Decorator):
def __call_inner__(self, *args, **kwargs) -> float:
return super().__call_inner__(*args, **kwargs) * 2
让我们通过装饰一个函数来查看它的实际效果
@Double
def add(a, b):
return a + b
assert add(7, 14) == 42
您也可以装饰方法和类方法
class AddConstant:
default_constant = 319
def __init__(self, constant=default_constant):
self.constant = constant
@Double
def add_to(self, value):
return value + self.constant
@Double
@classmethod
def add_default(cls, value):
return value + cls.default_constant
assert AddConstant(7).add_to(14) == 42
assert AddConstant.add_default(14) == 666
装饰器参数
我们的Double
装饰器相当不错,但我们能做得更好!因此,让我们创建一个装饰器,它能够将结果乘以任何数字,而不仅仅是2
。
class Multiply(Decorator):
factor: int
def __call_inner__(self, *args, **kwargs) -> float:
return super().__call_inner__(*args, **kwargs) * self.factor
只需简单地设置类型注解的 factor
属性,我们就可以将其用作装饰器参数。如果你熟悉 dataclasses,你会发现这非常类似于定义数据类字段。
@Multiply(2)
def add_and_double(a, b):
return a + b
@Multiply(factor=3)
def add_and_triple(a, b):
return a + b
assert add_and_double(8, 15) == 46
assert add_and_triple(8, 15) == 69
默认参数和继承
DRY(不要重复自己)是一种优雅的做法,所以让我们将 Double
和 Multiply
装饰器合并成一个默认乘以 2
,除非有其他指定。
class DoubleOrMultiply(Multiply):
factor = 2
@DoubleOrMultiply
def add_and_double(a, b):
return a + b
@DoubleOrMultiply(factor=3)
def add_and_triple(a, b):
return a + b
assert add_and_double(7, 14) == 42
assert add_and_triple(8, 15) == 69
高级数据类方法
提供的 Decorator
基类除了 __call_inner__
之外,还有两个可以覆盖的接口方法
Decorator.__decorate__(self, **params)
,在函数方法被装饰后立即调用,所有装饰器参数值或默认值作为关键字参数,即DoubleOrMultiply.__decorate__(self, factor: int = 2)
。Decorator.__bind__(self, instance_or_class)
,当方法(不是函数)绑定到实例时调用,或者当类/静态方法绑定到类时调用。
此外,这些属性可用于确定已装饰的内容
is_function
is_method
;实例、类或静态方法is_instancemethod
is_classmethod
is_staticmethod
对于方法,还提供了 is_bound
和 is_unbound
。
如果你要找原始包装函数,你可以在 __func__
中找到它。
真是有品味啊?