如何吃透Python的物件導向(OOP)

kele是可樂呀發表於2021-02-26

​本篇可樂和大家一起來吃透 Python 的物件導向,類和例項

物件導向(OOP)

解釋:物件導向它是一種程式設計的思想,將現實事物抽象化為程式設計物件。
舉例說明:喝可樂
① 選擇自己根據配方買對應的材料然後製作可樂,最後喝可樂。
② 自己去小賣部直接買可樂喝。
第一種屬於程式導向(對應到程式設計當中,也就是每一個步驟都需要一步一步實現)
第二種就是物件導向,我們並不需要知道每一步是如何實現的,只需要知道最後能夠喝可樂即可。

一、類

解釋:類是物件導向的重要組成部分,類是對相同特徵和行為事物的統稱,是一個抽象的概念。

✔ 語法

class 類名:
實際程式碼

✔ 舉例:以人為例子

# 人有眼睛,鼻子,嘴巴這些特徵。可以玩電腦,走路這些行為。
# 程式碼如下:
class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def play_computer(self):
        print("我會玩電腦")
​
    def walk(self):
        print("我會走路")
​
# self:下面會細講,並用程式碼演示

二、物件

解釋:物件是類建立出來真實存在的事物,物件又可以稱為例項。

✔ 語法

物件名 = 類名()

✔ 舉例:以上述人為例子

人是一個抽象的概念,並不能代表實實在在的事物,但是可樂和在座的各位同學都是實際存在的事物,我們都屬於人。

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def play_computer(self):
        print("我會玩電腦")
​
    def walk(self):
        print("我會走路")
        
# 建立 kele 物件
kele = Person()

2.1 呼叫物件方法

✔ 語法

物件.方法名(引數)

✔ 舉例

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def play_computer(self):
        print("我會玩電腦")
​
    def walk(self):
        print("我會走路")
​
# 建立 kele 物件
kele = Person()
kele.play_computer()
​
# 輸出 我會玩電腦

✔ 解釋例項方法中的 self 是什麼

先上程式碼

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def play_computer(self):
        print("我會玩電腦")
​
    def eye(self):
        print(self.eyes)
        self.eyes = "卡茲然大眼睛"
        print(self.eyes)
​
​
kele = Person()
kele.eye()
​
# 輸出結果是 眼睛  卡茲然大眼睛
​
​
class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def play_computer(self):
        print("我會玩電腦")
​
    def eye(self):
        pass
​
​
kele = Person()
print(kele.eyes)
kele.eyes = "卡茲然大眼睛"
print(kele.eyes)
​
# 輸出 眼睛  卡茲然大眼睛

到這裡可能有一部分同學已經明白 self 實際上是個什麼東東了,為了更加通俗易懂,可樂再舉一個例子:

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def play_computer(self):
        print(f"self是{self}")
​
kele = Person()
kele.play_computer()
print(f"kele是{kele}")

結果:

根據上述兩個示例,我們可以知道 self 實際上就是類建立出來的例項物件。

❗ 物件在呼叫方法的時候不需要手動傳 self 值,因為 python 直譯器會自動將例項引用傳遞給 self 。

2.2 獲取物件屬性

解釋:屬性就是特徵。例如:人的手,人的鼻子,人的身高,人的體重。

✔ 語法

① 物件名.屬性名 (這種在類外部使用)
② self.屬性名 (這種在類內部使用)

✔ 舉例1:還是以人為例子

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def play_computer(self):
        print(f"self是{self}")
​
​
kele = Person()
print(kele.nose)
​
# 輸出 鼻子

✔ 舉例2

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def get_nose(self):
        print(self.nose)
​
​
kele = Person()
kele.get_nose()
​
# 輸出  鼻子

2.3 修改/設定物件屬性

✔ 語法

① 物件名.屬性名 = 值 (這種在類外部使用)
② self.屬性名 = 值 (這種在類內部使用)

✔ 舉例1:依舊以人為例子

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def play_computer(self):
        print(f"self是{self}")
