python的staticmethod與classmethod實現(xiàn)實例代碼
本文源于一時好奇,想要弄清出python的staticmethod()這一builtin方法的實現(xiàn),查了一些資料(主要是python官方手冊了)匯集于此
python在類中,有三種調(diào)用method的方法:普通method,staticmethod和classmethod
前兩個應(yīng)該都好理解,classmethod就是在調(diào)用這個函數(shù)的時候,會把調(diào)用對象的class object對象隱式地傳進(jìn)去。咦?這個class object不是一個類型?No,在python里面,class object不像靜態(tài)語言一樣是個類型,它在虛擬機(jī)中,就是一個對象。普通method調(diào)用需要把自己self作為參數(shù)傳遞,初學(xué)的時候怎么著也不能理解,不過看多了就自然熟悉了。比較奇怪的是staticmethod和classmethod不像靜態(tài)語言一樣,通過保留關(guān)鍵字定義,而是使用@staticmethod或者staticmethod()這種builtin函數(shù)進(jìn)行定義。這個@staticmethod到底是個什么東東?
@staticmethod def foo(x): print(x)
之前用過java,所以第一反應(yīng)這是個annotation……唔,確實感覺像個AOP的東西,python里把它稱作decorator。如果我們要自己實現(xiàn)一個staticmethod,該怎么寫呢?
研究了下官方的代碼,我再改了改,感覺應(yīng)該這樣寫:
def foo(x):
print(x)
class StaticMethod(object):
def __init__(self, function):
print("__init__() called")
self.f = function
def __get__(self, instance, owner):
print("\t__get__() called")
print("\tINFO: self = %s, instance =%s, owner = %s" % (self, instance, owner))
return self.f
class Class1(object):
method = StaticMethod(foo)
if __name__ == '__main__':
ins = Class1()
print("ins = %s, Class1 = %s" % (ins, Class1))
print("ins.method = %s, Class1.method = %s" % (ins.method, Class1.method))
ins.method('abc')
Class1.method('xyz')
輸出結(jié)果是:
__init__() called
ins = <__main__.Class1 object at 0xece2d0>, Class1 = <class '__main__.Class1'>
__get__() called
INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =<__main__.Class1 object at 0xece2d0>, owner = <class '__main__.Class1'>
__get__() called
INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =None, owner = <class '__main__.Class1'>
ins.method = <function foo at 0xeb6c00>, Class1.method = <function foo at 0xeb6c00>
__get__() called
INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =<__main__.Class1 object at 0xece2d0>, owner = <class '__main__.Class1'>
abc
__get__() called
INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =None, owner = <class '__main__.Class1'>
xyz
嗯,看上去一切都挺順利,Class1包含了一個變量method,不過這個method其實也是一個特殊處理過的StaticMethod類。這個類中有一個__get__函數(shù),當(dāng)類被“get”的時候,被訪問的時候,會默認(rèn)把訪問者的instance和class信息都傳進(jìn)來。所以我們看到不管是否調(diào)用method()這個函數(shù),只要碰著了method,這個函數(shù)就會觸發(fā),就會打印出當(dāng)前instance和class信息。雖然ins和Class1的instance各有不同,但__get__函數(shù)中只是返回foo函數(shù),所以這里調(diào)用method之時就沒有區(qū)別,調(diào)用的都是同一個function對象。
好的,那么classmethod又如何實現(xiàn)呢?
def foo2(cls, x):
print("foo2's class = ", cls)
print(x)
class ClassMethod(object):
def __init__(self, function):
print("ClassMethod: __init__() called")
self.f = function
def __get__(self, instance, owner = None):
print("\t__get__() called")
print("\tINFO: self = %s, instance =%s, owner = %s" % (self, instance, owner))
def tmpfunc(x):
print("I'm tmpfunc")
return self.f(owner, x)
return tmpfunc
class Class2(object):
method = ClassMethod(foo2)
class Class21(Class2):
pass
if __name__ == '__main__':
ins = Class2()
print("ins.method = %s, Class2.method = %s, Class21.method = %s" % (ins.method, Class2.method, Class21.method))
ins.method('abc')
Class2.method('xyz')
Class21.method('asdf')
輸出結(jié)果是:
ClassMethod: __init__() called
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =<__main__.Class2 object at 0xdeb350>, owner = <class '__main__.Class2'>
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class2'>
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class21'>
ins.method = <function tmpfunc at 0xdee050>, Class2.method = <function tmpfunc at 0xdee1e8>, Class21.method = <function tmpfunc at 0xdee270>
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =<__main__.Class2 object at 0xdeb350>, owner = <class '__main__.Class2'>
I'm tmpfunc
foo2's class = <class '__main__.Class2'>
abc
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class2'>
I'm tmpfunc
foo2's class = <class '__main__.Class2'>
xyz
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class21'>
I'm tmpfunc
foo2's class = <class '__main__.Class21'>
asdf
可以看出,classmethod和staticmethod的實現(xiàn)方法是大同小異。staticmethod比較簡單,直接返回self.f變量就好了,而classmethod不行,需要把調(diào)用時候的class類型信息傳給foo2函數(shù),這個函數(shù)根據(jù)接收的class信息來作不同的工作。(不過我現(xiàn)在也沒有想到可以用來做些什么)
有個地方值得注意,可能同志們剛才也已經(jīng)想到了,我一定必須要定義一個tempfunc,再返回它才能完成工作嗎?可不可以不要
def tmpfunc(x):
print("I'm tmpfunc")
return self.f(owner, x)
return tmpfunc
而直接返回一個
return self.f(owner, *args)
我剛試了一把,直接傳args默認(rèn)參數(shù)是不行的,因為__get__被調(diào)用的時候,還沒有把參數(shù)傳進(jìn)來。只有return tmpfunc之后,Class2.method('xyz')的參數(shù)才掛在tmpfunc之上。
當(dāng)然,如果有朋友成功做到了,請一定留言告訴我XD
小結(jié):看來staticmethod和classmethod實現(xiàn)不是很困難,多虧了__get__函數(shù)幫忙。前文也提到__get__被調(diào)用時會把instance和class信息都填進(jìn)來,真是幫了很大忙。但是,這個__get__函數(shù)到底又是怎么一回事?為什么這么神奇?大家可以參考Python中 __get__和__getattr__和__getattribute__的區(qū)別
總結(jié)
以上就是本文關(guān)于python的staticmethod與classmethod實現(xiàn)實例代碼的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
在Pytorch中使用樣本權(quán)重(sample_weight)的正確方法
今天小編就為大家分享一篇在Pytorch中使用樣本權(quán)重(sample_weight)的正確方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08
Python tkinter之ComboBox(下拉框)的使用簡介
這篇文章主要介紹了Python tkinter之ComboBox(下拉框)的使用簡介,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2021-02-02
在PyCharm中打包Python項目并將其運行到服務(wù)器上的方法(推薦)
在PyCharm中打包Python項目并運行到服務(wù)器上,主要步驟包括:創(chuàng)建并設(shè)置項目、編寫項目代碼、打包項目、配置服務(wù)器環(huán)境、上傳可執(zhí)行文件到服務(wù)器以及運行項目,通過這些步驟,可以將Python項目打包并部署到服務(wù)器上2024-11-11
Python隨機(jī)函數(shù)庫random的使用方法詳解
這篇文章主要介紹了Python隨機(jī)函數(shù)庫random的使用方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-08-08
Pandas.DataFrame刪除指定行和列(drop)的實現(xiàn)
本文主要介紹了Pandas.DataFrame刪除指定行和列(drop)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
關(guān)于python 讀取csv最快的Datatable的用法,你都學(xué)會了嗎
大家都知道Datatable與眾不同就是快,還有一點大家需要注意使用Datatable庫需要python3.6及以上版本,接下來通過本文給大家介紹了python 讀取csv最快的Datatable的用法,需要的朋友可以參考下2021-10-10
詳解Python中的GIL(全局解釋器鎖)詳解及解決GIL的幾種方案
這篇文章主要介紹了詳解Python中的GIL(全局解釋器鎖)詳解及解決GIL的幾種方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01

