Python中的@staticmethod和@classmethod的區別

Bigyoungs發表於2020-06-30

一直搞不明白,類方法和靜態方法的區別,特意研究了一下,跟大家分享一下。

為了方便大家瞭解兩者的差別,以下的示例程式碼將有助於發現其中的差別:

class A(object):
    def foo(self, x):
        print "executing foo(%s, %s)" % (self, x)

    @classmethod
    def class_foo(cls, x):
        print "executing class_foo(%s, %s)" % (cls, x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)" % x    

a = A()

以下是物件例項呼叫方法的常用方法,物件例項a作為第一個引數隱式傳遞。

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

使用classmethods時,物件例項的類作為第一個引數而不是隱式傳遞self。

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

您也可以class_foo使用該類進行呼叫。

實際上,如果您將某些東西定義為類方法,則可能是因為您打算從類而不是從類例項呼叫它。

A.foo(1)本來會引發TypeError,但A.class_foo(1)效果很好:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

人們發現類方法的一種用途是建立可繼承的替代建構函式。

使用staticmethods時,self(物件例項)和 cls(類)都不會隱式傳遞為第一個引數。它們的行為類似於普通函式,只是您可以從例項或類中呼叫它們:

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

特別注意此句:

靜態方法用於對與類之間具有某種邏輯聯絡的函式分組。

foo只是一個函式,但是當您呼叫a.foo它時,不僅獲得該函式,還會獲得該函式的“部分應用”版本,該物件例項a繫結為該函式的第一個引數。foo期望有2個引數,而a.foo只期望有1個引數。

a勢必到foo。這就是下面的術語“繫結”的含義:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

與a.class_foo,a不繫結class_foo,而是與類A繫結class_foo。

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

在這裡,使用靜態方法,即使它是一種方法,也a.static_foo只是返回一個沒有繫結引數的良好的'ole函式。static_foo期望有1個引數,也 a.static_foo期望有1個引數。

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

當然,當您static_foo使用類進行呼叫時,也會發生同樣的事情A。

print(A.static_foo)
# <function static_foo at 0xb7d479cc>

總結一下彼此的呼叫區別:

e9c9bb5d9285c7eae68b281b8ab094a0.png

本文首發於BigYoung小站

相關文章