python的装饰器如果是一个类,流程和原理是怎样的?


class Singleton:

    """
    单例类装饰器,可以用于想实现单例的任何类。注意,不能用于多线程环境。
    """

    def __init__(self, cls):
        """ 需要的参数是一个类 """
        self._cls = cls

    def Instance(self):
        """
        返回真正的实例
        """
        try:
            return self._instance
        except AttributeError:
            self._instance = self._cls()
            return self._instance

    def __call__(self):
        raise TypeError('Singletons must be accessed through `Instance()`.')

    def __instancecheck__(self, inst):
        return isinstance(inst, self._decorated)


# 装饰器
@Singleton
class A:
    """一个需要单列模式的类"""
    def __init__(self):
        pass

    def display(self):
        return id(self)

if __name__ == '__main__':
    s1 = A.Instance()
    s2 = A.Instance()
    print(s1, s1.display())
    print(s2, s2.display())
    print(s1 is s2)

这是网上看到的单例模式实现,他的装饰器是一个类,但是我在网上看到的关于装饰器的都是函数,按照我的理解,如果装饰器是个函数的话,会将@下面的函数传入@的函数,@的函数回返回一个函数,这个函数回执行传入的函数,和一些其他的操作。但是如果@的是一个装饰器的话应该怎么理解呢,按这段代码看 A应该是传进了Singleton的__init__方法,但是调用又是A.Instance(),这是继承关系吗,还有__instancecheck__是干嘛的,self._decorated又是什么意思?实在无法理解

阅读 2.2k
1 个回答

这里是个人对这些代码的理解,希望能为你提供一些线索:

@Singleton装饰class A 的时候,也就是以class A 作为参数给 Singleton(self._cls),就已经实例化了Singleton类并且命名为A。
然后A.instance()是调用instance()方法把在Singleton类的A里面的self._cls实例化,那么classA 的实例就变成了Singleton类实例A的一个成员属性。 这有点类似于inner class,或者nested class,inner class可以使用外部class的属性和方法,但是应该与继承有区别的。

下面这段应该是这样的:self._decorated其实就是self._cls, 我在下面网页找到类似代码,然后改了self._decorated,运行结果一样,至于为什么会这样我不了解。
http://outofmemory.cn/code-sn...

def __instancecheck__(self, inst):

    return isinstance(inst, self._decorated)

__instancecheck__(self, inst):是python的魔法方法,当执行 print(isinstance(s2,A)) 时候就会触发这方法,用以判别其實例是否某class 的实例。

把def instance() 改成这样:
def Instance(self):

        self._instance = self._cls()
        return self._instance
        

运行 s1 is s2 会返False。
我们知道没有改之前,因为try except 会让 instance() return self._instance, 如果没有的话就实现一个。 造成 s1 和s2 两个id一样,我的理解应该是同一个instance吧,s1 is s2 返回True。
而改了之后,s1 和s2 就不同id了, 然后 s1 is s2 就返回False。

call 讓 A() 出錯,所以要用instance() 訪問A以實現被decorated 的class

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题