需要澄清“decorator类”是如何在Python中工作的吗

2024-10-02 22:29:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在学习如何在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)()的调用。这不应该为每个KlasseA()调用生成一个新的Singleton实例吗?

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

  3. 有没有一个可能的'抓到'与上述单一装饰配方?


Tags: instanceselfidinitdefargscallkwargs
1条回答
网友
1楼 · 发布于 2024-10-02 22:29:59

Decorators是在定义类时应用的,而不是在实例化类时应用的。关于你的第一点,它实际上相当于:

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

相关问题 更多 >