🍖面向對象編程

引入

面向對象的由來html

v2-5cc3f8dc72f94dc7e30391d104ec5319_hd

一.面向過程與面向對象

1.面向過程

  • 面向過程編程的核心就是過程二字, 既先作什麼, 再作什麼, 而後作什麼
  • 優勢 : 將複雜的問題流程化, 進而簡單化
  • 缺點 : 一整個流程只爲了解決一個問題, 換另外一個問題又須要另外一個整套的流程, 牽一髮而動全身

2.面向對象

  • 面向對象編程的核心就是對象二字, 對象是特徵與技能的集合體
  • 也能夠說對象是一個容器, 用來盛放 數據(特徵) 和 功能(技能)
  • 優勢 : 提升程序的解耦合性, 進而提升程序的可擴展性, 對某一個對象單獨修改, 會馬上反映到整個體系當中
  • 缺點 : 編程的複雜程度遠高於面向過程, 而且不能精準的預測到問題的處理流程和結果, 只能讓對象之間進行交互才能準確的知道最終的結果

v2-ba306425d0a7aee2c7260381f1bf7b97

ps : 一個軟件質量因素有不少: 性能, 可維護, 可擴展, 可移植, 成本, 安全......, 而面向對象解決的僅僅是可擴展性的問題, 因此它也是有侷限性的python

二.類與對象

1.什麼是類

  • 類, 即類別, 種類, 是面向對象設計最重要的概念, 對象是特徵與技能的集合體, 而類則是一系列對象類似特徵與技能的集合體
⛅在沒有學習類這個概念時,數據與功能是分離的
⛅每次調用都須要重複傳入一堆參數, 咱們能想到的解決方法是,把這些變量都定義成全局變量
⛅這樣咱們將會定義一大堆全局變量,這些全局變量並無作任何區分,即可以被全部功能使用
⛅然而事實上只有某一些對象才使用某一些它們所須要的功能, 並非所有的功能都須要
⛅言外之意:咱們必須找出一種可以將數據與操做數據的方法組合到一塊兒的解決方法,這就是咱們說的類了
  • 現實世界與程序中類與對象的關係
⛅"現實世界中 : 先有對象, 再有類
世界上現實有了各類各樣的物種:豬,狗,貓,人,而後咱們將其歸爲:豬類,犬類,貓類,人類

⛅"在程序中 : 先有類, 再有對象
與函數相似, 先定義再調用, 類也是同樣, 先定義類, 再調用類
不一樣的是函數調用時執行函數體代碼, 而類則是實例出一個對

2.類的定義與實例化

  • 類名儘可能使用駝峯體
🐫製造一個"鴨子對象",鴨子有不一樣品種"特徵", 鴨子會叫, 還會跑這些"技能" (特徵與對象的結合體: 就是屬性與方法)

⛅先定義一個"鴨子類"
class Duck:
	⛅特徵(屬性)
	bread = "你好鴨"
	color = "yello"
	⛅技能(方法),特殊的函數,自帶"self"
	def run(self):
		print("技能奔跑")
        
⛅定義一個"鴨子對象"
duck1 = Duck()

⛅使用對象
print(duck1.bread)  # 你好鴨
print(duck1.color)  # yello
duck1.run()         # 技能奔跑

3.__dict__ : 類的名稱空間

  • 類中能夠有任意的 Python 代碼, 這些代碼在類定義階段就會執行
  • 於是會產生新的名稱空間, 用來存放類的變量名與函數名, 能夠經過[類名].__dict__來進行查看
  • 同理, 對象的名稱空間也是使用.__dict__來查看
🐫"."(點)專門用來訪問屬性, 本質上就是在操做"__dict__"

print(Duck.__dict__)
'''輸出結果
{'__module__': '__main__', 'bread': '你好鴨', 'color': 'yello',\
'run': <function Duck.run at 0x000001FB5771FC18>, '__dict__': <attribute '__dict__' of 'Duck' objects>,\
'__weakref__': <attribute '__weakref__' of 'Duck' objects>, '__doc__': None}
'''「__」開頭的能夠先不要關注

Duck.bread            # 等於經典類的操做 : Duck.__dict__["bread"]
Duck.color = "black"  # 等於經典類的操做 : Duck.__dict__["color"] = "black"
Duck.new_x = "haha"   # 等於經典類的操做 : Duck.__dict__["new_x"] = "haha"
del Duck.new_x        # 等於經典類的操做 : Duck.__dict__.pop("new_x")

