Abstract Base Class 要求具体物具有最少 class 属性,但允许额外的
Abstract Base Class requiring concretions to have minimum class attributes but allowing for extra
我看到了一些与我的问题相关的问题,但我仍然无法想出合适的方法。
我有以下基础和子class:
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', 'two', 'one'}
{'four', 'five', 'six'}
子 class 显然在实例化过程中覆盖了基础 class' __attrs__
值。我想弄清楚的是如何让 base class' __attrs__
的值继承并 extended 由 subclass ——输出如下:
{'three', 'two', 'one','four', 'five', 'six'}
但不一定(或可能)按此顺序。第一行subclass'__init__
将parents的属性复制到实例中,达到最终结果。然而,当我计划在这里有 很多 的凝结物时,我正在努力想办法在基础 class 中以某种方式做到这一点。
您可以更改您的基础 class 以添加其自己的属性:
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 方法,您可以在基础 class 上定义,它将被调用以初始化任何子 classes。
>>> class Base:
... attrs = {'one', 'two', '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
将作为第一个参数传递,实际上需要 subclass!这是一种特殊情况,您几乎不想在常规 class 方法(或实例方法!)中执行此操作。
请注意,与往常一样,__init_subclass__
可帮助您避免实施元class。您可以使用 metaclass 执行此操作,如下所示,尽管它有点笨拙,因为您不能假设父项具有 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', 'two', 'three'}
...
>>> class Child(Base):
... attrs = {'four', 'five'}
...
>>> Child.attrs
{'two', 'four', 'three', 'five', 'one'}
>>> Base.attrs
{'two', 'one', 'three'}
再次注意super(self, self)
...
如果所有这些都太 magical/implicit 不符合你的口味,我可能会同意,你总是可以定义一个装饰器,我会选择 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', 'two', 'three'}
...
>>> @Base.update_attrs
... class Child(Base):
... attrs = {'four', 'five'}
...
>>> Child.attrs
{'two', 'four', 'three', 'five', 'one'}
>>> Base.attrs
{'two', 'one', 'three'}
我看到了一些与我的问题相关的问题,但我仍然无法想出合适的方法。
我有以下基础和子class:
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', 'two', 'one'}
{'four', 'five', 'six'}
子 class 显然在实例化过程中覆盖了基础 class' __attrs__
值。我想弄清楚的是如何让 base class' __attrs__
的值继承并 extended 由 subclass ——输出如下:
{'three', 'two', 'one','four', 'five', 'six'}
但不一定(或可能)按此顺序。第一行subclass'__init__
将parents的属性复制到实例中,达到最终结果。然而,当我计划在这里有 很多 的凝结物时,我正在努力想办法在基础 class 中以某种方式做到这一点。
您可以更改您的基础 class 以添加其自己的属性:
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 方法,您可以在基础 class 上定义,它将被调用以初始化任何子 classes。
>>> class Base:
... attrs = {'one', 'two', '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
将作为第一个参数传递,实际上需要 subclass!这是一种特殊情况,您几乎不想在常规 class 方法(或实例方法!)中执行此操作。
请注意,与往常一样,__init_subclass__
可帮助您避免实施元class。您可以使用 metaclass 执行此操作,如下所示,尽管它有点笨拙,因为您不能假设父项具有 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', 'two', 'three'}
...
>>> class Child(Base):
... attrs = {'four', 'five'}
...
>>> Child.attrs
{'two', 'four', 'three', 'five', 'one'}
>>> Base.attrs
{'two', 'one', 'three'}
再次注意super(self, self)
...
如果所有这些都太 magical/implicit 不符合你的口味,我可能会同意,你总是可以定义一个装饰器,我会选择 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', 'two', 'three'}
...
>>> @Base.update_attrs
... class Child(Base):
... attrs = {'four', 'five'}
...
>>> Child.attrs
{'two', 'four', 'three', 'five', 'one'}
>>> Base.attrs
{'two', 'one', 'three'}