关于python:在__new__中执行init工作是“原罪”吗? 如果是这样,那么如何最好地处理单例初始化运行?

Is it an 'original sin' to do init work in __new__? If so, how best to handle run once init for singletons?

我有一个类,我使用标准的python单例形式。它也只是一个值,但不是在每个实例中初始化它,当我进行单例处理时,我在__new__()中初始化它。这是pythonic方式吗?如果没有,我还能怎么做?

1
2
3
4
5
6
7
class Foo(object):
    _inst = None
    def __new__(cls, val):
        if Foo._inst is None:
            Foo._inst = super(Foo, self).__new__(cls)
            Foo._inst.val = val
        return Foo._inst

这显然是简化形式。我已经使用了等待__init__()的构造来检查并设置Foo._inst来处理一次单独的init运行,但这对于多线程情况下的同步错误似乎已经成熟。如果在再次运行__init__()的情况下没有可以在现有实例中损坏的值的情况,将init放在__init__()中没有任何害处,除非您运行的代码在您不执行时无效地执行任何操作我需要,但经常有腐败的状态值,我不想覆盖。我知道单身人士也是邪恶的,但有时候,他们是最好的解决方案(比如定义我希望能够用is检查的特殊用途类型)。

这似乎是我能提出的最佳解决方案,但我觉得在__new__()中初始化实例值很脏。有没有人有关于如何更好地处理这个问题的想法?


您始终可以使用全局变量而不是单例。 具有三个不同实例的类的示例:

1
2
3
4
5
6
7
8
9
10
11
12
class _Ternary(object):
   """Internal class.  Don't instantiate!"""
    def __init__(self, value):
        self.value = value

ternary_0 = _Ternary(0)
ternary_1 = _Ternary(1)
ternary_2 = _Ternary(2)

def ternary(value):
   """Factory function to request a"ternary" instance."""
    return {0: ternary_0, 1: ternary_1: 2: ternary_2}[value]

这是直截了当的,可以避免单身人士的痛苦。


回答第一个问题:
单例在Python中并不经常使用,因为它们并不是真正需要的。

回答第二个问题:
如果您认为自己确实需要它们,那么有时会使用稍微清洁,类似"Borg"的模式,请参阅:Borg设计模式
如果你只需要在实例之间共享一些属性而不需要完整的单例(可以实例化一次),你可以简单地使用类属性,如下所示:

1
2
3
4
5
class Foo( object ):
    val = ...

    def __init__( self ):
        ...

然后,所有实例将共享"val"属性的相同值。


没有更好的方法来创造单身人士。 如果你想要它(并且三值逻辑是关于我能想到的唯一例子),那么你就可以按照自己的方式去做。