我试图了解python的类继承方法,并且在弄清楚如何执行以下操作时遇到了一些麻烦:
如何从以孩子的输入为条件的类继承方法?
我在下面尝试了以下代码,但没有成功。
class A(object):
def __init__(self, path):
self.path = path
def something(self):
print("Function %s" % self.path)
class B(object):
def __init__(self, path):
self.path = path
self.c = 'something'
def something(self):
print('%s function with %s' % (self.path, self.c))
class C(A, B):
def __init__(self, path):
# super(C, self).__init__(path)
if path=='A':
A.__init__(self, path)
if path=='B':
B.__init__(self, path)
print('class: %s' % self.path)
if __name__ == '__main__':
C('A')
out = C('B')
out.something()
我得到以下输出:
class: A
class: B
Function B
虽然我希望看到:
class: A
class: B
B function with something
我猜为什么A.something()
使用(而不是B.something()
)的原因与python的MRO有关。
调用__init__
任何一个父类都不会更改您的类的继承结构。除了C.__init__
创建实例时,您还更改了运行什么初始化程序方法。C
从两个继承A
和B
,并且所有方法B
都受到那些阴影A
由于继承的顺序。
如果需要基于构造函数中的值更改类继承,请创建两个具有不同结构的单独的类。然后提供另一个可调用的API作为创建实例的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')
,但是它们都实现了相同的接口,因此对调用者而言无关紧要。
如果必须在isinstance()
或issubclass()
测试中使用通用的“ C”类,则可以混合使用一个“ C”类,并使用该__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)
或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
但是,这变得异常棘手和丑陋。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句