微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

抽象基类要求凝结物具有最少的类属性但允许额外的

如何解决抽象基类要求凝结物具有最少的类属性但允许额外的

我已经看到一些与我的问题相关的问题,但我仍然无法想出合适的方法

我有以下基类和子类:

class Base:
    __attrs__ = {'one','two','three'}

    def __init__(self,nums: {str} = None):
        if nums:
            self.__attrs__.update(nums)
        self.nums = self.__attrs__


class Child(Base):
    __attrs__ = {'four','five','six'}

    def __init__(self,nums: {str} = None):
        # self.__attrs__.update(super().__attrs__.copy())  <-----this works when uncommented
        super(Child,self).__init__(nums)


b = Base()
print(b.nums)

c = Child()
print(c.nums)

# The output,as expected.
{'three','one'}
{'four','six'}

子类显然在实例化过程中覆盖了基类的 __attrs__ 值。我想弄清楚的是如何让子类继承和扩展的基类'__attrs__中的值——这样输出将如下所示: >

{'three','one','four','six'}

但不一定(或可能)按此顺序。子类'__init__ 的第一行将父类属性复制到实例并实现最终结果。然而,当我计划在这里拥有很多的具体化时,我正试图以某种方式在基类中以某种方式做到这一点。

解决方法

您可以更改基类以添加其自己的属性:

class Base:
    __attrs__ = {'one','two','three'}

    def __init__(self,nums: {str} = None):
        self.__attrs__.update(Base.__attrs__)  # <-- add this.
        if nums:
            self.__attrs__.update(nums)
        self.nums = self.__attrs__
,

这是 __init_subclass__ 的工作,它是一个类方法,您可以在基类上定义该基类,该基类将被调用以初始化任何子类。

>>> class Base:
...     attrs = {'one','three'}
...     def __init_subclass__(cls): # cls will be a subclass!
...         cls.attrs.update(super(cls,cls).attrs)
...
>>> class Child(Base):
...     attrs = {'four','five'}
...
>>> Child.attrs
{'two','four','three','five','one'}
>>> Base.attrs
{'two','one','three'}

注意,在这种情况下,我们将 cls 作为两个参数显式传递给 super。否则,如果您使用零参数形式,Foo 将作为第一个参数传递,并且实际上需要子类!这是一种特殊情况,您几乎永远不想在常规类方法(或实例方法!)中执行此操作。

请注意,像往常一样,__init_subclass__ 可以帮助您避免必须实现元类。您可以按如下方式使用元类执行此操作,尽管它有点笨拙,因为您不能假设父类具有 attrs。

>>> class AttrsMeta(type):
...     def __init__(self,*args,**kwargs):
...         try:
...             parent_attrs = super(self,self).attrs
...         except AttributeError: # parent no attrs,base class?
...             return # handle however you like
...         self.attrs.update(parent_attrs) # assume the class always has an attrs defined
...
>>> class Base(metaclass=AttrsMeta):
...     attrs = {'one','three'}
...
>>> class Child(Base):
...     attrs = {'four','three'}

再次注意super(self,self)...

如果所有这些对您的口味来说有点过于神奇/隐含,而且我可能倾向于同意,您总是可以定义一个装饰器,我会使用类似这样的 API:

>>> def attrs(cls):
...     def update_attrs(subclass):
...         subclass.attrs.update(super(subclass,subclass).attrs)
...         return subclass
...     cls.update_attrs = update_attrs
...     return cls
...
>>> @attrs
... class Base:
...     attrs = {'one','three'}
...
>>> @Base.update_attrs
... class Child(Base):
...     attrs = {'four','three'}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。