Python: 抽象层级 类 没有抽象方法
Python: hierarchy of abstract classes without abstract methods
那么,问题来了:
我想定义一个抽象class,比方说AbstractA
,它不需要子classes来实现它的任何方法,而是以扩展其功能。根据 Java 接口 class.
此外,我希望能够创建具有相同属性的 AbstractA
的抽象子 class,比方说 AbstractB
,但有些方法重新定义或扩展基础 class 方法。
我不想将 class (AbstractA
) 抽象化,例如through the check of class name in __init__
or __new__
,因为这需要抽象子class (AbstractB
) 来重新定义该方法及其主要功能,即新实例的构造或初始化。或者调用 super().__init__(...)
,我也希望避免这种情况(也许我在这里错了)。
所以,我想要这样的东西:
class AbstractA:
def __init__(self):
# do initialization stuff
def very_common_method(self, ...):
# do very common stuff
class AbstractB(AbstractA):
# do not duplicate initialization stuff here, inherit instead
def less_common_method(self, ...):
# do less common stuff
class AX(AbstractA):
def specific_method_1(self, ...):
class BX(AbstractB):
def specific_method_2(self, ...):
# Instantiating AbstractA or AbstractB should result in error.
# Instantiating AX or BX should not.
下面我有一个可能的解决方案。
有什么我忽略的缺点吗?更好的解决方案?
谢谢!
可能的解决方案如下:
class AbstractA:
_is_abstract = True
def __init__(self):
if self._is_abstract:
raise RuntimeError("Abstract class instantiation.")
# do initialization stuff
def __init_subclass__(self): # is called every time class is subclassed
self._is_abstract = False # thus makes sure abstract check fails on a subclass
class AbstractMixin:
def __init_subclass__(self):
self._is_abstract = True
class AbstractB(AbstractMixin, AbstractA): # AbstractMixin takes precendence on MRO,
# inherit __init__ # so the class abstract check returns True.
def __init_subclass__(self):
self._is_abstract = False
class A(AbstractA):
pass
class B(AbstractB):
pass
AbstractA()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.
AbstractB()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.
A()
<__main__.A object at 0x7f0bba5112e8>
B()
<__main__.B object at 0x7f0bba511438>
class A(object):
def __init__(self):
if self.__class__ == A:
raise RuntimeError("Abstract class instantiation.")
print(self.__class__.__name__)
class B(A):
pass
>>> A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.
>>> B()
B
<__main__.B object at 0x7f8c816a58d0>
>>>
在 Python 中,您可能会将 "abstract" 基础 class 实现为混入。您不需要做任何特别的事情;按照惯例,您会在名称中添加 Mixin
以表明它不打算直接实例化,而只是用作其他 class 的基础 class。
class AMixin:
def __init__(self):
# do initialization stuff
def very_common_method(self, ...):
# do very common stuff
class BMixin(AMixin):
# do not duplicate initialization stuff here, inherit instead
def less_common_method(self, ...):
# do less common stuff
class AX(AMixin):
def specific_method_1(self, ...):
class BX(BMixin):
def specific_method_2(self, ...):
class Foo:
...
class Bar(Foo, BMixin):
...
那么,问题来了:
我想定义一个抽象class,比方说
AbstractA
,它不需要子classes来实现它的任何方法,而是以扩展其功能。根据 Java 接口 class.此外,我希望能够创建具有相同属性的
AbstractA
的抽象子 class,比方说AbstractB
,但有些方法重新定义或扩展基础 class 方法。
我不想将 class (AbstractA
) 抽象化,例如through the check of class name in __init__
or __new__
,因为这需要抽象子class (AbstractB
) 来重新定义该方法及其主要功能,即新实例的构造或初始化。或者调用 super().__init__(...)
,我也希望避免这种情况(也许我在这里错了)。
所以,我想要这样的东西:
class AbstractA:
def __init__(self):
# do initialization stuff
def very_common_method(self, ...):
# do very common stuff
class AbstractB(AbstractA):
# do not duplicate initialization stuff here, inherit instead
def less_common_method(self, ...):
# do less common stuff
class AX(AbstractA):
def specific_method_1(self, ...):
class BX(AbstractB):
def specific_method_2(self, ...):
# Instantiating AbstractA or AbstractB should result in error.
# Instantiating AX or BX should not.
下面我有一个可能的解决方案。 有什么我忽略的缺点吗?更好的解决方案?
谢谢!
可能的解决方案如下:
class AbstractA:
_is_abstract = True
def __init__(self):
if self._is_abstract:
raise RuntimeError("Abstract class instantiation.")
# do initialization stuff
def __init_subclass__(self): # is called every time class is subclassed
self._is_abstract = False # thus makes sure abstract check fails on a subclass
class AbstractMixin:
def __init_subclass__(self):
self._is_abstract = True
class AbstractB(AbstractMixin, AbstractA): # AbstractMixin takes precendence on MRO,
# inherit __init__ # so the class abstract check returns True.
def __init_subclass__(self):
self._is_abstract = False
class A(AbstractA):
pass
class B(AbstractB):
pass
AbstractA()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.
AbstractB()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.
A()
<__main__.A object at 0x7f0bba5112e8>
B()
<__main__.B object at 0x7f0bba511438>
class A(object):
def __init__(self):
if self.__class__ == A:
raise RuntimeError("Abstract class instantiation.")
print(self.__class__.__name__)
class B(A):
pass
>>> A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.
>>> B()
B
<__main__.B object at 0x7f8c816a58d0>
>>>
在 Python 中,您可能会将 "abstract" 基础 class 实现为混入。您不需要做任何特别的事情;按照惯例,您会在名称中添加 Mixin
以表明它不打算直接实例化,而只是用作其他 class 的基础 class。
class AMixin:
def __init__(self):
# do initialization stuff
def very_common_method(self, ...):
# do very common stuff
class BMixin(AMixin):
# do not duplicate initialization stuff here, inherit instead
def less_common_method(self, ...):
# do less common stuff
class AX(AMixin):
def specific_method_1(self, ...):
class BX(BMixin):
def specific_method_2(self, ...):
class Foo:
...
class Bar(Foo, BMixin):
...