​
​
kele = Person()
kele.nose = "卡茲然大鼻子"
print(kele.nose)
​
# 輸出  卡茲然大鼻子

✔ 舉例2

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
    def modify_nose(self):
        self.nose = "卡茲然大鼻子"
​
​
kele = Person()
kele.modify_nose()
print(kele.nose)
​
# 輸出  卡茲然大鼻子

2.4 魔法方法

解釋:所謂的魔法方法也就是 python 內部已經提供的方法,他們的表現形式是 xxx 。

2.4.1 魔法方法 init

解釋 init 方法它是用於物件生成之後進行初始化的函式,不需要程式設計師手動呼叫,python 直譯器會在物件建立之後自動呼叫。
例如:人與生俱來就有嘴巴,鼻子,眼睛。那麼我們在構造類的時候,就可以將這些屬性放進 init 方法中。

✔ 舉例

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
        print(self.eyes)
​
​
kele = Person()
​
# 輸出 眼睛

❗ 他並不需要程式設計師手動呼叫。

2.4.2 魔法方法 new

解釋:我們之前一直在說物件是由類建立出來的,那麼類又是怎麼建立出來的呢?就是通過 new 方法,這個方法的功能就是建立物件。

✔ 如何通過 new 方法實現單例

解釋:所謂的單例就是一個類建立出來的物件都是相同的。

在預設情況下類建立出來的各個物件都是不一樣的,如果我們想一個類建立出來的物件都是一樣的,那該怎麼做呢?答案就是通過 new 方法。

✔ 類建立不同的物件程式碼

class Person:
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
​
kele1 = Person()
kele2 = Person()
print(kele1)
print(kele2)

結果如圖:

✔ 單例程式碼

class Person:
    instance = None
​
    def __new__(cls, *args, **kwargs):
        if not cls.instance:
            cls.instance = super(Person, cls).__new__(cls, *args, **kwargs)
        return cls.instance
​
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"
​
​
kele1 = Person()
kele2 = Person()
print(kele1)
print(kele2)

先貼出結果:

解釋一下程式碼:

具體程式碼在下面講解完繼承,類屬性,類方法之後就知道什麼含義了,可樂先講一下程式碼的大致意思:用變數 instance 儲存物件的記憶體地址,開始時只為 None ,當第一個物件建立之後,將該記憶體地址賦值給 instance 變數,後續的物件建立時判斷變數 instance 是否有值了。如果有,那麼將之前的物件地址給新物件。這樣就保證了,後續的物件都和第一個物件的記憶體地址一樣,即該類建立出來的物件都是同一個。

2.5 類屬性

解釋:類物件所擁有的屬性,該類建立出來的所有物件共享同一個類屬性,類屬性在記憶體中只會有一個副本。

✔ 使用場景

如果在一個類中所有的物件都有一個共同的屬性,並且這個屬性的值是一樣的,那麼我們就可以將屬性設定為類屬性,如果這個屬性的值每個物件都有其自己的含義,那麼我們可以將其定義為例項屬性。

✔ 語法

在類裡面 屬性名 = 值

✔ 舉例

class Person:
    nose = "鼻子"
​
    def __init__(self, name):
        self.name = name
​
​
kele1 = Person("可樂1號")
kele2 = Person("可樂2號")

2.5.1 獲取類屬性

✔ 語法

① cls.屬性名 (在類裡面)
② 類.屬性名 (在類外面)
③ 例項.屬性名 (在類外面)

✔ 舉例

class Person:
    nose = "鼻子"
​
kele = Person()
​
print(kele.nose)
print(Person.nose)
​
# 輸出 鼻子 鼻子

2.5.2 修改類屬性的值

✔ 語法

① cls.屬性名 = 值 (在類裡面)
② 類.屬性名 = 值 (在類外面)

❗ 不可用例項.屬性名 = 值來修改,這個含義代表新增例項屬性。

✔ 舉例

class Person:
    nose = "鼻子"
