面向對象編程(Python版詳解)

python版,面向對象編程分三篇給大家介紹,這是第一篇,歡迎閱讀學習,一起進步




一.面向對象編程介紹

  • 如今主流的軟件開發思想有兩種:一個是面向過程,另一個是面向對象。面向過程出現得較早,典型代表爲C語言,開發中小型項目的效率很高,但是很難適用於如今主流的大中型項目開發場景。面向對象則出現得更晚一些,典型代表爲Java或C++等語言,更加適合用於大型開發場景。兩種開發思想各有長短。
  • 對於面向過程的思想: 需要實現一個功能的時候,看重的是開發的步驟和過程,每一個步驟都需要自己親力親爲,需要自己編寫代碼(自己來做)
  • 對於面向對象的思想:當需要實現一個功能的時候,看重的並不是過程和步驟,而是關心誰幫我做這件事(偷懶,找人幫我做)
  • 面向對象的三大特徵有:封裝性、繼承性、多態性。

生活舉例

  • 洗衣服

  • 面向過程(手洗):脫衣服、找一個盆、加水、加洗衣粉、浸泡30分鐘、搓洗、擰衣服、倒掉水、再加水、漂洗、擰衣服、倒掉水、晾衣服。

  • 面向對象(機洗):脫衣服、放入洗衣機、按下開關、拿出衣服晾曬。

  • 買電腦

  • 面向過程(自己買):需要電腦、查詢參數信息、橫向比較機型、瞭解打折信息、與店家討價還價、下單、收快遞、開機驗貨、確認收貨。

  • 面向對象(找人買):需要電腦、找祕書幫我買、收電腦。


二.類和對象

面向對象編程的2個非常重要的概念:類和對象

  • 對象是面向對象編程的核心,在使用對象的過程中,爲了將具有共同特徵和行爲的一組對象抽象定義,提出了另外一個新的概念——類
  • 面向對象的語言當中,“類”就是用來模擬現實事物的。
  • 類:抽象的,是一張“手機設計圖”。
  • 對象:具體的,是一個“真正的手機實例”。

在這裏插入圖片描述

  • 小結:類是抽象的,在使用的時候通常會找到這個類的一個具體的存在,使用這個具體的存在。一個類可以找到多個對象。

人以類聚 物以羣分。
具有相似內部狀態和運動規律的實體的集合(或統稱爲抽象)。
具有相同屬性和行爲事物的統稱

  • 類就相當於製造飛機時的圖紙,用它來進行創建的飛機就相當於對象 類是一類事物,對象即是這類事物實現

在這裏插入圖片描述

  • 類中也有屬性、行爲兩個組成部分,而“對象”是類的具體實例
  • 屬性:事物的特徵描述信息,用於描述某個特徵“是什麼”。
  • 行爲:事物的能力行動方案,用於說明事物“能做什麼”。

三.類的構成

  • 類(Class) 由3個部分構成
類的名稱:類名
類的屬性:一組數據
類的方法:允許對進行操作的方法 (行爲)
  • 案例
1)人類設計:

事物名稱(類名):(Person)
屬性:身高(height)、年齡(age)
方法(行爲/功能):(run)、打架(fight)
2)狗類的設計

類名:(Dog)
屬性:品種 、毛色、性別、名字、 腿兒的數量
方法(行爲/功能):叫 、跑、咬人、吃、搖尾巴
  • 類的抽象
  • 如何把日常生活中的事物抽象成程序中的類?
  • 擁有相同(或者類似)屬性和行爲的對象都可以抽像出一個類
  • 方法:一般名詞都是類(名詞提煉法)

案例:坦克發射3顆炮彈轟掉了2架飛機

  • 坦克—可以抽象成類
  • 炮彈—以抽象成類
  • 飛機—可以抽象成類

案例:如下植物大戰殭屍可以抽象爲幾個類

在這裏插入圖片描述

向日葵
類名: xrk
屬性: 顏色
行爲: 放陽光
豌豆
類名: wd
屬性: 顏色 、髮型,血量
行爲:發炮, 搖頭
堅果:
類名:jg
屬性:血量 類型
行爲:阻擋;
殭屍:
類名:js
屬性:顏色、血量、 類型、速度
行爲:走 跑跳 吃 死

四.定義類 和 創建對象

  • 定義一個類,格式如下:
class 類名:
    方法列表
  • demo:定義一個Hero類
# class Hero:  # 經典類(舊式類)定義形式
# class Hero():

