天天看點

了解python的staticmethod與classmethod實作

本文源于一時好奇,想要弄清出python的staticmethod()這一builtin方法的實作,查了一些資料(主要是python官方手冊了)彙集于此

python在類中,有三種調用method的方法:普通method,staticmethod和classmethod

前兩個應該都好了解,classmethod就是在調用這個函數的時候,會把調用對象的class object對象隐式地傳進去。咦?這個class object不是一個類型?No,在python裡面,class object不像靜态語言一樣是個類型,它在虛拟機中,就是一個對象

普通method調用需要把自己self作為參數傳遞,初學的時候怎麼着也不能了解,不過看多了就自然熟悉了。比較奇怪的是staticmethod和classmethod不像靜态語言一樣,通過保留關鍵字定義,而是使用@staticmethod或者staticmethod()這種builtin函數進行定義。這個@staticmethod到底是個什麼東東?

@staticmethod
def foo(x):
    print(x)
           

之前用過java,是以第一反應這是個annotation……唔,确實感覺像個AOP的東西,python裡把它稱作decorator。如果我們要自己實作一個staticmethod,該怎麼寫呢?

研究了下官方的代碼,我再改了改,感覺應該這樣寫:

輸出結果是:

嗯,看上去一切都挺順利,Class1包含了一個變量method,不過這個method其實也是一個特殊處理過的StaticMethod類。這個類中有一個__get__函數,當類被“get”的時候,被通路的時候,會預設把通路者的instance和class資訊都傳進來。是以我們看到不管是否調用method()這個函數,隻要碰着了method,這個函數就會觸發,就會列印出目前instance和class資訊。雖然ins和Class1的instance各有不同,但__get__函數中隻是傳回foo函數,是以這裡調用method之時就沒有差別,調用的都是同一個function對象。

好的,那麼classmethod又如何實作呢?

輸出結果是:

可以看出,classmethod和staticmethod的實作方法是大同小異。staticmethod比較簡單,直接傳回self.f變量就好了,而classmethod不行,需要把調用時候的class類型資訊傳給foo2函數,這個函數根據接收的class資訊來作不同的工作。(不過我現在也沒有想到可以用來做些什麼)

有個地方值得注意,可能同志們剛才也已經想到了,我一定必須要定義一個tempfunc,再傳回它才能完成工作嗎?可不可以不要

def tmpfunc(x):
            print("I'm tmpfunc")
            return self.f(owner, x)
        return tmpfunc
           

而直接傳回一個

return self.f(owner, *args)
           

我剛試了一把,直接傳args預設參數是不行的,因為__get__被調用的時候,還沒有把參數傳進來。隻有return tmpfunc之後,Class2.method('xyz')的參數才挂在tmpfunc之上。

當然,如果有朋友成功做到了,請一定留言告訴我XD

小結:看來staticmethod和classmethod實作不是很困難,多虧了__get__函數幫忙。前文也提到__get__被調用時會把instance和class資訊都填進來,真是幫了很大忙。但是,這個__get__函數到底又是怎麼一回事?為什麼這麼神奇?這裡賣個關子,本文先不講了,下篇博文再看看這個[url=http://luozhaoyu.iteye.com/blog/1506426]__get__函數[/url]吧