能否无需显式指定父类名,将父类方法用作子类方法装饰器?
解决方案:隐式引用父类的
delayed_init装饰器 你可以通过几种方式避免硬编码父类名称Manager,实现对父类装饰器的隐式引用,以下是几种可行方案:
方案1:使用类级别的super()引用
在子类定义阶段,通过super(子类名, 子类名)直接获取父类的装饰器,无需硬编码父类名称:
import numpy as np class Manager: def __init__(self, value, delay_init=True): self.value = value self.is_init = False self.data = None if not delay_init: self._initialize() @staticmethod def delayed_init(fn): def wrapped_delayed_init(obj, *args, **kwargs): if not obj.is_init: obj.data = np.random.randn(obj.value, obj.value) obj.is_init = True return fn(obj, *args, **kwargs) return wrapped_delayed_init @delayed_init.__get__(object) def _initialize(self): pass class DataManager(Manager): def __init__(self, value): super().__init__(value) # 使用类级别的super获取父类的delayed_init装饰器 @super(DataManager, DataManager).delayed_init def calculate_mean(self): return np.mean(self.data) data_manager = DataManager(100) assert data_manager.data is None mean = data_manager.calculate_mean()
super(DataManager, DataManager)会返回父类Manager的类上下文,从而直接访问其静态方法delayed_init。
方案2:在子类中定义代理装饰器
在子类内部定义一个代理装饰器,通过super()隐式调用父类的装饰器,后续子类方法只需使用这个代理装饰器即可:
import numpy as np class Manager: # 保持原有代码不变 def __init__(self, value, delay_init=True): self.value = value self.is_init = False self.data = None if not delay_init: self._initialize() @staticmethod def delayed_init(fn): def wrapped_delayed_init(obj, *args, **kwargs): if not obj.is_init: obj.data = np.random.randn(obj.value, obj.value) obj.is_init = True return fn(obj, *args, **kwargs) return wrapped_delayed_init @delayed_init.__get__(object) def _initialize(self): pass class DataManager(Manager): def __init__(self, value): super().__init__(value) # 定义代理装饰器,隐式调用父类的delayed_init @classmethod def delayed_init(cls, fn): return super().delayed_init(fn) # 使用子类的代理装饰器 @delayed_init def calculate_mean(self): return np.mean(self.data) data_manager = DataManager(100) assert data_manager.data is None mean = data_manager.calculate_mean()
该方案让子类方法的装饰器写法更简洁,且完全与父类名称解耦。
方案3:使用元类自动装饰标记方法
如果有多个需要延迟初始化的方法,可以通过元类自动识别标记的方法,自动应用父类的delayed_init装饰器:
import numpy as np # 定义标记装饰器,用来标记需要延迟初始化的方法 def needs_delayed_init(fn): fn._needs_delayed_init = True return fn # 定义元类,自动装饰标记的方法 class ManagerMeta(type): def __new__(cls, name, bases, attrs): # 遍历类属性,找到标记的方法并应用父类的delayed_init for attr_name, attr in attrs.items(): if callable(attr) and hasattr(attr, '_needs_delayed_init'): attrs[attr_name] = bases[0].delayed_init(attr) return super().__new__(cls, name, bases, attrs) class Manager(metaclass=ManagerMeta): def __init__(self, value, delay_init=True): self.value = value self.is_init = False self.data = None if not delay_init: self._initialize() @staticmethod def delayed_init(fn): def wrapped_delayed_init(obj, *args, **kwargs): if not obj.is_init: obj.data = np.random.randn(obj.value, obj.value) obj.is_init = True return fn(obj, *args, **kwargs) return wrapped_delayed_init @delayed_init.__get__(object) def _initialize(self): pass class DataManager(Manager): def __init__(self, value): super().__init__(value) # 只需添加标记装饰器,元类会自动应用父类的delayed_init @needs_delayed_init def calculate_mean(self): return np.mean(self.data) data_manager = DataManager(100) assert data_manager.data is None mean = data_manager.calculate_mean()
该方案无需手动引用任何父类装饰器,只需给目标方法添加标记即可完成自动装饰。
内容的提问来源于stack exchange,提问作者dyprious
相关产品推荐
相关产品推荐

