Python – 面向對象編程 – 實例方法、靜態方法、類方法

實例方法

在類中定義的方法默認都是實例方法,前面幾篇文章已經大量使用到實例方法

 

實例方法栗子

class PoloBlog:
    def __init__(self, name, age):
        print("自動調用構造方法")
        self.name = name
        self.age = age

    def test(self):
        print("一個實例方法,需要通過對象調用")
        print("my name is :", self.name, " and my age is :", self.age)


blog = PoloBlog("小菠蘿", 24)
blog.test()


# 輸出結果
自動調用構造方法
一個實例方法,需要通過對象調用
my name is : 小菠蘿  and my age is : 24 
  • 最少也要包含一個 self 參數,用於綁定調用此方法的實例對象(Python 會自動完成綁定)
  • 實例方法通常會用實例對象直接調用

 

通過類名調用實例方法

Python 也支援通過類名調用實例方法,但需要手動給 self 參數傳實例對象

blog = PoloBlog("小菠蘿", 24)

PoloBlog.test(blog)


# 輸出結果
自動調用構造方法
一個實例方法,需要通過對象調用
my name is : 小菠蘿  and my age is : 24

 

假設不傳實例對象,pycharm 會有warning

 

類方法

類方法和實例方法很相似,又很不相似

 

相似點

  • 也至少要包含一個參數,不過通常命名為 cls
  • 在調用類方法時,無需顯式為 cls 參數傳參,但傳遞的並不是實例對象,而是類對象本身

 

不同點

最大的不同在於需要使用 @classmethod 裝飾器才能稱為類方法

 

實際栗子

class PoloBlog:
    # 類屬性
    sum = 0

    # 類方法, 添加裝飾器
    @classmethod
    def class_func(cls):
        print("class_func cls 對象的 id ", id(cls))
        cls.sum += 1
        print("類屬性 sum ", cls.sum)

    @classmethod
    def class_func_twi(cls):
        print("class_func_twi cls 對象的 id ", id(cls))
        cls.sum += 1
        print("類屬性 sum ", cls.sum)


PoloBlog.class_func()
PoloBlog.class_func_twi()


# 輸出結果
class_func cls 對象的 id  140583542774880
類屬性 sum  1
class_func_twi cls 對象的 id  140583542774880
類屬性 sum  

cls 代表的是同一個對象,類對象

 

類方法可以調用實例方法嗎?

可以,但有局限性

class PoloBlog:
    # 類屬性
    sum = 0

    def __init__(self, sum):
        self.sum = sum

    # 實例方法
    def test(self):
        print("self id is ",id(self))
        print("self 對象的 sum 屬性值為:", self.sum)

    # 類方法, 添加裝飾器
    @classmethod
    def class_func(cls):
        print("cls id is ", id(cls))
        print("類屬性 sum ", cls.sum)
        # 調用實例方法
        cls.test(cls)


PoloBlog.class_func()


# 輸出結果
cls id is  140500501817184
類屬性 sum  0
self id is  140500501817184
self 對象的 sum 屬性值為: 0
  • 類方法調用實例方法的方式: cls.實例方法(cls) ,通過 cls 調用,且還要傳遞 cls 為參數
  • 從 id 相同即可看出,實例方法接收的仍然是一個類對象

 

實例對象可以調用類方法嗎?

可以,但不建議

blog = PoloBlog(2)
blog.class_func()


# 輸出結果
cls id is  140500501817184
類屬性 sum  0
self id is  140500501817184
self 對象的 sum 屬性值為: 0 
  • blog 是一個實例對象,且初始化賦值了 sum 實例屬性
  • 但最後實例方法列印的仍然是 sum 類屬性,表明類方法無法訪問實例屬性
  • 且 cls、self 參數的 id 和上面的栗子完全一樣,表明即使通過實例對象調用類方法,傳遞的仍然是類對象的引用,所有類方法都被同一個類對象調用,一個類只有一個類對象

 

實例方法可以調用類屬性嗎?

可以,但不能通過實例對象調用,只能通過類對象

class PoloBlog:
    # 類屬性
    name = "類啊類屬性"

    def __init__(self, name):
        self.name = name

    # 實例方法
    def test(self):
        # 錯誤栗子
        # print(name)

        # 訪問的仍然是實例屬性
        print(self.name)

        # 通過類名訪問
        print(PoloBlog.name)


blog = PoloBlog("小菠蘿")
blog.test()


# 輸出結果
小菠蘿
類啊類屬性

 

假設直接調用 name 變數可以嗎

肯定不行,報錯

 

擴展思考題!

  • 一個方法內部既需要訪問實例屬性,又需要訪問類屬性,應該定義為什麼方法?
  • 答案:實例方法,因為可以通過 類對象.類屬性 來訪問,但在類方法中無法訪問實例屬性

程式碼栗子直接看上面一個就是啦!

 

靜態方法

  • 和之前學過的函數一毛一樣,唯一區別是:靜態方法需要定義在類體中,且需要添加 @staticmethod 裝飾器
  • 靜態方法沒有 self、cls 參數,也不需要至少傳一個參數,和普通函數一樣
  • Python 解釋器不會對它包含的參數做任何類或對象的綁定,所以靜態方法無法調用任何類屬性、類方法、實例屬性、實例方法,除非通過類名和實例對象
class PoloBlog:

    # 靜態方法
    @staticmethod
    def info(name, age):
        print(name, age)


# 通過類對象調用
PoloBlog.info("小菠蘿111", 24)

blog = PoloBlog()
# 通過實例對象調用
blog.info("小菠蘿222", 14)


# 輸出結果      
小菠蘿111 24
小菠蘿222 14

 

關於 classmethod 和 staticmethod 的實際應用場景

可以參考這篇文章

待我實戰後再來完善此章節

//www.zhihu.com/question/20021164