Calling __init__
任何一个父类都不会改变类的继承结构,不会。除了更改之外,您仅更改运行的初始化程序方法C.__init__
当创建实例时。C
继承自两者A
and B
,以及所有方法B
被那些在A
由于继承顺序。
如果您需要根据构造函数中的值更改类继承,请创建两个单独的班级,具有不同的结构。然后提供不同的可调用对象作为 API 来创建实例:
class CA(A):
# just inherit __init__, no need to override
class CB(B):
# just inherit __init__, no need to override
def C(path):
# create an instance of a class based on the value of path
class_map = {'A': CA, 'B': CB}
return class_map[path](path)
您的 API 的用户仍然有名字C()
打电话;C('A')
生成一个不同类的实例C('B')
,但它们都实现相同的接口,因此这对调用者来说并不重要。
If you have有一个通用的“C”类可以使用isinstance()
or issubclass()
测试,你可以混合其中之一,然后使用__new__ method https://docs.python.org/3/reference/datamodel.html#object.__new__覆盖返回的子类:
class C:
def __new__(cls, path):
if cls is not C:
# for inherited classes, not C itself
return super().__new__(cls)
class_map = {'A': CA, 'B': CB}
cls = class_map[path]
# this is a subclass of C, so __init__ will be called on it
return cls.__new__(cls, path)
class CA(C, A):
# just inherit __init__, no need to override
pass
class CB(C, B):
# just inherit __init__, no need to override
pass
__new__
被调用来构造新的实例对象;如果__new__
方法返回该类(或其子类)的实例,然后__init__
将自动在该新实例对象上调用。这就是为什么C.__new__()
返回结果CA.__new__()
or CB.__new__()
; __init__
我们将会为您打电话。
后者的演示:
>>> C('A').something()
Function A
>>> C('B').something()
B function with something
>>> isinstance(C('A'), C)
True
>>> isinstance(C('B'), C)
True
>>> isinstance(C('A'), A)
True
>>> isinstance(C('A'), B)
False
如果这些选项都不适合您的特定用例,则必须在新的中添加更多路由somemethod()
实施于C
,然后调用A.something(self)
or B.something(self)
基于self.path
。当你必须这样做时,这很快就会变得很麻烦每一个方法,但是装饰器可以提供帮助:
from functools import wraps
def pathrouted(f):
@wraps
def wrapped(self, *args, **kwargs):
# call the wrapped version first, ignore return value, in case this
# sets self.path or has other side effects
f(self, *args, **kwargs)
# then pick the class from the MRO as named by path, and call the
# original version
cls = next(c for c in type(self).__mro__ if c.__name__ == self.path)
return getattr(cls, f.__name__)(self, *args, **kwargs)
return wrapped
然后在类的空方法上使用它:
class C(A, B):
@pathrouted
def __init__(self, path):
self.path = path
# either A.__init__ or B.__init__ will be called next
@pathrouted
def something(self):
pass # doesn't matter, A.something or B.something is called too
然而,这变得非常不Python且丑陋。