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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM