1. 程式人生 > >面向對象(一)

面向對象(一)

實現 指定 per 賦值語句 assm 開發 ret init 類的方法

類是對一群具有相同 特征或者 行為的事物的一個統稱,是抽象的,不能直接使用

1)特征 被稱為 屬性(變量)

2)行為 被稱為 方法(函數)

案例改造 —— 給對象增加屬性

  • Python 中,要 給對象設置屬性,非常的容易,但是不推薦使用只需要在 類的外部的代碼 中直接通過 . 設置一個屬性即可
    • 因為:對象屬性的封裝應該封裝在類的內部

註意:這種方式雖然簡單,但是不推薦使用!

tom.name = "Tom"
...

lazy_cat.name = "大懶貓"

__del__ 方法(知道)

  • Python

    • 當使用 類名() 創建對象時,為對象 分配完空間
      後,自動 調用 __init__ 方法
    • 當一個 對象被從內存中銷毀 前,會 自動 調用 __del__ 方法
  • 應用場景

    • __init__ 改造初始化方法,可以讓創建對象更加靈活
    • __del__ 如果希望在對象被銷毀前,再做一些事情,可以考慮一下 __del__ 方法
  • 生命周期

    • 一個對象從調用 類名() 創建,生命周期開始
    • 一個對象的 __del__ 方法一旦被調用,生命周期結束
    • 在對象的生命周期內,可以訪問對象屬性,或者讓對象調用方法


class Cat:

    def __init__(self, new_name):

        self.name = new_name

        print("%s 來了" % self.name)

    def __del__(self):

        print("%s 去了" % self.name)

# tom 是一個全局變量
tom = Cat("Tom")
print(tom.name)

# del 關鍵字可以刪除一個對象
del tom

print("-" * 50)

__str__ 方法

  • Python 中,使用 print 輸出 對象變量,默認情況下,會輸出這個變量 引用的對象由哪一個類創建的對象,以及 在內存中的地址十六進制表示
  • 如果在開發中,希望使用 print 輸出 對象變量 時,能夠打印 自定義的內容,就可以利用 __str__ 這個內置方法了

註意:__str__ 方法必須返回一個字符串

class Cat:

    def __init__(self, new_name):

        self.name = new_name

        print("%s 來了" % self.name)

    def __del__(self):

        print("%s 去了" % self.name)

    def __str__(self):
        return "我是小貓:%s" % self.name

tom = Cat("Tom")
print(tom)

身份運算符

身份運算符用於 比較 兩個對象的 內存地址 是否一致 —— 是否是對同一個對象的引用

  • Python 中針對 None 比較時,建議使用 is 判斷
運算符描述實例
is is 是判斷兩個標識符是不是引用同一個對象 x is y,類似 id(x) == id(y)
is not is not 是判斷兩個標識符是不是引用不同對象 x is not y,類似 id(a) != id(b)

is 與 == 區別:

is 用於判斷 兩個變量 引用對象是否為同一個
== 用於判斷 引用變量的值 是否相等

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> b is a 
False
>>> b == a
True

