如何设置子类的属性归因于父类的属性归因?对于归因,我知道我可以做类似的事情
setattr(self.name, 'nickname', object)
。但是,如果我有一个类似Animal的类,它是Bird继承的,并且包含一个名为name的属性。我可以创建另一个财产吗
叫伯德班?
class Animal:
def __init__(self):
self._name = None
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
class Bird(Animal):
def __init__(self):
super().__init__()
# I need to create the other property under name attribution from Animal class as nickname
#so I can access as cat.name.nickname = 'i am nickname'
#print(cat.name.nickname) # 'i am nickname
#@property
#def nickname(self):
# return self._name
#
#@name.setter
#def name(self, value):
# self._name = value
cat = Animal()
cat.name = 'i am cat'
print(cat.name) # i am cat
答案 0 :(得分:0)
属性获取器和设置器可以使用super-调用超类上的属性方法。
这意味着您可以在子类中重新创建name
属性,为兼容性而检索超类值,并将其包装在具有所需属性的另一个类上。
但是,键_name
将在实例字典中使用,以保持值Animal.name
属性知道-因此我们需要在实例中使用另一个影子名称来保留该值,以排除子类的值。
也就是说,仍然需要构建一个聪明的类,该类可以将属性的原始值包装在超类上,并且知道如何在子类上处理属性设置和检索-Wrapper
代码如下做到这一点:
class Wrapper(str):
def __new__(cls, original_str, *args):
return super().__new__(cls, original_str)
def __init__(self, original_str, name_in_parent, parent):
self._name = name_in_parent
self._parent = parent
# original_str is taken care of in `__new__`
def __setattr__(self, attrname, value):
if attrname.startswith("_"):
return super().__setattr__(attrname, value)
ns = getattr(self._parent, self._name, None)
if ns is None:
ns = {}
setattr(self._parent, self._name, ns)
ns[attrname] = value
def __getattr__(self, attrname):
return getattr(self._parent, self._name)[attrname]
这将在超类上使用一个简单的属性,如:
class Animal:
@property
def name(self):
return self._name
@name.setter
def name(self, value):
# just so that the property is not 100% meaningless
self._name = value.lower()
class Bird(Animal):
@property
def name(self):
return Wrapper(super().name, "_bird_name", self)
@name.setter
def name(self, value):
# this turned out to be the trickiest part - to retrieve
# the original property on the superclass so that we can
# call it's setter. `super()` did not work for this.
# We set just the core value - the specialized class
# with more attributes is only used upon reading the property back
super_property = [getattr(val, "name") for val in a.__class__.__mro__[1:] if hasattr(val, "name")][0]
super_property.__set__(self, value)
这有效:
In [511]: b = Bird()
In [512]: b.name = "Woodpecker"
In [513]: b.name
Out[513]: 'woodpecker'
In [514]: b.name.nickname = "Woody"
In [515]: b.__dict__
Out[515]: {'_name': 'woodpecker', '_bird_name': {'nickname': 'Woody'}}
In [516]: b.name.nickname
Out[516]: 'Woody'
如果您想限制可接受的子属性,只需在if
中使用普通的Wrapper.__setattr__
语句即可。