Python 中 staticmethod 和 classmethod 原理探究

起步

文章 《Python中 property 的實現原理及實現純 Python 版》 中探究了 property 的實現原理。若是能理解那邊描述符的使用方式,那也能很快理解本篇中的 staticmethodclassmethodphp

函數與方法

對於類中定義的方法來講,經過類來調用與實例調用是不同的:python

class C:
    def f(self): pass

print(C.f)    # <function C.f at >
print(C().f)  # <bound method C.f of >

一個返回的是 function 類型,一個返回的是 method 類型。他們的主要區別在於,函數的 傳參都是顯式傳遞的 而方法則方法中 傳參每每都會有隱式傳遞的,具體根據於調用方。例如示例中的 C().f 經過實例調用的方式會隱式傳遞 self 數據。閉包

staticmethod 的實現

staticmethod 的效果是讓 C.fc.f 都返回函數,等價於 object.__getattribute__(c, "f")object.__getattribute__(C, "f") ,運行代碼以下:函數

class C:
    @staticmethod
    def sf(): pass

c = C()
print(C.sf)         # <function C.sf at 0x000001AEDDA64040>
print(c.sf)         # <function C.sf at 0x000001AEDDA64040>
print(C.sf is c.sf) # True

要實現這樣的方式也能夠依託於描述符的機制,在 __get__ 中返回原始的函數,所以它的 Python 實現版本異常的簡單:工具

class staticmethod(object):
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f

這麼簡單的代碼也已是 C 實現版本對應的Python完整代碼了。學習

classmethod 的實現

classmethod 則是要讓 C.fc.f 都返回方法,而且傳遞隱式參數 cls , 運行代碼以下:設計

class C:
    @classmethod
    def cf(cls): pass

c = C()
print(C.cf)         # <bound method C.cf>
print(c.cf)         # <bound method C.cf>
print(C.cf is c.cf) # False

classmethod 不只要隱式傳遞參數,還須要每次建立新的 <bound method> 對象。所以它的實現上須要用閉包,將閉包函數做爲返回值以便獲得新的對象:code

class classmethod(object):
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, klass=None):
        if klass is None:
            klass = type(obj)
        def newfunc(*args):
            return self.f(klass, *args)
        return newfunc

這裏的技巧就在於閉包將隱式的 cls 經過閉包空間進行綁定。這個純python實現版本在功能上沒什麼問題,僅有個小缺陷:對象

c = C()
print(C.cf)         # <function classmethod.__get__.<locals>.newfunc at 0x000001EDF2527EE0>
print(c.cf)         # <function classmethod.__get__.<locals>.newfunc at 0x000001EDF2527EE0>
print(C.cf is c.cf) # False

儘管咱們用閉包綁定了個隱式參數,但經過 c.cf 獲取的依然是 function 對象。我沒有找到能夠在Python代碼中建立 <bound method> 實例的方式。ip

總結

staticmethodclassmethod 都運用了描述符的機制,學習描述符不只能提供接觸到更多工具集的方法,還能更深地理解 Python 工做的原理並更加體會到其設計的優雅性。

相關文章
相關標籤/搜索