gpt4 book ai didi

python - 如何在python中为父类的属性创建属性

转载 作者:太空宇宙 更新时间:2023-11-03 20:52:14 27 4
gpt4 key购买 nike

如何将子类的属性属性设置为父类的属性属性?对于归因,我知道我可以做类似的事情setattr(self.name, '昵称', object)。但是,如果我有一个像 Animal 这样的类,它由 Bird 继承,并且包含一个名为 name 的属性。我可以创建另一个属性(property)吗在 Bird 类的名称下?

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

最佳答案

属性 getter 和 setter 可以调用父类(super class)上的属性方法,使用 super -

这意味着您可以在子类中重新创建 name 属性,检索父类(super class)值以实现兼容性,并将其包装在另一个具有您想要的属性的类上。

但是,键 _name 将在实例字典中获取,以保持 Animal.name 属性知道值 - 因此我们需要实例中的另一个影子名称来保留子类排除的值。

也就是说,仍然需要构建一个聪明的类,它可以包装父类(super class)上属性的原始值,并知道如何处理子类上的属性设置和检索 - 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]

这将与父类(super class)上的一个简单属性一起使用,例如:

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'

如果您想限制接受的子属性,只需在 Wrapper.__setattr__ 中使用简单的 if 语句即可。

关于python - 如何在python中为父类的属性创建属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56244459/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com