我有一个类似于以下内容的模式:
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)
这允许Foo
和Bar
将新值(创建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__
的值使用现有实例?
答案 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>