简体   繁体   English

如何组合python中不同父类定义的属性?

[英]How to combine properties defined by different parent classes in python?

Suppose we have two classes and each computes a property stuff in a different way.假设我们有两个类,每个类stuff以不同的方式计算属性。 Is is possible to combine their outputs in a method/property of a child class?是否可以将它们的输出组合到子类的方法/属性中?

The following code shows the desired effect (though get_stuff_from needs to be replaced by a proper python construct, if such thing exists).下面的代码显示了预期的效果(尽管get_stuff_from需要用适当的 python 结构替换,如果存在的话)。

class Foo():
    @property
    def stuff(self):
        return ['a','b','c']

class Bar():
    @property
    def stuff(self):
        return ['1','2','3']

class FooBar(Foo, Bar):
    @property
    def stuff(self):

        # Computes stuff from the internal state like Foo().stuff
        foo_stuff = get_stuff_from(Foo)

        # Computes stuff from the internal state like Bar().stuff
        bar_stuff = get_stuff_from(Bar)

        # Returns the combined results
        return foo_stuff + bar_stuff

foo_bar = FooBar()
print(foo_bar.stuff)

which should output:应该输出:

['a', 'b', 'c', '1', '2', '3']

If stuff were a method instead of a property, this would be simple to implement:如果stuff是一个方法而不是一个属性,这将很容易实现:

class Foo():
    def stuff(self):
        return ['a','b','c']

class Bar():
    def stuff(self):
        return ['1','2','3']

class FooBar(Foo, Bar):
    def stuff(self):

        # Computes stuff from the internal state like Foo().stuff
        foo_stuff = Foo.stuff(self)

        # Computes stuff from the internal state like Bar().stuff
        bar_stuff = Bar.stuff(self)

        # Returns the combined results
        return foo_stuff + bar_stuff

foo_bar = FooBar()
print(foo_bar.stuff())

however, I would like to find out whether it is possible to do the same with properties.但是,我想知道是否可以对属性做同样的事情。

A property is just an object with an fget method.属性只是一个具有fget方法的对象。 You could access the base class' property object and invoke its fget method with the self object that refers to the child class:您可以访问基类的属性对象并使用引用子类的self对象调用其fget方法:

class FooBar(Foo, Bar):
    @property
    def stuff(self):

        # Computes stuff from the internal state like Foo().stuff
        foo_stuff = Foo.stuff.fget(self)

        # Computes stuff from the internal state like Bar().stuff
        bar_stuff = Bar.stuff.fget(self)

        # Returns the combined results
        return foo_stuff + bar_stuff

And now FooBar().stuff returns ['a', 'b', 'c', '1', '2', '3']现在FooBar().stuff返回['a', 'b', 'c', '1', '2', '3']

Having two parents using the same name for two different things is a conflict you should fix before inheriting.让两个父母为两个不同的事物使用相同的名字是一种冲突,您应该在继承之前解决。 Usually, this means using at least one adaptor class.通常,这意味着至少使用一个适配器类。

class Foo():
    @property
    def stuff(self):
        return ['a','b','c']

class Bar():
    @property
    def stuff(self):
        return ['1','2','3']


class BarAdaptor:
    def __init__(self):
        self.b = Bar()

    @property
    def bar_stuff(self):
        return self.b.stuff


class FooBar(Foo, BarAdaptor):
    # Don't repeat or perpetuate the mistake of
    # overloading stuff to mean different things.
    @property
    def foobar_stuff(self):
        return self.stuff + self.bar_stuff

For symmetry, you might want to adapt Foo and Bar .为了对称,您可能需要调整FooBar

This is inspired by the advice for incorporating non-cooperative classes into a hierarchy of cooperative multiple inheritance classes, outlined in Python's `super() considered super!这是受到将非合作类合并到合作多继承类层次结构中的建议的启发,在Python 的 `super() considered super! . .

You could do it like this, otherwise I don't know why you're deriving from Foo and Bar.你可以这样做,否则我不知道你为什么要从 Foo 和 Bar 派生。 In your current code you were just overwriting these properties.在您当前的代码中,您只是覆盖了这些属性。

class Foo():
    @property
    def stuff(self):
        return self._foo_stuff
    @property
    def _foo_stuff(self):
        return ['a','b','c']
class Bar():
    @property
    def stuff(self):
        return self._bar_stuff
    @property
    def _bar_stuff(self):
        return ['1','2','3']
class FooBar(Foo, Bar):
    @property
    def stuff(self):
        return self._foo_bar_stuff
    @property
    def _foo_bar_stuff(self):
        return self._foo_stuff + self._bar_stuff
foo_bar = FooBar()
print(foo_bar.stuff)

Output:输出:

['a', 'b', 'c', '1', '2', '3']

You can do this using the code below您可以使用以下代码执行此操作

class FooBar(Foo, Bar):
    def __init__(self):
        self.foo = Foo()
        self.bar = Bar()

    @property
    def stuff(self):
        return self.foo.stuff + self.bar.stuff

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM