如何使__init__获取新值或现有实例?

时间:2013-06-27 16:38:49

标签: python

我有一个类似于以下内容的模式:

class Foobar(object):  # instances of this class will be referenced by others
    def __init__(self, value):
        self.value = value

class Foo(object):
    def __init__(self, value, foobar)
        self.value = value
        if isinstance(foobar, Foobar):
            self.foobar = foobar
        else:
            self.foobar = Foobar(foobar)

class Bar(object):
    def __init__(self, value, foobar)
        self.value = value
        if isinstance(foobar, Foobar):
            self.foobar = foobar
        else:
            self.foobar = Foobar(foobar)

这允许FooBar将新值(创建Foobar)或现有Foobar实例作为foobar参数


我想摆脱这个多余的代码:

# ...
        if isinstance(foobar, Foobar):
            self.foobar = foobar
        else:
            self.foobar = Foobar(foobar)

我考虑了以下内容,但由于Foobar.__new__()中的无限递归而无效:

class Foobar(object):
    def __new__(cls, value):
        if isinstance(value, cls):
           return value
        else:
           return Foobar(value)
    def __init__(self, value):
        self.value = value

class Foo(object):
    def __init__(self, value, foobar)
        self.value = value
        self.foobar = Foobar(foobar)

class Bar(object):
    def __init__(self, value, foobar)
        self.value = value
        self.foobar = Foobar(foobar)

允许类创建新实例的最佳方法根据传递给__init__的值使用现有实例?

2 个答案:

答案 0 :(得分:4)

您可以通过调用基类__new__()来删除递归:

class Foobar(object):
    def __new__(cls, value):
        if isinstance(value, cls):
           return value
        else:
           return object.__new__(cls, value)
    def __init__(self, value):
        self.value = value

请注意,__new__()的第一个参数是一个类,而不是self

那就是说,我不相信这是一个有用的模式。一般来说,我建议接受构造函数中的实例,并将对象构造留给调用代码。虽然做正确事情的魔法通常看起来很方便,但它通常会导致更多的问题,而不是它的价值。

答案 1 :(得分:1)

另一个选择是使用mixin类来分解重复的代码...

class Foobar(object):
    def __init__(self, value):
        self.value = value

class FoobarMixin(object):
    def __init__(self, **kwargs):
        foobar = kwargs['foobar']
        if isinstance(foobar, Foobar):
            self.foobar = foobar
        else:
            self.foobar = Foobar(foobar)

class Foo(FoobarMixin):
    def __init__(self, value, **kwargs):
        super(Foo, self).__init__(**kwargs)
        self.value = value
        print self.value, self.foobar

class Bar(FoobarMixin):
    def __init__(self, value, **kwargs):
        super(Bar, self).__init__(**kwargs)
        self.value = value
        print self.value, self.foobar

foo = Foo('foo', foobar='foobar')
bar = Bar('bar', foobar=Foobar('foobar'))

...打印......

foo <__main__.Foobar object at 0x7fa0fedf6050>
bar <__main__.Foobar object at 0x7fa0fedeaf10>