天天看點

Python 執行個體方法、類方法和靜态方法

在 Python 中,執行個體方法(instance method),類方法(class method)與靜态方法(static method)經常容易混淆。本文通過代碼例子來說明它們的差別。

執行個體方法

Python 的執行個體方法用得最多,也最常見。我們先來看 Python 的執行個體方法。

class Kls(object):
    def __init__(self, data):
        self.data = data

    def printd(self):
        print(self.data)


ik1 = Kls('leo')
ik2 = Kls('lee')

ik1.printd()
ik2.printd()
           

輸出:

leo

lee

上述例子中,

printd

為一個執行個體方法。執行個體方法第一個參數為

self

,當使用

ik1.printd()

調用執行個體方法時,執行個體

ik1

會傳遞給

self

參數,這樣

self

參數就可以引用目前正在調用執行個體方法的執行個體。利用執行個體方法的這個特性,上述代碼正确輸出了兩個執行個體的成員資料。

類方法

Python 的類方法采用裝飾器

@classmethod

來定義,我們直接看例子。

class Kls(object):
    num_inst = 

    def __init__(self):
        Kls.num_inst = Kls.num_inst + 

    @classmethod
    def get_no_of_instance(cls):
        return cls.num_inst


ik1 = Kls()
ik2 = Kls()

print ik1.get_no_of_instance()
print Kls.get_no_of_instance()
           

輸出:

2

2

在上述例子中,我們需要統計類

Kls

執行個體的個數,是以定義了一個類變量

num_inst

來存放執行個體個數。通過裝飾器

@classmethod

的使用,方法

get_no_of_instance

被定義成一個類方法。在調用類方法時,Python 會将類(class Kls)傳遞給

cls

,這樣在

get_no_of_instance

内部就可以引用類變量

num_inst

由于在調用類方法時,隻需要将類型本身傳遞給類方法,是以,既可以通過類也可以通過執行個體來調用類方法。

靜态方法

在開發中,我們常常需要定義一些方法,這些方法跟類有關,但在實作時并不需要引用類或者執行個體,例如,設定環境變量,修改另一個類的變量,等。這個時候,我們可以使用靜态方法。

Python 使用裝飾器

@staticmethod

來定義一個靜态方法。

IND = 'ON'


class Kls(object):
    def __init__(self, data):
        self.data = data

    @staticmethod
    def checkind():
        return IND == 'ON'

    def do_reset(self):
        if self.checkind():
            print('Reset done for: %s' % self.data)

    def set_db(self):
        if self.checkind():
            print('DB connection made for: %s' % self.data)


ik1 = Kls()
ik1.do_reset()
ik1.set_db()
           

輸出:

Reset done for: 24

DB connection made for: 24

在代碼中,我們定義了一個全局變量

IND

,由于

IND

跟類

Kls

相關,是以我們将方法

checkind

放置在類

Kls

中定義。方法

checkind

隻需檢查

IND

的值,而不需要引用類或者執行個體,是以,我們将方法

checkind

定義為靜态方法。

對于靜态方法,Python 并不需要傳遞類或者執行個體,是以,既可以使用類也可以使用執行個體來調用靜态方法。

執行個體方法,類方法與靜态方法的差別

我們用代碼說明執行個體方法,類方法,靜态方法的差別。注意下述代碼中方法

foo

class_foo

static_foo

的定義以及使用。

class Kls(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)


ik = Kls()

# 執行個體方法
ik.foo()
print(ik.foo)
print('==========================================')

# 類方法
ik.class_foo()
Kls.class_foo()
print(ik.class_foo)
print('==========================================')

# 靜态方法
ik.static_foo()
Kls.static_foo('hi')
print(ik.static_foo)
           

輸出:

executing foo(<__main__.Kls object at x0551E190>,)
<bound method Kls.foo of <__main__.Kls object at x0551E190>>
==========================================
executing class_foo(<class '__main__.Kls'>,)
executing class_foo(<class '__main__.Kls'>,)
<bound method type.class_foo of <class '__main__.Kls'>>
==========================================
executing static_foo()
executing static_foo(hi)
<function static_foo at x055238B0>
           

對于執行個體方法,調用時會把執行個體

ik

作為第一個參數傳遞給

self

參數。是以,調用

ik.foo(1)

時輸出了執行個體

ik

的位址。

對于類方法,調用時會把類

Kls

作為第一個參數傳遞給

cls

參數。是以,調用

ik.class_foo(1)

時輸出了

Kls

類型資訊。

前面提到,可以通過類也可以通過執行個體來調用類方法,在上述代碼中,我們再一次進行了驗證。

對于靜态方法,調用時并不需要傳遞類或者執行個體。其實,靜态方法很像我們在類外定義的函數,隻不過靜态方法可以通過類或者執行個體來調用而已。

值得注意的是,在上述例子中,

foo

隻是個函數,但當調用

ik.foo

的時候我們得到的是一個已經跟執行個體

ik

綁定的函數。調用

foo

時需要兩個參數,但調用

ik.foo

時隻需要一個參數。

foo

ik

進行了綁定,是以,當我們列印

ik.foo

時,會看到以下輸出:

<bound method Kls.foo of <__main__.Kls object at x0551E190>>
           

當調用

ik.class_foo

時,由于

class_foo

是類方法,是以,

class_foo

Kls

進行了綁定(而不是跟

ik

綁定)。當我們列印

ik.class_foo

時,輸出:

<bound method type.class_foo of <class '__main__.Kls'>>
           

當調用

ik.static_foo

時,靜态方法并不會與類或者執行個體綁定,是以,列印

ik.static_foo

(或者

Kls.static_foo

)時輸出:

<function static_foo at x055238B0>
           

概括來說,是否與類或者執行個體進行綁定,這就是執行個體方法,類方法,靜态方法的差別。

參考資料

  1. https://www.pythoncentral.io/difference-between-staticmethod-and-classmethod-in-python/
  2. https://taizilongxu.gitbooks.io/stackoverflow-about-python/content/14/README.html
  3. https://kuanghy.github.io/2015/12/19/python-variable
  4. https://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python