class Hero(object):  # 新式類定義形式
    def info(self):
        print("英雄各有見,何必問出處。")
  • 說明:
  • ①定義類時有2種形式:新式類和經典類,上面代碼中的Hero爲新式類,前兩行註釋部分則爲經典類;
  • ②object 是Python 裏所有類的最頂級父類;
  • ③類名 的命名規則按照"大駝峯命名法"
  • ④info 是一個實例方法,第一個參數一般是self,表示實例對象本身,當然了可以將self換爲其它的名字,其作用是一個變量這個變量指向了實例對象

  • python中,可以根據已經定義的類去創建出一個或多個對象。
  • 創建對象的格式爲:
對象名1 = 類名()
對象名2 = 類名()
對象名3 = 類名()
  • 創建對象demo:
class Hero(object):  # 新式類定義形式
    """info 是一個實例方法,類對象可以調用實例方法,實例方法的第一個參數一定是self"""
    def info(self):
        """當對象調用實例方法時,Python會自動將對象本身的引用做爲參數,
            傳遞到實例方法的第一個參數self裏"""
        print(self) 
        print("self各不同,對象是出處。")


# Hero這個類 實例化了一個對象  taidamier(泰達米爾)
taidamier = Hero()

# 對象調用實例方法info(),執行info()裏的代碼
# . 表示選擇屬性或者方法
taidamier.info()

print(taidamier)  # 打印對象,則默認打印對象在內存的地址,結果等同於info裏的print(self)
print(id(taidamier))  # id(taidamier) 則是內存地址的十進制形式表示
<__main__.Hero object at 0x036EB0D0>
self各不同,對象是出處。
<__main__.Hero object at 0x036EB0D0>
57585872
  • 小結:當創建一個對象時,就是用一個模子,來製造一個實物

五.對象屬性獲取

對象既然有實例方法,是否也可以有自己的屬性?

  • 添加和獲取對象的屬性
class Hero(object):
    """定義了一個英雄類,可以移動和攻擊"""
    def move(self):
        """實例方法"""
        print("正在前往事發地點...")

    def attack(self):
        """實例方法"""
        print("發出了一招強力的普通攻擊...")

# 實例化了一個英雄對象 泰達米爾
taidamier = Hero()

# 給對象添加屬性,以及對應的屬性值
taidamier.name = "泰達米爾"  # 姓名
taidamier.hp = 2600  # 生命值
taidamier.atk = 450  # 攻擊力
taidamier.armor = 200  # 護甲值

# 通過.成員選擇運算符,獲取對象的屬性值
print("英雄 %s 的生命值 :%d" % (taidamier.name, taidamier.hp))
print("英雄 %s 的攻擊力 :%d" % (taidamier.name, taidamier.atk))
print("英雄 %s 的護甲值 :%d" % (taidamier.name, taidamier.armor))

# 通過.成員選擇運算符,獲取對象的實例方法
taidamier.move()
taidamier.attack()
英雄 泰達米爾 的生命值 :2600
英雄 泰達米爾 的攻擊力 :450
英雄 泰達米爾 的護甲值 :200
正在前往事發地點...
發出了一招強力的普通攻擊...

對象創建並添加屬性後,能否在類的實例方法裏獲取這些屬性呢?如果可以的話,應該通過什麼方式?

  • 在方法內通過self獲取對象屬性
class Hero(object):
    """定義了一個英雄類,可以移動和攻擊"""
    def move(self):
        """實例方法"""
        print("正在前往事發地點...")

    def attack(self):
        """實例方法"""
        print("發出了一招強力的普通攻擊...")

    def info(self):
        """在類的實例方法中,通過self獲取該對象的屬性"""
        print("英雄 %s 的生命值 :%d" % (self.name, self.hp))
        print("英雄 %s 的攻擊力 :%d" % (self.name, self.atk))
        print("英雄 %s 的護甲值 :%d" % (self.name, self.armor))


# 實例化了一個英雄對象 泰達米爾
taidamier = Hero()

# 給對象添加屬性,以及對應的屬性值
taidamier.name = "泰達米爾"  # 姓名
taidamier.hp = 2600  # 生命值
taidamier.atk = 450  # 攻擊力
taidamier.armor = 200  # 護甲值

# 通過.成員選擇運算符,獲取對象的實例方法
taidamier.info()  # 只需要調用實例方法info(),即可獲取英雄的屬性
taidamier.move()
taidamier.attack()
英雄 泰達米爾 的生命值 :2600
英雄 泰達米爾 的攻擊力 :450
英雄 泰達米爾 的護甲值 :200
正在前往事發地點...
發出了一招強力的普通攻擊...

