Python - 物件導向程式設計 - 例項方法、靜態方法、類方法

小菠蘿測試筆記 發表於 2021-08-29
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

Python - 物件導向程式設計 - 例項方法、靜態方法、類方法

 

類方法

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

 

相似點

  • 也至少要包含一個引數,不過通常命名為 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 變數可以嗎

肯定不行,報錯

Python - 物件導向程式設計 - 例項方法、靜態方法、類方法

 

擴充套件思考題!

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

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

 

靜態方法

  • 和之前學過的函式一毛一樣,唯一區別是:靜態方法需要定義在類體中,且需要新增 @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 的實際應用場景

可以參考這篇文章

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

https://www.zhihu.com/question/20021164