面向對象三大特性

  1. 封裝 根據 職責屬性方法 封裝 到一個抽象的
  2. 繼承 實現代碼的重用,相同的代碼不需要重復的編寫
  3. 多態 不同的對象調用相同的方法,產生不同的執行結果,增加代碼的靈活度(繼承重寫父類方法 為前提

專業術語

  • Dog 類是 Animal 類的子類Animal 類是 Dog 類的父類Dog 類從 Animal繼承
  • Dog 類是 Animal 類的派生類Animal 類是 Dog 類的基類Dog 類從 Animal派生

對父類方法進行 擴展

  • 如果在開發中,子類的方法實現包含 父類的方法實現
    • 父類原本封裝的方法實現子類方法的一部分
  • 就可以使用 擴展 的方式
    1. 在子類中 重寫 父類的方法
    2. 在需要的位置使用 super().父類方法 來調用父類方法的執行
    3. 代碼其他的位置針對子類的需求,編寫 子類特有的代碼實現
關於 super
  • Pythonsuper 是一個 特殊的類
  • super() 就是使用 super 類創建出來的對象
  • 最常 使用的場景就是在 重寫父類方法時,調用 在父類中封裝的方法實現

父類的 私有屬性 和 私有方法

  1. 子類對象 不能 在自己的方法內部,直接 訪問 父類的 私有屬性私有方法
  2. 子類對象 可以通過 父類公有方法 間接 訪問到 私有屬性私有方法
  • 私有屬性、方法 是對象的隱私,不對外公開,外界 以及 子類 都不能直接訪問
  • 私有屬性、方法 通常用於做一些內部的事情

多繼承的使用註意事項

問題的提出

  • 如果 不同的父類 中存在 同名的方法子類對象 在調用方法時,會調用 哪一個父類中的方法呢?
  • (答:繼承的父類哪個在前面,就先調用它的方法)

提示:開發時,應該盡量避免這種容易產生混淆的情況! —— 如果 父類之間 存在 同名的屬性或者方法,應該 盡量避免 使用多繼承

Python 中的 MRO —— 方法搜索順序(知道)

  • Python 中針對 提供了一個 內置屬性 __mro__ 可以查看 方法 搜索順序
  • MRO 是 method resolution order,主要用於 在多繼承時判斷 方法、屬性 的調用 路徑
print(C.__mro__)

輸出結果

(<class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘object‘>)
  • 在搜索方法時,是按照 __mro__ 的輸出結果 從左至右 的順序查找的
  • 如果在當前類中 找到方法,就直接執行,不再搜索
  • 如果 沒有找到,就查找下一個類 中是否有對應的方法,如果找到,就直接執行,不再搜索
  • 如果找到最後一個類,還沒有找到方法,程序報錯

新式類與舊式(經典)類

objectPython 為所有對象提供的 基類,提供有一些內置的屬性和方法,可以使用 dir 函數查看

  • 新式類:以 object 為基類的類,推薦使用
  • 經典類:不以 object 為基類的類,不推薦使用

  • Python 3.x 中定義類時,如果沒有指定父類,會 默認使用 object 作為該類的 基類 —— Python 3.x 中定義的類都是 新式類

  • Python 2.x 中定義類時,如果沒有指定父類,則不會以 object 作為 基類

新式類經典類 在多繼承時 —— 會影響到方法的搜索順序

為了保證編寫的代碼能夠同時在 Python 2.xPython 3.x 運行!
今後在定義類時,如果沒有父類,建議統一繼承自 object

class 類名(object):
    pass

創建類的實例之後,內存中會開辟一塊空間,保存的是這個實例對象還有實例屬性,實例方法卻是引用類裏面的實例方法。  

要訪問類屬性有兩種方式:

  • 類名.類屬性
  • 對象.類屬性 (不推薦)(向上查找原則)

註意,如果使用 對象.類屬性 = 值 賦值語句,只會 給對象添加一個屬性,而不會影響到 類屬性的值

類方法

  • 類屬性 就是針對 類對象 定義的屬性
    • 使用 賦值語句class 關鍵字下方可以定義 類屬性
    • 類屬性 用於記錄 與這個類相關 的特征
  • 類方法 就是針對 類對象 定義的方法
    • 類方法 內部可以直接訪問 類屬性 或者調用其他的 類方法

語法如下

@classmethod
def 類方法名(cls):
    pass
  • 類方法需要用 修飾器 @classmethod 來標識,告訴解釋器這是一個類方法
  • 類方法的 第一個參數 應該是 cls
    • 哪一個類 調用的方法,方法內的 cls 就是 哪一個類的引用
    • 這個參數和 實例方法 的第一個參數是 self 類似
    • 提示 使用其他名稱也可以,不過習慣使用 cls
  • 通過 類名. 調用 類方法調用方法時,不需要傳遞 cls 參數
  • 在方法內部
    • 可以通過 cls. 訪問類的屬性
    • 也可以通過 cls. 調用其他的類方法

靜態方法

  • 在開發時,如果需要在 中封裝一個方法,這個方法:

    • 不需要 訪問 實例屬性 或者調用 實例方法
    • 不需要 訪問 類屬性 或者調用 類方法
  • 這個時候,可以把這個方法封裝成一個 靜態方法

語法如下 

@staticmethod
def 靜態方法名():
    pass

通過 類名. 調用 靜態方法

提問

如果方法內部 即需要訪問 實例屬性,又需要訪問 類屬性,應該定義成什麽方法?

答案

  • 應該定義 實例方法
  • 因為,類只有一個,在 實例方法 內部可以使用 類名. 訪問類屬性

 

面向對象(一)