六.魔法方法__init__()

創建對象後再去添加屬性有點不合適,有沒有簡單的辦法,可以在創建對象的時候,就已經擁有這些屬性?

class Hero(object):
    """定義了一個英雄類,可以移動和攻擊"""
    # Python 的類裏提供的,兩個下劃線開始,兩個下劃線結束的方法,就是魔法方法,__init__()就是一個魔法方法,通常用來做屬性初始化 或 賦值 操作。
    # 如果類面沒有寫__init__方法,Python會自動創建,但是不執行任何操作,
    # 如果爲了能夠在完成自己想要的功能,可以自己定義__init__方法,
    # 所以一個類裏無論自己是否編寫__init__方法 一定有__init__方法。

    def __init__(self):
        """ 方法,用來做變量初始化 或 賦值 操作,在類實例化對象的時候,會被自動調用"""
        self.name = "泰達米爾" # 姓名
        self.hp = 2600 # 生命值
        self.atk = 450  # 攻擊力
        self.armor = 200  # 護甲值

    def info(self):
        """在類的實例方法中,通過self獲取該對象的屬性"""
        print("英雄 %s 的生命值 :%d" % (self.name, self.hp))
        print("英雄 %s 的攻擊力 :%d" % (self.name, self.atk))
        print("英雄 %s 的護甲值 :%d" % (self.name, self.armor))

    def move(self):
        """實例方法"""
        print("正在前往事發地點...")

    def attack(self):
        """實例方法"""
        print("發出了一招強力的普通攻擊...")


# 實例化了一個英雄對象,並自動調用__init__()方法
taidamier = Hero()

# 通過.成員選擇運算符,獲取對象的實例方法
taidamier.info() # 只需要調用實例方法info(),即可獲取英雄的屬性
taidamier.move()
taidamier.attack()
英雄 泰達米爾 的生命值 :2600
英雄 泰達米爾 的攻擊力 :450
英雄 泰達米爾 的護甲值 :200
正在前往事發地點...
發出了一招強力的普通攻擊...

  • 有參數的__init__()方法
class Hero(object):
    """定義了一個英雄類,可以移動和攻擊"""

    def __init__(self, name, skill, hp, atk, armor):
        """ __init__() 方法,用來做變量初始化 或 賦值 操作"""
        # 英雄名
        self.name = name
        # 技能
        self.skill = skill
        # 生命值:
        self.hp = hp
        # 攻擊力
        self.atk = atk
        # 護甲值
        self.armor = armor

    def move(self):
        """實例方法"""
        print("%s 正在前往事發地點..." % self.name)

    def attack(self):
        """實例方法"""
        print("發出了一招強力的%s..." % self.skill)

    def info(self):
        print("英雄 %s 的生命值 :%d" % (self.name, self.hp))
        print("英雄 %s 的攻擊力 :%d" % (self.name, self.atk))
        print("英雄 %s 的護甲值 :%d" % (self.name, self.armor))


# 實例化英雄對象時,參數會傳遞到對象的__init__()方法裏
taidamier = Hero("泰達米爾", "旋風斬", 2600, 450, 200)
gailun = Hero("蓋倫", "大寶劍", 4200, 260, 400)

# 直接輸出對象即爲地址
print(gailun)
# <__main__.Hero object at 0x0318B100>
print(taidamier)
# <__main__.Hero object at 0x0318B0D0>

# 不同對象的屬性值的單獨保存
print(id(taidamier.name))
print(id(gailun.name))

# 同一個類的不同對象,實例方法共享
print(id(taidamier.move()))
# 泰達米爾 正在前往事發地點...
# 2045877480
print(id(gailun.move()))
# 蓋倫 正在前往事發地點...
# 2045877480
  • 輸出結果
<__main__.Hero object at 0x0318B100>
<__main__.Hero object at 0x0318B0D0>
51928864
51928912
泰達米爾 正在前往事發地點...
2045877480
蓋倫 正在前往事發地點...
2045877480
  • 如果是屬性則直接輸出其地址值,如果是方法則先執行方法在輸出地址值
  • 通過一個類,可以創建多個對象,就好比通過一個模具創建多個實體一樣
  • init(self)中,默認有1個參數名字爲self,如果在創建對象時傳遞了2個實參,那麼__init__(self)中出了self作爲第一個形參外還需要2個形參,例如__init__(self,x,y)

  • 注意:
  • ①在類內部獲取 屬性 和 實例方法,通過self獲取;
  • ②在類外部獲取 屬性 和 實例方法,通過對象名獲取。
  • ③如果一個類有多個對象,每個對象的屬性是各自保存的,都有各自獨立的地址
  • 但是實例方法是所有對象共享的,只佔用一份內存空間。類會通過self來判斷是哪個對象調用了實例方法。

