用 python 类中的属性覆盖属性

lib*_*lib 7 python inheritance properties

我有一堂课,比如:

class Parent(object):
    def __init__(self, a1 = None, a2 = None):
        someInitialization()
        self.a1 = a1
        self.a2 = a2

    def coolMethod(self): 
        return dosomething(self.a2)
Run Code Online (Sandbox Code Playgroud)

这么说吧

  • 我不想修改父类的属性
  • 我不想在初始化时提供 a1 和 a2 因为它们的计算成本很高(并且父级的每个方法都不需要它们)
  • 我不想记住 Parent 的哪个方法需要 a1 或 a2,它们应该可以工作

编辑我的实际约束并不是那么严格,但我问这个问题也是为了更好地理解类属性、方法等。

我正在使用最简单的解决方案,无需初始化继承:

class Child(Parent):
    _propertiesCache = {'a1':None,'a2':None}
    def _initProperty(self, propertyName):
        value = self._propertiesCache[propertyName]
        if value is None:
            self._propertiesCache[propertyName]=expensiveFunction(self.b, propertyName)
        return  self._propertiesCache[propertyName]

    @property
    def a1(self):
        return self._initProperty('a1')

    @property
    def a2(self):
        return self._initProperty('a2')

    def __init__(self,b):
        self.b = b
        someInitialization()
Run Code Online (Sandbox Code Playgroud)

有没有办法正确调用父类的初始化?如果我使用super(Child,self).__init__()我得到AttributeError: can't set attribute。我试图覆盖__new__但我总是错过一些东西

class Child(Parent):
    _propertiesCache = {'a1':None,'a2':None}
    @classmethod
    def _initProperty(cls, propertyName):
        value = cls._propertiesCache[propertyName]
        if value is None:
            cls._propertiesCache[propertyName] = someTimeConsumingFunctionThatIDontWantToCallAtInitialization(propertyName)
        return  cls._propertiesCache[propertyName]

    @property
    def a1(self):
        return self._initProperty('a1')

    @property
    def a2(self):
        return self._initProperty('a2')

    def __new__(cls):
        super(Child,cls).__new__(cls)
        return cls
    def __init__(self,b):
        self.b = b
        super(Child,self).__init__(a1=self.a1, a2=self.a2)
Run Code Online (Sandbox Code Playgroud)

给我:

>>c = Child();c.a1
<property at 0x3aa4228>
>>c.a1.fget(c)
"ValueOfa1"
Run Code Online (Sandbox Code Playgroud)

Tad*_*sen 4

不要调用您的方法,而是_initProperty调用它,__getattr__以便每次在应存储的正常位置(属性字典、类字典等)中找不到该属性时都会调用该方法,然后在第一次尝试访问该属性时调用该方法被初始化。

确保不要在 Parent 初始化中设置它们,也许只有在它们不是 None 时才设置它们:

class Parent:
     def __init__(self,a1=None,a2=None):
         if a1 is not None:
             self.a1 = a1
         if a2 is not None:
             self.a2 = a2
Run Code Online (Sandbox Code Playgroud)

为了与错误保持一致,AttributeError如果属性不存在,您将需要引发,而不是让其KeyError通过,并且可能添加对常规属性字典中的值的引用,以便不需要运行__getattr__每次:

_propertiesCache = {'a1':None,'a2':None}
def __getattr__(self, propertyName):
    if propertyName not in self._propertiesCache:
        raise AttributeError(propertyName)
    value = self._propertiesCache[propertyName]
    if value is None:
        value = self._propertiesCache[propertyName]=expensiveFunction(self.b, propertyName)
    setattr(self,propertyName,value)
    return  value
Run Code Online (Sandbox Code Playgroud)

无论以何种方式实现这一点,您都需要确保:

该属性直到第一次使用时才设置(此时__getattr__使用)