为外部模块返回的对象添加行为的pythonic方法是什么?

时间:2013-08-17 12:17:29

标签: python inheritance styles multiple-inheritance

我回答这个问题的尝试借鉴了这个问题:Cast base class to derived class python (or more pythonic way of extending classes)

我正在编写一个mixin类,它将为另一个模块返回的对象添加一些功能。另一个模块中的代码如下所示:

class Foo(Mixin):
    def __new__(cls, *args, **kwargs):
        #...handle a bunch of cases

        if case1:
            return FooTypeA
        elif case2:
            return FooTypeB
        #... etc

class FooTypeA(Mixin):
    #...

class FooTypeB(Mixin):
    #...

我写了MyMixin,它为Foo返回的对象添加了一些功能。我试图解决这个问题是:

from other_module import Foo, FooTypeA, FooTypeB, ...

class MyFoo(Foo):
    def __new__(cls, *args, **kwargs):
        #...handle most of the same cases

        if case1:
            ret = FooTypeA(*args, **kwargs)
            ret.__class__ = MyFooTypeA
        if case2:
            ret = FooTypeB(*args, **kwargs)
            ret.__class__ = MyFooTypeB
        #... etc


class MyFooTypeA(FooTypeA, MyMixin):
    pass

class MyFooTypeB(FooTypeB, MyMixin):
    pass

这看起来非常非常难看。真的没有更好的解决方案吗?

如果没有,为什么?

编辑:我认为如果不进入特技会更容易,但我实际编写的代码是here。本模块的作者编写了“WebDriverMixin”,它主要提供了一些更好的语法来访问页面上的selenium webdriver实例所在的元素。我有“SiteSpecificMixin”,它提供了一些更好的语法来访问我正在测试的特定网站的元素。

webdriverplus.WebDriver返回webdriverplus.Firefoxwebdriverplus.Chromewebdriverplus.Ie等的实例,webdriverplus.Firefox继承自webdriverplus.WebDriverMixinselenium.webdriver.firefox.webdriver.Firefoxwebdriverplus.Chrome继承自webdriverplus.WebDriverMixinselenium.webdriver.firefox.webdriver.Chrome

我想为webdriverplus.Webdriver返回的对象添加功能,这似乎需要创建一个类mysite.SiteSpecificDriver,将webdriverplus.WebDriver.__new__的主体复制+粘贴到mysite.SiteSpecificDriver.__new__然后编写mysite.Firefox(需要继承自webdriverplus.Firefoxmysite.SiteSpecificMixin),mysite.Chrome(需要继承自webdriverplus.Chromemysite.SiteSpecificMixin })等,并重新处理原始作者在他自己的模块中处理的所有浏览器。

我正在使用上面的示例中的代码来处理它,并且它可以正常工作。我是OOP的新手,但我对OO技术的理解是他们应该让你避免使用if-elif -...- else条款的代码,这些代码依赖于你正在使用的对象类型,所以我认为我一定做错了。

1 个答案:

答案 0 :(得分:1)

您可以以更动态的方式重写此内容:

from other_module import Foo, FooTypeA, FooTypeB

bases = [Foo, FooTypeA, FooTypeB]

class MyMixin(object):
    pass

def factory(bases, mixins, name='MyClass'):
    return type(name, bases + mixins, {})

new_classes = [factory((c,), (MyMixin,)) for c in bases]