七.魔法方法__str__()

  • 當使用print輸出對象的時候,默認打印對象的內存地址。如果類定義了__str__(self)方法,那麼就會打印從在這個方法中 return 的數據
class Hero(object):
    """定義了一個英雄類,可以移動和攻擊"""

    def __init__(self, name, skill, hp, atk, armor):
        """ __init__() 方法,用來做變量初始化 或 賦值 操作"""
        # 英雄名
        self.name = name  # 實例變量
        # 技能
        self.skill = skill
        # 生命值:
        self.hp = hp   # 實例變量
        # 攻擊力
        self.atk = atk
        # 護甲值
        self.armor = armor

    def move(self):
        """實例方法"""
        print("%s 正在前往事發地點..." % self.name)

    def attack(self):
        """實例方法"""
        print("發出了一招強力的%s..." % self.skill)

    # def info(self):
    #     print("英雄 %s 的生命值 :%d" % (self.name, self.hp))
    #     print("英雄 %s 的攻擊力 :%d" % (self.name, self.atk))
    #     print("英雄 %s 的護甲值 :%d" % (self.name, self.armor))


    def __str__(self):
        """
            這個方法是一個魔法方法 (Magic Method) ,用來顯示信息
            該方法需要 return 一個數據,並且只有self一個參數,當在類的外部 print(對象) 則打印這個數據
        """
        return "英雄 <%s> 數據: 生命值 %d, 攻擊力 %d, 護甲值 %d" % (self.name, self.hp, self.atk, self.armor)


taidamier = Hero("泰達米爾", "旋風斬", 2600, 450, 200)
gailun = Hero("蓋倫", "大寶劍", 4200, 260, 400)

# 如果沒有__str__ 則默認打印 對象在內存的地址。
# 當類的實例化對象 擁有 __str__ 方法後,那麼打印對象則打印 __str__ 的返回值。
print(taidamier)
print(gailun)

# 查看類的文檔說明,也就是類的註釋
print(Hero.__doc__)
英雄 <泰達米爾> 數據: 生命值 2600, 攻擊力 450, 護甲值 200
英雄 <蓋倫> 數據: 生命值 4200, 攻擊力 260, 護甲值 400
定義了一個英雄類,可以移動和攻擊
  • ①在python中方法名如果是__xxxx__()的,那麼就有特殊的功能,因此叫做“魔法”方法
  • ②__str__方法通常返回一個字符串,作爲這個對象的描述信息

八.魔法方法__del__()

  • 創建對象後,python解釋器默認調用__init__()方法;
  • 當刪除對象時,python解釋器也會默認調用一個方法,這個方法爲__del__()方法
class Hero(object):

    # 初始化方法
    # 創建完對象後會自動被調用
    def __init__(self, name):
        print('__init__方法被調用')
        self.name = name

    # 當對象被刪除時,會自動被調用
    def __del__(self):
        print("__del__方法被調用")
        print("%s 被 GM 幹掉了..." % self.name)


# 創建對象
taidamier = Hero("泰達米爾")

# 刪除對象
print("%d 被刪除1次" % id(taidamier))
del(taidamier)


print("--" * 10)


gailun = Hero("蓋倫")
gailun1 = gailun
gailun2 = gailun

print("%d 被刪除1次" % id(gailun))
del(gailun)

print("%d 被刪除1次" % id(gailun1))
del(gailun1)

print("%d 被刪除1次" % id(gailun2))
del(gailun2)
  • 運行結果
__init__方法被調用
54112464 被刪除1次
__del__方法被調用
泰達米爾 被 GM 幹掉了...
--------------------
__init__方法被調用
54112464 被刪除154112464 被刪除1次
__del__方法被調用
蓋倫 被 GM 幹掉了...
  • 當有變量保存了一個對象的引用時,此對象的引用計數就會加1;
  • 當使用del() 刪除變量指向的對象時,則會減少對象的引用計數。如果對象的引用計數不爲1,那麼會讓這個對象的引用計數減1,當對象的引用計數爲0的時候,則對象纔會被真正刪除(內存被回收)。

  • The best investment is in yourself
    在這裏插入圖片描述
  • 2020.04.03 記錄辰兮的第46篇博客
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章