多个python类继承

DUWUDA

我试图了解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有关。

马丁·彼得斯(Martijn Pieters)

调用__init__任何一个父类都不会更改您的类的继承结构。除了C.__init__创建实例时,您还更改了运行什么初始化程序方法C从两个继承AB,并且所有方法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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章