1. 程式人生 > 實用技巧 >python 類中方法總結 --- 例項方法、類方法、靜態方法

python 類中方法總結 --- 例項方法、類方法、靜態方法

  在python的類語法中,可以出現三種方法,具體如下:

  (1)例項方法

    1)第一個引數必須是例項本身,一般使用【self】表示。

    2)在例項方法中,可以通過【self】來操作例項屬性,【類名】來操作類屬性。

    3)例項方法只能通過例項物件去呼叫,儘管也可以通過類名間接呼叫【類名.方法名(self, ...)】,但此時仍然需要傳入self物件。

  (2)類方法

    1)使用【@classmethod】修飾函式,且第一個引數必須是類本身,一般使用【cls】表示。

    2)在類方法中,可以使用【cls=類名】來操作類屬性,但是不能操作例項屬性(self物件中儲存的變數)。

    3)類方法可以通過例項物件或者類物件呼叫。

  (3)靜態方法

    1)使用【@staticmethod】修飾函式,不需要使用任何引數表示。與普通函式一樣,只是將該方法放到了類中實現而已。

    2)使用方式與類方法一樣,參考類方法中的 2)、3)。(注:靜態方法只能通過【類名】去操作類屬性;)

案例1:例項方法、類方法、靜態方法使用

class Foo(object):
"""類三種方法語法形式"""
count = 0 # 統計例項物件的數量
class_method_count = 0 # 統計類方法的呼叫次數 # 例項方法
def __init__(self, name):
self.name = name
Foo.count += 1 # 例項方法
def instance_method(self):
print("是類{}的例項方法,只能被例項物件呼叫".format(Foo))
print("產生了一個<{}>例項,共有<{}>個例項物件".format(self.name, Foo.count)) # 類方法
@classmethod
def class_method(cls):
print("是類{}的類方法,可以被例項物件、類物件呼叫".format(cls))
cls.__static_method_test()
cls.class_method_count += 1 # 靜態方法
@staticmethod
def static_method():
print("是類{}的靜態方法,可以被例項物件、類物件呼叫".format(Foo))
print("+++以下內容為類方法class_method()的執行結果:")
Foo.class_method() @staticmethod
def __static_method_test():
print("呼叫了靜態方法 static_method_test()") print("--"*20 + "例項方法測試" + "--"*20)
obj1 = Foo("dog")
obj1.instance_method() # <=> Foo.instance_method(obj1) print("--"*20 + "類方法測試" + "--"*20)
obj1.class_method()
print("--"*20)
Foo.class_method() print("--"*20 + "靜態方法測試" + "--" * 20)
obj1.static_method()
print("--"*20)
Foo.static_method() """
執行結果:
----------------------------------------例項方法測試----------------------------------------
是類<class '__main__.Foo'>的例項方法,只能被例項物件呼叫
產生了一個<dog>例項,共有<1>個例項物件
----------------------------------------類方法測試----------------------------------------
是類<class '__main__.Foo'>的類方法,可以被例項物件、類物件呼叫
呼叫了靜態方法 static_method_test()
----------------------------------------
是類<class '__main__.Foo'>的類方法,可以被例項物件、類物件呼叫
呼叫了靜態方法 static_method_test()
----------------------------------------靜態方法測試----------------------------------------
是類<class '__main__.Foo'>的靜態方法,可以被例項物件、類物件呼叫
+++以下內容為類方法class_method()的執行結果:
是類<class '__main__.Foo'>的類方法,可以被例項物件、類物件呼叫
呼叫了靜態方法 static_method_test()
----------------------------------------
是類<class '__main__.Foo'>的靜態方法,可以被例項物件、類物件呼叫
+++以下內容為類方法class_method()的執行結果:
是類<class '__main__.Foo'>的類方法,可以被例項物件、類物件呼叫
呼叫了靜態方法 static_method_test()
"""

  從案例1中得到,類方法與靜態方法可以相互呼叫,但是靜態方法只能用【類名】表示,而類方法用【cls】就比較方便了。

案例2:例項方法、類方法、靜態方法在繼承中(子類重寫父類中的方法)的使用

class Foo(object):
X = 1
Y = 14 @staticmethod
def average(*mixes):
print("父類中的靜態方法 average(*mixes)")
print("*****", mixes)
return sum(mixes) / len(mixes) @staticmethod
def static_method():
print("父類中的靜態方法 static_method()")
return Foo.average(Foo.X, Foo.Y) # 注:因為這兒已經限定了只允許呼叫父類中的average() @classmethod
def class_method(cls): # 父類中的類方法
print("父類中的類方法 class_method(cls)")
return cls.average(cls.X, cls.Y) # 注:若用子類物件呼叫該函式,此時的cls==Son,故呼叫子類重寫後的average() class Son(Foo):
@staticmethod
def average(*mixes): # "子類中過載了父類的靜態方法"
print("子類中過載了父類的靜態方法 average(*mixes)")
print("*****", mixes)
return sum(mixes) / len(mixes) print(Son.average(1, 2, 3), "\n" + "---" * 20)
print(Son.class_method(), "\n" + "---" * 20)
print(Son.static_method(), "\n" + "---" * 20) """
執行結果:
------------------------------------------------------------
子類中過載了父類的靜態方法 average(*mixes)
***** (1, 2, 3)
2.0
------------------------------------------------------------
父類中的類方法 class_method(cls)
子類中過載了父類的靜態方法 average(*mixes)
***** (1, 14)
7.5
------------------------------------------------------------
父類中的靜態方法 static_method()
父類中的靜態方法 average(*mixes)
***** (1, 14)
7.5
------------------------------------------------------------
"""

  從案例2中得到,子類物件呼叫父類中的 類方法class_method(cls) 時,由於【cls】此時為【Son】,故會執行子類中的類方法、靜態方法、靜態屬性;進一步推斷出,類方法中【cls】取決於類方法的呼叫者,只有發生類方法呼叫後才能知道執行結果。而父類中靜態方法static_method()只能呼叫父類中類方法、靜態方法、靜態屬性,與靜態方法的呼叫者無關;進一步推斷,靜態方法可以提前預知程式的執行結果,如執行當前類中的某個類方法或靜態方法。

  對案例2做一個多型測試,新增程式碼如下:

def test_polymorphic(foo):
"""
多型測試
:param foo: 父類物件
:return: None
"""
print(f.average(1, 2, 3)) f = Foo()
test_polymorphic(f) print("----"*10)
f = Son() # 會觸發多型
test_polymorphic(f) """
父類中的靜態方法 average(*mixes)
***** (1, 2, 3)
2.0
----------------------------------------
子類中過載了父類的靜態方法 average(*mixes)
***** (1, 2, 3)
2.0
"""

  繼續做多型測試,新增程式碼如下:

def test_polymorphic(foo):
"""
多型測試
:param foo: 父類物件
:return: None
"""
print(f.class_method()) f = Foo()
test_polymorphic(f) print("----"*10)
f = Son() # 會觸發多型
test_polymorphic(f) """
父類中的類方法 class_method(cls)
父類中的靜態方法 average(*mixes)
***** (1, 14)
7.5
----------------------------------------
父類中的類方法 class_method(cls)
子類中過載了父類的靜態方法 average(*mixes)
***** (1, 14)
7.5
"""

案例3:使用類方法或靜態方法初始化類(可以自定義類的初始方式)

class Book(object):
def __init__(self, title):
self.__title = title @classmethod
def object_create_by_class_method(cls, title_list):
"""
使用生產器例項化多個物件
:param title_list: 每個物件的初始化引數,List
:return:迭代器,每個例項化物件
"""
for title in title_list:
yield cls(title=title) @staticmethod
def object_create_by_static_method(title_list): # 功能與類方法一樣
for title in title_list:
yield Book(title=title) @property
def title(self):
return self.__title @title.setter
def title(self, value):
if not isinstance(value, str):
raise TypeError('%s must be str' % value)
self.__title = value @title.deleter
def title(self):
del self.__title
# raise TypeError('Can not delete') books = ["Chinese", "mathematics", "English"]
g_books = Book.object_create_by_class_method(books)
print(g_books) # <generator object Book.object_create_by_class_method at 0x000001FB72AFEEC8> print(g_books.__next__().title) # 檢視書的title -- Chinese
print(g_books.__next__().title) # 檢視書的title -- mathematics book = g_books.__next__() # 得到一個例項化物件 print(book.title) # 檢視書的title -- English
print(book.__dict__) # {'_Book__title': 'English'} book.title = "英語" # 修改屬性
print(book.title) # 檢視書的title -- 英語
print(book.__dict__) # {'_Book__title': '英語'} del book.title # 刪除屬性
print(book.__dict__) # {}

  從案例3中得到,使用類方法或者靜態方法可以自定義類的初始化方式,本案例中實現的功能是使用生產器批量建立多個物件。同時,案列中使用了【property】屬性,property的作用相當於執行了某個函式,並獲得該函式的返回值;其使用方式有3種,分別為【@property --- get】、【@函式名.setter --- set】、【@函式名.deleter --- del】,後二種必須在第一種使用的情況下才能使用,在表現形式上就是通過例項化物件間接訪問屬性。

  最後,我們對案例3做微小改變,來看看例項方法、類方法、靜態方法與類、物件之間的關係,程式碼如下:

class Book(object):
@classmethod
def object_create_by_class_method(cls):
pass @staticmethod
def object_create_by_static_method():
pass def instance_method(self):
pass book = Book()
print(book.instance_method) # 方法(繫結到物件:發生呼叫時,將【例項物件=self】自動作為第一個引數傳入例項方法中)
print(book.object_create_by_class_method) # 方法(繫結到類:發生呼叫時,將【類=cls】自動作為第一個引數傳入類方法中)
print(book.object_create_by_static_method) # 普通函式(非繫結:發生呼叫時,不需要傳入任何引數,如self,cls) print(Book.instance_method) # 普通函式(非繫結,因為例項方法就儲存在類的名稱空間中)
print(Book.object_create_by_class_method) # 繫結到類
print(Book.object_create_by_static_method) # 普通函式(非繫結)
"""
<bound method Book.instance_method of <__main__.Book object at 0x000002481CEDE988>>
<bound method Book.object_create_by_class_method of <class '__main__.Book'>>
<function Book.object_create_by_static_method at 0x000002481D12C828> <function Book.instance_method at 0x000002481D12C8B8>
<bound method Book.object_create_by_class_method of <class '__main__.Book'>>
<function Book.object_create_by_static_method at 0x000002481D12C828>
"""

  可以發現,

    1)類中的例項方法都綁定了例項物件,故建議使用例項物件呼叫例項方法;

    2)類中的類方法都綁定了類,故建議使用類物件呼叫類方法,即使使用例項物件呼叫類方法,仍然自動將【類名】作為第一個引數傳入類方法。

    3)而對於靜態方法而言,無論使用例項物件或者類物件呼叫其方法都不會自動進行引數傳遞,故不做限制。

    4)若能用類解決的問題,就將類中的方法定義為類方法,這樣可以避免例項化物件的開銷。

繫結與非繫結的參考連結:

https://www.cnblogs.com/MrYang161/p/11431725.html

http://cda.pinggu.org/view/23514.html