玩对象创建

时间:2011-10-31 21:18:27

标签: oop python

我有两个方法foo

Foo = type('Foo', (object,), {'foo': lambda s: 'Foo method'})
Bar = type('Bar', (object,), {'foo': lambda s: 'Bar method'})

我还有一些其他类需要根据参数对上述类之一进行子类化。

我的解决方案:

class Subject(object):
    def __new__(cls, key):
        base = (Foo if key else Bar)

        name = cls.__name__ + base.__name__
        dict_ = dict(cls.__dict__.items() + base.__dict__.items())
        bases = (base, cls)

        t = type(name, bases, dict_)
        return base.__new__(t)

    def bar(self):
        return 'Subject method'

测试:

print(Subject(True).foo(), Subject(True).bar())
print(Subject(False).foo(), Subject(False).bar())

输出:

('Foo method', 'Subject method')
('Bar method', 'Subject method')

这个解决方案足够安全吗?或者我需要更多的东西才能知道?是否有更多的pythonic方式来做这种不规则的东西?

3 个答案:

答案 0 :(得分:2)

我认为大多数人会看到上面的代码,并建议使用合成而不是继承。 Subject将定义一个 foo 方法,该方法根据布尔值调度到正确的类。

或者,您可以使用工厂函数根据需要创建Foo或Bar。

def subject(selector):
     'Factory function that chooses between Foo and Bar'
     return Foo() if selector else Bar()

如果需要,使Foo和Bar都从公共类继承,以便工厂函数始终返回公共类的子类的实例。

答案 1 :(得分:1)

如果你避免元类(魔术),代码将更具可读性(因此更加pythonic)。采用Chris和Raymond建议的方法,即

使用构图:

class Subject(object):
    def __init__(self, key):
        self.foo = (Foo if key else Bar)().foo
    def bar(self):
        return 'Subject method'

或使用工厂功能:

def Subject(key):
    class Subject(Foo if key else Bar):
        def bar(self):
            return 'Subject method'
    return Subject()

答案 2 :(得分:0)

以下是您当前方法可能导致的一些意外行为的示例,即使Subject覆盖了来自FooBarFoo或{的内容将调用该方法的{1}}版本:

Bar

即使您可以通过在class Subject(object): # all of your current methods as they were above def foo(self): return 'Subject foo' >>> Subject(False).foo() 'Bar method' 之前将base.__dict__.items()放在创建cls.__dict__.items()的行上来解决这个问题,我建议完全放弃这种方法,可能使用Chris Lutz的评论或Raymond's answer

如果您有兴趣做的是采用动态方法,我建议如下。在dict_类中创建方法的私有版本,然后在Subject中指定要使用的任何方法:

Subject.__init__()