使用 __init__ 方法接收新值或已有实例

60 阅读2分钟

在面向对象编程中,经常需要创建具有相同属性和方法的不同对象。一种常见的方法是使用 __init__ 方法来初始化对象。

但是,有时我们需要在 __init__ 方法中接收新值或已有实例。例如,我们可能有一个 Foobar 类,它具有一个 value 属性。我们希望 FooBar 类可以使用 Foobar 的实例或使用新值来创建 Foobar 实例。

以下是我们希望实现的代码:

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 参数。

但是,这段代码存在冗余,需要在 FooBar 类中重复相同的代码。因此,我们希望找到一种方法来消除这种冗余。

2. 解决方案

方法一

一种解决方案是使用 __new__ 方法来创建对象。__new__ 方法在 __init__ 方法之前调用,它负责创建对象并返回对象引用。

我们可以通过重写 __new__ 方法来实现我们的目标。以下是重写的 __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__ 方法中,我们首先检查 value 是否是 Foobar 类的一个实例。如果是,则直接返回该实例。否则,我们调用 object.__new__(cls, value) 来创建 Foobar 实例并返回该实例。

这样,我们就消除了 FooBar 类中冗余的代码。

方法二

另一种解决方案是使用 mixin 类。mixin 类是一个提供某些功能的类,它可以被其他类继承。

我们可以创建一个 FoobarMixin 类来提供 __init__ 方法的逻辑。以下是 FoobarMixin 类的代码:

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

FoobarMixin 类中的 __init__ 方法接受一个 **kwargs 参数,它是一个关键字参数字典。__init__ 方法从 **kwargs 参数中提取 foobar 参数,然后检查 foobar 参数是否是一个 Foobar 实例。如果是,则直接将 foobar 参数赋值给 self.foobar 属性。否则,__init__ 方法调用 Foobar(foobar) 来创建 Foobar 实例并将其赋值给 self.foobar 属性。

然后,我们可以让 FooBar 类继承 FoobarMixin 类。以下是 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

这样,我们就消除了 FooBar 类中冗余的代码,并且实现了我们的目标。

我们也可以使用以下代码来创建 FooBar 的实例:

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

输出结果如下:

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