4.定製對象獨有的特徵

  • 調用類, 或稱爲實例化, 獲得對象
class Duck:
    bread = "你好鴨"
    color = "yello"
    "self"

    def run(self):
        print("技能奔跑")

duck1 = Duck()

duck1.name = "哎鴨"     # 定製獨有的品種
duck1.color = "black"   # 定製獨有的顏色 
duck1.weight = 20       # 定製獨有的重量

print(duck1.name)       # 哎鴨
print(duck1.color)      # black
print(duck1.weight)     # 20

5.__init__方法

  • 該方法是爲對象初始化本身獨有的特徵
  • 該方法內能夠有任意的python代碼, 必定不能有返回值
🐫上面咱們介紹了一種給對象定製獨有特徵的方法,下面咱們使用"__init__"方法直接進行初始化賦值

⛅新方案, 只要是類實例化獲得對象, 就會自動觸發"__init__"的執行
class Duck:
    def __init__(self):
        self.bread = "你好鴨"
        self.color = "yello"

    def run(self):
        print(f"{self.bread}有技能奔跑")

duck1 = Duck()

print(duck1.bread)  # 你好鴨
print(duck1.color)  # yello
duck1.run()         # 你好鴨有技能奔跑

⛅"__init__"的升級使用, 觸發"__init__"的執行, 並傳入參數(傳參原則與函數傳參相同)
class Duck:
    def __init__(self,bread,color):
        self.bread = bread
        self.color = color

    def run(self):
        print(f"{self.bread}有技能奔跑")

duck1 = Duck("快跑鴨","black")
duck2 = Duck("能夠鴨","blue")
duck3 = Duck("牛鴨","white")

print(duck1.bread)  # 快跑鴨
print(duck1.color)  # black
duck1.run()         # 快跑鴨有技能奔跑

print(duck2.bread)  # 能夠鴨
print(duck2.color)  # blue
duck2.run()         # 能夠鴨有技能奔跑

print(duck3.bread)  # 牛鴨
print(duck3.color)  # white
duck3.run()         # 牛鴨有技能奔跑

三.對象屬性查找

1.類的兩種屬性

  • 類的數據屬性是全部對象共享的
  • 類的函數屬性是綁定給對象用的

2.數據屬性共享

  • 數據 ID 都同樣

ps : id是python的實現機制,並不能真實反映內存地址,若是有內存地址,仍是之內存地址爲準編程

class Duck:
    master = "shawn"
    def __init__(self,bread,size):
        self.bread = bread
        self.size = size

duck1 = Duck("嘿鴨",100)
duck2 = Duck("好的鴨",80)

print(id(duck1.master))  # 1905145581488
print(id(duck2.master))  # 1905145581488

3.函數屬性綁定給對象

  • obj.method 稱爲綁定方法, 內存地址都不同
class Duck:
    master = "shawn"
    def __init__(self,bread,size):
        self.bread = bread
        self.size = size
    def run(self):
        print(f"{self.bread}在跑")

duck1 = Duck("嘿鴨",100)
duck2 = Duck("好的鴨",80)
duck3 = Duck("別鴨",80)

print(Duck.run)  # <function Duck.run at 0x000001F46C919168>
print(duck1.run) # <bound method Duck.run of <__main__.Duck object at 0x000001F46C693E08>>
print(duck2.run) # <bound method Duck.run of <__main__.Duck object at 0x000001F46C8F3E48>>
print(duck3.run) # <bound method Duck.run of <__main__.Duck object at 0x000001F46C8F3E88>>

4.對象的查找

  • 對象尋找屬性, 好比 name, 它會先到本身的名稱空間裏面去找, 找不到再去類裏面去找, 類中找不到再去父類, 父類中找不到就拋出異常

82ca289a1f35444a979154657e883b5

  • 類中定義的屬性, 對象只能使用, 不能修改, 對象若是修改, 改的是本身的名稱空間
⛅對象更改屬性, 該的只是本身的
class Duck:
    master = "shawn"
    def __init__(self,bread,size):
        self.bread = bread
        self.size = size
    def run(self):
        print(f"{self.bread}在跑")

duck1 = Duck("不要鴨",80)
duck1.master = "song"  # 更改屬性

