如何以Pythonic风格创建工厂方法?附装饰器类实现场景
用工厂方法结合functools.wraps实现装饰器类,限制直接实例化
我需要实现一个装饰器类,要求用户通过工厂方法创建类实例,而非直接调用构造函数实例化。这么做的核心原因是可以借助functools.wraps来包装被装饰的可调用对象,保留其原有的元信息(如函数名、文档字符串等)。
完整实现代码
import functools import inspect class Decorator: def __init__(self, kallable): self._kallable = kallable @classmethod def make_decorator(kls, kallable): # 先实例化装饰器类 wrapped_kallable = kls(kallable) # 使用functools.wraps包装实例,保留原可调用对象的元信息 return functools.wraps(kallable)(wrapped_kallable) def __call__(self, *args, **kwargs): # 获取被装饰函数的名称 func_name = self._kallable.__name__ # 示例前置操作:打印进入函数的日志 print(f"ENTERING FUNCTION {func_name}") # 执行原函数 ret_val = self._kallable(*args, **kwargs) # 示例后置操作:打印离开函数的日志 print(f"LEAVING FUNCTION {func_name}") return ret_val
关键细节说明
工厂方法的作用:
make_decorator作为类方法,是用户创建装饰器实例的唯一入口。它先构造Decorator实例,再用functools.wraps(kallable)对实例进行包装——这一步是直接实例化做不到的,因为functools.wraps需要返回一个包装后的可调用对象,而直接实例化返回的是未处理的类实例,会丢失原函数的元信息。
装饰逻辑实现:
__call__方法是装饰器的核心执行逻辑,这里的打印操作只是示例,你可以替换为任何需要的前置/后置处理(比如参数校验、性能统计、异常捕获等)。- 注意:原代码中
inspect.currentframe().f_code.co_name会获取到__call__方法的名称,而非被装饰函数的名字,所以建议使用self._kallable.__name__来获取原函数的标识。
使用示例
# 用工厂方法作为装饰器 @Decorator.make_decorator def calculate_sum(a, b): """计算两个数的和""" return a + b # 调用装饰后的函数 result = calculate_sum(3, 5) print(f"结果:{result}") # 验证元信息是否保留 print(f"函数名:{calculate_sum.__name__}") print(f"文档字符串:{calculate_sum.__doc__}")
输出结果:
ENTERING FUNCTION calculate_sum LEAVING FUNCTION calculate_sum 结果:8 函数名:calculate_sum 文档字符串:计算两个数的和
内容的提问来源于stack exchange,提问作者Toothpick Anemone
相关产品推荐
相关产品推荐