​
Person.nose = "卡自然大鼻子"
print(Person.nose)
​
# 輸出 卡自然大鼻子

2.6 類方法

解釋:類方法是類物件所擁有的方法,用 @classmethod 來對方法進行修飾。

✔ 使用場景

類方法一般搭配類屬性來使用,常常用於對類屬性的修改。

✔ 語法

@classmethod
def 類方法名(cls):

✔ 舉例

class Person:
    nose = "鼻子"
​
    @classmethod
    def add(cls):
        pass

2.6.1 呼叫類方法

✔ 語法

① 類.類方法名 (在類外面)
② 例項.類方法名 (在類外面)
③ cls.類方法名 (在類裡面)

✔ 舉例1

class Person:
    nose = "鼻子"
​
    @classmethod
    def add(cls, nose):
        cls.nose = nose
​
    @classmethod
    def update(cls):
        cls.add("卡自然大鼻子")
​
​
Person.update()
print(Person.nose)
​
# 輸出 卡自然大鼻子

✔ 舉例2

class Person:
    nose = "鼻子"
​
    @classmethod
    def update(cls):
        cls.nose = "卡自然大鼻子"
​
​
Person.update()
print(Person.nose)
​
# 輸出 卡自然大鼻子

✔ 舉例3

class Person:
    nose = "鼻子"
​
    @classmethod
    def update(cls):
        cls.nose = "卡自然大鼻子"
​
kele = Person()
kele.update()
print(kele.nose)
​
# 輸出 卡自然大鼻子

2.7 靜態方法

解釋:靜態方法可以理解為就是普通的函式,只不過他的作用域限制於類裡面,但是和類和例項本身並沒有多大的關係,他通過 @staticmethod 來修飾。

✔ 使用場景

如果想定義一個函式,但是該函式和類本身或者例項物件沒有多大關係,但是限制於該類中就可以使用靜態方法來定義。

✔ 舉例

class Person:
    @staticmethod
    def play_game():
        print("可樂打遊戲")
​
kele = Person()
kele.play_game()
​
# 輸出 可樂打遊戲

三、物件導向三大特性

特性:封裝,繼承,多型。

3.1 封裝

解釋:將程式碼寫到類裡面即是封裝,並且封裝還可以給屬性或者方法設定許可權。在上述程式碼中已經使用了封裝的特性。

3.2 繼承

解釋:指的是類當中的從屬關係,子類自動擁有父類所有的屬性和方法。

❗ 所有的類都預設繼承Object類。

3.2.1 單繼承

單繼承:只繼承一個父類。

✔ 舉例

class Father:
​
    def __init__(self):
        self.name = "可樂家族"
​
    def get_name(self):
        print(self.name)
​
​
class Son(Father):
    pass
​
​
son = Son()
son.get_name()
​
# 輸出 可樂家族

3.2.2 多繼承

多繼承:子類同時繼承多個父類。

✔ 舉例1

class Father:
​
    def __init__(self):
        self.name = "可樂家族"
​
    def get_name(self):
        print(self.name)
​
​
class Mother:
​
    def __init__(self):
        self.name = "媽媽家族"
​
    def get_name(self):
        print(self.name)
​
    def add_nose(self):
        self.nose = "鼻子"
​
​
class Son(Mother, Father):
    pass
​
​
son = Son()
son.get_name()
​
# 輸出 媽媽家族

✔ 舉例2

class Father:
​
    def __init__(self):
        self.name = "可樂家族"
​
    def get_name(self):
        print(self.name)
​
​
class Mother:
​
    def __init__(self):
        self.name = "媽媽家族"
​
    def get_name(self):
        print(self.name)
​
    def add_nose(self):
        self.nose = "鼻子"
​
​
class Son(Father, Mother):
    pass
​
​
son = Son()
son.get_name()
​
# 輸出 可樂家族

❗ 如果繼承的父類當中擁有相同的屬性或者方法,那麼優先繼承第一個父類的屬性和方法。

3.2.3 mro確認繼承順序

