动态选择从哪个子类继承方法?

时间:2016-02-04 22:16:20

标签: python inheritance subclass dynamic-programming subclassing

假设我有不同的类,提供对不同子系统的访问,但具有通用接口。它们都提供相同的方法集,但每个类以不同的方式实现它们(想想使用foo.write()写入文件或通过套接字发送数据等)

由于接口是相同的,我想创建一个能够选择正确类但只基于构造函数/初始化器参数的类。

在代码上,它看起来像

class Foo(object):
    def who_am_i(self):
        print "Foo"

class Bar(object):
    def who_am_i(self):
        print "Bar"

# Class that decides which one to use and adds some methods that are common to both
class SomeClass(Foo, Bar):
    def __init__(self, use_foo):
        # How inherit methods from Foo -OR- Bar?

SomeClass如何从[{1}} Foo继承Bar和/或__init__参数?< / p>

目标应该是

__new__

是否有一些干净的&#34; pythonic&#34;实现这个的方法?我并不想使用函数动态定义>>> some_object = SomeClass(use_foo=True) >>> some_object.who_am_i() Foo >>> another_object = SomeClass(use_foo=False) >>> another_object.who_am_i() Bar ,但我没有找到另一种方法来执行此操作。

谢谢!

5 个答案:

答案 0 :(得分:3)

如评论中所述,这可以通过工厂函数(假装为类的函数)来完成:

def SomeClass(use_foo):
    if use_foo:
        return Foo()
    else:
        return Bar()

答案 1 :(得分:1)

这里可以使用班级工厂。请注意使用字典来确保相同的子类实例用于每个基类。

def makeclass(baseclass, classes={}):
    if baseclass not in classes:
        class Class(baseclass):
            pass   # define your methods here
        classes[baseclass] = Class
    return classes[baseclass]

obj1 = makeclass(Foo)(...)
obj2 = makeclass(Bar)(...)

isinstance(obj1, makeclass(Foo)) # True
isinstance(obj1, Foo)            # True
issubclass(makeclass(Foo), Foo)  # True
issubclass(type(obj1), Foo)      # True

您还可以使用dict方法创建__missing__子类,以完成相同的操作;它让你更明确地知道你有一个存储类的容器,但是按需创建它们:

class ClassDict(dict):
     def __missing__(self, baseclass):
         class Class(baseclass):
             pass   # define your methods here
         self[baseclass] = Class
         return Class

subclasses = ClassDict()
obj1 = subclasses[Foo]
obj2 = subclasses[Bar]

答案 2 :(得分:1)

据我所知,你的继承完全倒退;而不是你提出的多重继承:

Foo              Bar
- foo code       - bar code

     \          /

      SomeClass(Foo, Bar)
      - common code

您可以使用更简单的单继承模型:

      SomeClass
      - common code

     /          \

Foo(SomeClass)   Bar(SomeClass)
- foo code       - bar code

这使您的问题成为选择实例化哪个子类(只需要进行一次的决策)而不是调用哪个超类方法(可能需要在每个方法调用上进行)。这可以通过以下方式解决:

thing = Foo() if use_foo else Bar()

答案 3 :(得分:0)

由于对答案缺乏一致意见,可能问题就在于问题。 jonrsharpe's comment对此问题提供了一个有趣的见解:这应该通过继承来解决

考虑SomeClass定义如下:

# Class that uses Foo or Bar depending on the environment
# Notice it doesn't subclasses either Foo or Bar
class SomeClass(object):
    def __init__(self, use_foo):
        if use_foo:
            self.handler = Foo() 
        else:
            self.handler = Bar() 

    # Makes more sense asking 'Who implements?' instead of 'Who am I?'
    def who_implements(self):
        return self.handler

    # Explicitly expose methods from the handler
    def some_handler_method(self, *args, **kwargs):
        return self.handler.some_handler_method(*args, **kwargs)

    def another_handler_method(self, *args, **kwargs):
        return self.handler.another_handler_method(*args, **kwargs)

我们是否需要获取有关处理程序实现的详细信息,只需获取handler属性即可。子类SomeClass的其他类甚至不会直接看到处理程序,这实际上是有意义的。

答案 4 :(得分:-1)

可以使用__new__方法实现此目的:

_foos = {}
_bars = {}
class SomeClass(object):
     def __new__(cls,use_foo,*args,**kwargs):
         if use_foo:
            if cls not in _foos:
                class specialized(cls,Foo):pass
                _foos[cls] = specialized
           else:
               specialized = _foos[cls]
         else:
            if cls not in _bars:
                class specialized(cls,Bar):pass
                _bars[cls] = specialized
           else:
               specialized = _bars[cls]
         specialized.__name__ = cls.__name__
         return object.__new__(specialized,*args,**kwargs)
     #common methods to both go here
     pass

这比工厂函数的优点是isinstance(SomeClass(True),SomeClass)有效,SomeClass可以被子类化。