print(Duck.master)     # shawn
print(duck1.master)    # song

⛅類修改
class Duck:
    master = "shawn"
    def __init__(self,bread,size):
        self.bread = bread
        self.size = size
    def run(self):
        print(f"{self.bread}在跑")

duck1 = Duck("醬紫鴨",80)
Duck.master = "xing" # 類修改屬性

print(Duck.master)   # xing
print(duck1.master)  # xing

四.對象的綁定方法

1.什麼是對象的綁定方法

  • 定義在類內部的函數 (且沒有被任何裝飾器裝飾的) 就是對象的綁定方法, 對象來調用, 調用時會自動傳入對象自己 self
  • 對象的綁定方法, 類也能夠調用, 當類調用的時候, 調的就是一個普通的函數, 有幾個參數就要傳幾個參數
  • 能夠經過 self 來區分究竟是哪一個對象調用了本身的綁定方法

ps : self能夠是任意名字,可是約定俗成地寫成self安全

2.什麼叫函數, 什麼叫方法?

  • 函數就是 def 定義的函數, 有幾個參數就要傳幾個參數
  • 方法是綁定給對象使用的, 由對象來調用, 特殊之處就是會把對象自身傳入, 與方法 __init__是同樣的道理

3.對象調用綁定方法演示

  • 對象調用, 將對象自身傳入
class Duck:
    master = "shawn"
    def __init__(self,bread,size):
        self.bread = bread
        self.size = size
    def run(self):
        print(f"{self.bread}在跑")

    def eat(self):
        print(f"{self.bread}在吃東西")

    def sleep(self):
        print(f"{self.bread}在睡覺")

duck1 = Duck("可惡鴨",80)
duck2 = Duck("厲害鴨",50)
duck3 = Duck("好慘鴨",90)

duck1.run()    # 可惡鴨在跑
duck2.eat()    # 厲害鴨在吃東西
duck3.sleep()  # 好慘鴨在睡覺

4.類調用方法演示

  • 其實類中的函數主要是給對象來使用的, 這裏只作演示
  • 類調用時要遵循函數的參數規則, 有幾個參數就要傳幾個參數
Duck.run(duck1)   # 可惡鴨在跑
Duck.eat(duck2)   # 厲害鴨在吃東西
Duck.sleep(duck3) # 好慘鴨在睡覺

五.Python中一切皆對象

1."類" 與 "類型"

  • 在Python3中,"類""類型"同一個概念, 咱們其實早就使用了類這個概念
  • 經常使用的數據類型 : list, dict, int, float, tuple, set 等
list1 = list([1,2,3])
dict1  = dict({"name":"shawn"})
int1 = int("12311321")
float1 = float("11.3")
tuple1 = tuple((1,2,3))
set1 = set(list1)

print(type(list1))   # <class 'list'>
print(type(dict1))   # <class 'dict'>
print(type(int1))    # <class 'int'>
print(type(float1))  # <class 'float'>
print(type(tuple1))  # <class 'tuple'>
print(type(set1))    # <class 'set'>

2.list 類演示

⛅使用"list"類實例化出一個對象
list1 = list([1,2,3,4])
list2 = list([5,6,6,8])

⛅每一個對象均可以使用"list"類的公共屬性和方法,咱們稱之爲綁定方法,而且綁定給不一樣的對象, 內存地址也不相同
print(list1.append)  # <built-in method append of list object at 0x000001A950EAF108>
print(list2.append)  # <built-in method append of list object at 0x000001A950EAF188>

⛅實例化出來的每一個對象都是相互獨立的個體, 相互不影響
list1.append(1)
list2.insert(0,9)

print(list1)  # [1, 2, 3, 4, 1]
print(list2)  # [9, 5, 6, 6, 8]

六.小結

  • 在上述介紹類與對象的使用過程當中,咱們更多的是站在底層原理的角度去介紹類與對象之間的關聯關係app

  • 若是隻是站在使用的角度,咱們無需考慮語法「對象.屬性"中」屬性「到底源自於哪裏,只須要知道是經過對象獲取到的就能夠了函數

  • 因此說,對象是一個高度整合的產物,有了對象,咱們只須要使用」對象.xxx「的語法就能夠獲得跟這個對象相關的全部數據與功能,十分方便且解耦合程度極高性能

相關文章
相關標籤/搜索