鍍金池/ 問答/Python/ python的裝飾器如果是一個類,流程和原理是怎樣的?

python的裝飾器如果是一個類,流程和原理是怎樣的?


class Singleton:

    """
    單例類裝飾器,可以用于想實現(xiàn)單例的任何類。注意,不能用于多線程環(huán)境。
    """

    def __init__(self, cls):
        """ 需要的參數(shù)是一個類 """
        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)

這是網(wǎng)上看到的單例模式實現(xiàn),他的裝飾器是一個類,但是我在網(wǎng)上看到的關于裝飾器的都是函數(shù),按照我的理解,如果裝飾器是個函數(shù)的話,會將@下面的函數(shù)傳入@的函數(shù),@的函數(shù)回返回一個函數(shù),這個函數(shù)回執(zhí)行傳入的函數(shù),和一些其他的操作。但是如果@的是一個裝飾器的話應該怎么理解呢,按這段代碼看 A應該是傳進了Singleton的__init__方法,但是調(diào)用又是A.Instance(),這是繼承關系嗎,還有__instancecheck__是干嘛的,self._decorated又是什么意思?實在無法理解

回答
編輯回答
玄鳥

這里是個人對這些代碼的理解,希望能為你提供一些線索:

@Singleton裝飾class A 的時候,也就是以class A 作為參數(shù)給 Singleton(self._cls),就已經(jīng)實例化了Singleton類并且命名為A。
然后A.instance()是調(diào)用instance()方法把在Singleton類的A里面的self._cls實例化,那么classA 的實例就變成了Singleton類實例A的一個成員屬性。 這有點類似于inner class,或者nested class,inner class可以使用外部class的屬性和方法,但是應該與繼承有區(qū)別的。

下面這段應該是這樣的:self._decorated其實就是self._cls, 我在下面網(wǎng)頁找到類似代碼,然后改了self._decorated,運行結果一樣,至于為什么會這樣我不了解。
http://outofmemory.cn/code-sn...

def __instancecheck__(self, inst):

    return isinstance(inst, self._decorated)

__instancecheck__(self, inst):是python的魔法方法,當執(zhí)行 print(isinstance(s2,A)) 時候就會觸發(fā)這方法,用以判別其實例是否某class 的實例。

把def instance() 改成這樣:
def Instance(self):

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

運行 s1 is s2 會返False。
我們知道沒有改之前,因為try except 會讓 instance() return self._instance, 如果沒有的話就實現(xiàn)一個。 造成 s1 和s2 兩個id一樣,我的理解應該是同一個instance吧,s1 is s2 返回True。
而改了之后,s1 和s2 就不同id了, 然后 s1 is s2 就返回False。

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

2018年2月27日 19:53