1. 程式人生 > >裝飾器之類裝飾器

裝飾器之類裝飾器

外部的方法至今都玩過了,現在來思索一下的方法這麼裝飾

類方法修飾器

類的方法唯一的特殊點在於,self內部是可以呼叫的,但是在外部卻是隱藏的,那這個怎麼搞

為求穩妥,先定參修飾一個

def godme(fun):
    def __godme(self,message):
        print('before')
        fun(self,message)
        print('after')
    return __godme

class Person:
    def show(self,message):
        print(message)
    @godme
    def say(self,message):
        print(message)

person = Person()
person.say('happy')
'''
before
happy
after
'''
實驗過的我不敘述了,但是發現這麼一點

類當中的方法和普通方法一樣,使用方法一樣,只有物件進行呼叫的時候,第一個引數會預設吧物件例項傳入,然後隱匿

這個相當於__call__和__new__一類的東西吧,同樣的,四則運算在類內部也有對應的方法實現,但是外部符號就可以呼叫

所以修飾類的self不可以省略,外部定義時和內部定義沒有區別,但是物件呼叫會自動隱藏

思考:self都能傳入的話,我是不是能做點什麼?

def godme(fun):
    def __godme(self,message):
        self.show('sunny')
        print('before')
        fun(self,message)
        print('after')
    return __godme

class Person:
    def show(self,message):
        print(message)
    @godme
    def say(self,message):
        print(message)

person = Person()
person.say('happy')
'''
sunny
before
happy
after
'''
在外部傳入的 self,也可以呼叫類內部方法,不過就像物件能夠自動填充self一樣,self表示物件例項

物件例項呼叫類內部方法時會自動填充self,並隱藏該引數

那麼,顯式的宣告self之後,其餘的不就隨便定義成收容所了麼,畢竟類內部方法有這麼一個必須存在self入參的這個硬性規定

def godme(fun):
    def __godme(self,*args,**kwargs):
        self.show('sunny')
        print('before')
        fun(self,*args,**kwargs)
        print('after')
    return __godme

class Person:
    def show(self,message):
        print(message)
    @godme
    def say(self,message):
        print(message)

person = Person()
person.say('happy')
'''
sunny
before
happy
after
'''
這就實現了類方法適配修飾器的編寫

類修飾器

類同樣可以加上括號進行方法呼叫,也就是說,類也可以看做是一個方法,那麼,為什麼不能進行修飾呢?

def godme(fun):
    def __godme(cls,*args,**kwargs):
        print('before')
        fun(cls,*args,**kwargs)
        print('after')
    return __godme
@godme
class Person:
    def __new__(cls, *args, **kwargs):
        print('__new__')

Person(Person)
列印結果
before
__new__
after
發現其實除了類函式首個引數必須傳入也沒發現啥不同,類也是就是一個擁有更多複雜動態的方法而已

此外,我們可以真切的感受到了裝飾器自帶的一種深深的惡意了,這是它的優點也恰恰是它致命的弱點,造福也蘊含極大的破壞能力

功能替換:它並沒有讓我們的方法更加的多樣化,而只是把我們原有的功能作為一部分新增進入了一個新的方法裡面,然後返回給原方法的方法名

不過到底要不要新增進入返回的方法裡面,甚至是返不返回一個值,什麼值,這都是具有十足破壞力的

一個簡單的記號,可以輕易的增添功能而不改動原有程式碼,同時,一個簡單的符號也可以徹底摧毀整個程式碼架構

def godme(fun):
    def __godme(*args,**kwargs):
        print('there are no function')
    return __godme

@godme
def test():
    print('test')

test()      #there are no function
可怕的東西,不過現在除了弄亂自己程式碼這種沒有作用的例項,還沒有接觸到可以造成深遠破壞的程式碼

說到了替換,而且剛好是類名方法呼叫,和建立物件就有些許的關聯了,那不防來個單例裝飾器

def single(fun):
    def __single():
        return hasattr(fun,'single') and getattr(fun,'single') or setattr(fun,'single',fun()) or getattr(fun,'single')
    return __single

@single
class Person:
    pass

p1 = Person()
p2 = Person()
print(p1)           #<__main__.Person object at 0x02B525D0>
print(p2)           #<__main__.Person object at 0x02B525D0>
print(p1 is p2)     #True
在這個實現方法裡面,我們仍然是呼叫了它本身的物件生成方法

我們也可以直接外部建立一個字典,當字典中沒有指定類作為的key,就建立物件,並返回

同時在字典內部吧類名作為key,物件作為value,下次呼叫直接查詢,找不到就新增,找到直接返回

這種實現方法,網上有很多

至此,關於裝飾器的各種變種和內涵技巧都講述完畢,有疑問請參考前面幾篇文章,謝謝