需要澄清一个"装饰器类"在Python工作

时间:2014-11-14 04:06:21

标签: python singleton python-decorators

我正在学习如何在Python中创建单身人士(请不要说明为什么单身人士不好或者这样,这里不是主题)

基于一个实现,我尝试这样做:

class Singleton(object):
    def __init__(self, klass):
        print "S init"
        self.klass = klass
        self.instance = None
    def __call__(self, *args, **kwargs):
        print "S call"
        if self.instance is None:
            self.instance = self.klass(*args, **kwargs)
        else:
            self.instance(*args, **kwargs)
        return self.instance

@Singleton
class KlasseA:
    def __new__(cls, *args, **kwargs):
        print "KA new"
    def __init__(self, s):
        print "KA init"
        self.__init2(s)
    def __call__(self, s=None):
        print "KA call"
        self.__init2(s)
    def __init2(self, s):
        if s: self.s = s

@Singleton
class KlasseB:
    def __new__(cls, *args, **kwargs):
        print "KB new"
    def __init__(self, s):
        print "KB init"
        self.__init2(s)
    def __call__(self, s=None):
        print "KB call"
        self.__init2(s)
    def __init2(self, s):
        if s: self.s = s

现在,通过在同一.py文件中附加以下行来测试上述内容:

print ""
a = KlasseA('one')
print "a -> ", id(a), a.s
b = KlasseA('two')
print "b -> ", id(b), b.s
print "a -> ", id(a), a.s
c = KlasseA()
print "c -> ", id(c), c.s
print "b -> ", id(b), b.s
print "a -> ", id(a), a.s
d = KlasseB('three')
print "d -> ", id(d), d.s
print "a -> ", id(a), a.s

我得到了以下内容:

S init
S init

S call
KA init
a ->  140525844905496 one
S call
KA call
b ->  140525844905496 two
a ->  140525844905496 two
S call
KA call
c ->  140525844905496 two
b ->  140525844905496 two
a ->  140525844905496 two
S call
KB init
d ->  140525844905568 three
a ->  140525844905496 two

所以,单身装饰器确实有效。我在这里不明白的是:

  1. 我认为装饰器重新定义了通话,因此通话KlasseA()实际上是对Singleton(KlasseA)()的调用。不应该为每个Singleton调用生成一个新的KlasseA()实例吗?

  2. 我注意到有两个" S init"行,很可能是因为在Singleton()KlasseA声明期间调用了KlasseB。因此,创建了Singleton的两个实例。这些实例保存在哪里?

  3. 是否有可能出现的问题'使用上面的Singleton装饰器配方?

1 个答案:

答案 0 :(得分:1)

装饰器在定义类时应用,而不是在实例化时应用。关于你的观点1,它实际上相当于:

class KlasseA():
    ...

KlasseA = Singleton(KlasseA)

a = KlasseA()

关于第2点,名称KlasseAKlasseB绑定到Singleton的实例,如上所示。

关于第3点,我不确定仅因为您尝试创建新实例而调用类的单个实例的__call__方法是有意义的。也就是说,我认为Singleton.__call__应该只是

def __call__(self, *args, **kwargs):
    if self.instance is None:
        self.instance = self.klass(*arg, **kwargs)
    return self.instance