繼承順序:如果一個類繼承多個父類,並且繼承關係比較複雜,那麼我們可以使用內建方法 mro 來確定繼承順序。

✔ 舉例

class Father:
​
    def __init__(self):
        self.name = "可樂家族"
​
    def get_name(self):
        print(self.name)
​
​
class Mother:
​
    def __init__(self):
        self.name = "媽媽家族"
​
    def get_name(self):
        print(self.name)
​
    def add_nose(self):
        self.nose = "鼻子"
​
​
class Son(Mother, Father):
    pass
​
​
print(Son.__mro__)

結果如圖:
3.2.4 重寫父類的方法

繼承中,支援子類對父類的方法進行重寫。

✔ 舉例

class Father:
​
    def __init__(self):
        self.name = "可樂家族"
​
    def get_name(self):
        print(self.name)
​
​
class Mother:
​
    def __init__(self):
        self.name = "媽媽家族"
​
    def get_name(self):
        print(self.name)
​
    def add_nose(self):
        self.nose = "鼻子"
​
​
class Son(Mother, Father):
​
    def get_name(self):
        print("子類重新方法")
​
​
son = Son()
son.get_name()
​
# 輸出 子類重新方法

3.2.5 繼承之super

super:子類重寫父類方法,但是還需要呼叫父類的其他方法或同名方法時,使用 super 可以不用關心繼承的是哪個父類,在語法上只需要填寫子類類名即可。

✔ 舉例1

class Father:
​
    def __init__(self):
        self.name = "可樂家族"
​
    def get_name(self):
        print(self.name)
​
​
class Mother:
​
    def __init__(self):
        self.name = "媽媽家族"
​
    def get_name(self):
        print(self.name)
​
    def add_nose(self):
        self.nose = "鼻子"
​
​
class Son(Mother, Father):
​
    def get_name(self):
        print("子類重新方法")
        Mother.get_name(self)
        Father.__init__(self)
        Father.get_name(self)
​
​
son = Son()
son.get_name()
​
# 輸出 子類重新方法  媽媽家族  可樂家族

✔ 舉例2

class Father:
​
    def __init__(self):
        self.name = "可樂家族"
​
    def get_name(self):
        print(self.name)
​
​
class Mother:
​
    def __init__(self):
        self.name = "媽媽家族"
​
    def get_name(self):
        print(self.name)
        super(Mother, self).__init__()
        super(Mother, self).get_name()
​
    def add_nose(self):
        self.nose = "鼻子"
​
​
class Son(Mother, Father):
​
    def get_name(self):
        print("子類重新方法")
        super(Son, self).get_name()
​
​
son = Son()
son.get_name()
​
# 輸出 子類重新方法 媽媽家族 可樂家族

❗ super 會自動查詢父類,且順序遵循__mro__順序,適合單繼承使用;
❗ super 只能繼承最近的上一級父類,順序按照__mro__順序。

3.3 多型

解釋:不同的物件,有不同的結果,子類重寫父類的方法,並且呼叫不同的子類的相同父類方法,有不同的結果。

我們先上程式碼來看:

class Person:
​
    def get_sex(self):
        print("人")
​
​
class Man(Person):
​
    def get_sex(self):
        print("男人")
​
​
class Women(Person):
​
    def get_sex(self):
        print("女人")
​
​
man = Man()
women = Women()
man.get_sex()
women.get_sex()
​
# 輸出 男人  女人

程式碼解釋:

一個 Person 類中有一個父類公共方法 get_sex ,子類 man 和 women 通過重寫父類方法,產生不同的效果,這就是多型。那麼多型有什麼好處呢?多型可以使得程式碼變得更加靈活,更通用,適應的業務場景多。

到此,我們在本篇中學習了 python 物件導向。各位同學在學習過程中遇到疑問可以私聊可樂,可樂看到了都會一一回復的。那麼下一篇可樂將和大家看一下閉包,裝飾器和深拷貝,淺拷貝。謝謝大家的支援~~~


< END>

在這裡插入圖片描述

相關文章