Python之面向對象(史上最全~不談)(一)

基本概念

什麼是對象

在Python中萬物皆對象。
對象是具體的物體。該物體擁有屬性、行爲,對象就是把很多零散的東西封裝成一個整體。
e.g.
Javier_Ji 擁有姓名、年齡、身高、體重…(這些既是屬性);
Javier_Ji能走路、吃飯、睡覺…(這些既是行爲)。
Javier_Ji就是一個對象,一個實例。


面向過程&面向對象

面向過程的程序設計的核心是過程(流水線式思維),過程即解決問題的步驟,面向過程的設計就像流水線,能做到什麼在時候做什麼事情。在解決問題的時候關注的是解決問題的每一個過程(步驟)。
優點是:極大的降低了寫程序的複雜度,只需要順着要執行的步驟,堆疊代碼即可。
缺點是:一套流水線或者流程就是用來解決一個問題,代碼牽一髮而動全身。

面向對象在解決問題的時候,關注的是解決問題所需要的對象。
優點是:解決了程序的擴展性。對某一個對象單獨修改,會立刻反映到整個體系中,如對遊戲中一個人物參數的特徵和技能修改都很容易。
缺點:可控性差,無法向面向過程的程序設計流水線式的可以很精準的預測問題的處理流程與結果,面向對象的程序一旦開始就由對象之間的交互解決問題,即便是上帝也無法預測最終結果。於是我們經常看到一個遊戲人某一參數的修改極有可能導致陰霸的技能出現,一刀砍死3個人,這個遊戲就失去平衡。


舉個栗子:

舉個栗子
做好飯後洗碗
面向過程
洗菜
點火倒油
放菜/材料
翻炒
盛出
放水
放碗
倒洗潔精
開始刷碗
擦乾水
擺放好
面向對象
對象
技能1:做飯
技能2:洗碗
洗菜
點火倒油
放菜/材料
翻炒
盛出
放水
放碗
倒洗潔精
開始刷碗
擦乾水
擺放好
對象
技能1:做飯
放菜/材料
自動炒菜機
盛出
攪拌
翻炒
檢測火候
技能2:洗碗
放水/放碗
自動洗碗機
倒洗潔精
開始刷碗
擦乾水
擺放好

如何從面向過程編程的思想,過渡到面向對象編程?

  1. 一樣的,列舉出一個任務的具體實現步驟
  2. 試圖分離這些實現步驟中的功能代碼塊
  3. 將這些功能代碼塊,劃分到某一個對象中
  4. 根據這個對象以及對應的行爲,抽象出對應的類

由對象抽象出對應的類,如由Javier_Ji抽象出人類,人類擁有年齡、性別、身高等屬性,吃飯、睡覺等行爲。

類的作用

根據抽象出的類,生產具體的對象。
我們可以通過人類這個類生成張三、李四、王五等等不同的對象,這些對象的模板就是人類。

類的組成

名稱、屬性、方法
其中的屬性和方法都是抽象的概念。只有在產生對象之後,對象才擁有具體的屬性值和方法實現


列舉生活中的類:

  1. 類:錢
    對象:具體的1毛、1元、5元……
  2. 類:動物
    對象:貓、狗、老虎
  3. 類:汽車
    對象:凱迪拉克、寶馬、奧迪

對象和類的關係

抽象
實例化
對象

面向對象在python中的實現

如何定義一個類

class 類名:
	pass

怎樣通過類創建(或者說實例化)一個對象

對象名 = 類名()


通過類創建對象時底層執行機制

話不多說,上碼

class Person:
	pass

p = Person()

在這裏插入圖片描述
Person是一個變量名,引用了Person這個類,即該變量指向了Person這個類的地址。Person()使程序在內存中開闢了一塊新的空間用來存放對象,即上圖中的橢圓形。p也是一個變量,指向了根據Person這個類產生的對象的地址。
在產生的對象中有一個屬性值__class__關聯着Person類。

>>> p.__class__
<class '__main__.Person'>

屬性相關

屬性和變量的區別及判定依據

  1. 區別:
    概念:變量是“可以改變的量值”。屬性是“屬於某個對象的特性”。
    訪問權限:變量是根據不同的位置,存在不同的訪問權限(全局變量、局部變量……)。屬性只能通過對象來進行訪問,所以必須先找到對象才能調用其屬性,並且對象也是通過變量名來引用,而既然是變量,也有其相對應的訪問權限。
    2.判定依據:是否存在宿主。
    如果是變量,則直接寫給變量即可。如果是屬性,則需要寫對象.屬性
    根據宿主的不同可以劃分爲:對象屬性和類屬性

對象屬性

  1. 直接通過對象,動態添加
    語法:對象.屬性 = 值
class Person:
    pass


p = Person()
p.age = 18
print(p.age)

打印的結果爲:18
我們可以使用內置方法:__dict__來查看是否真的將age屬性存到了p對象中。
對象.__dict__表示的是當前該對象中的所有屬性

print(p.__dict__)

打印的結果爲:{'age': 18}

該屬性是如何存儲的呢?
在這裏插入圖片描述
在內存中開闢一塊空間存儲18age中存放的是18的唯一標識,即age指向18
當我們輸入p.age時,是通過p變量找到對應的對象,通過對象找到age屬性age的值指向18

  1. 通過類的初始化方法(構造方法)
    __init__方法

使用del命令,即可刪除屬性。

class Person:
    pass


p = Person()
p.age = 18
print(p.age, id(p.age))
del p.age
print(p.__dict__)

打印的結果爲:

18 140718833325632
{}

class Person:
    pass


p = Person()
p.age = 18
print(p.age, id(p.age))
p.age = 25
print(p.age, id(p.age))
print(p.__dict__)

打印的結果爲:

18 140718833325632
25 140718833325856
{'age': 25}

由打印出的結果我們可以發現,兩個屬性的值的地址不一樣。說明在修改屬性age指向的值18時,會開闢一塊新的空間來存儲新的值25,並將屬性age指向新的值25
改

對象.屬性p.age)即可查看(或叫訪問)該屬性的值。

注意:不同的對象之間不可以互相訪問對方的屬性!!!

類屬性

  1. 類名.類屬性 = 值
class Person:
    pass


Person.age = 20
print(Person.age)
print(Person.__dict__)

打印的結果爲:

20
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'age': 20}

我們可以看到,age屬性確實被添加進去了。

  1. 在類定義是添加類屬性
class Person:
    age = 20
    height = 180
    weight = 70


print(Person.age)
print(Person.height)
print(Person.weight)
print(Person.__dict__)

打印的結果爲:

20
180
70
{'__module__': '__main__', 'age': 20, 'height': 180, 'weight': 70, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

可以看到屬性ageheightweight都被添加進去了

  1. 通過類訪問:類名.屬性

  2. 通過對象訪問:對象.類屬性

class Person:
    age = 20
    height = 180
    weight = 70


p = Person()
print(p.age)
print(p.height)
print(p.weight)
print(Person.__dict__)
print(p.__dict__)

打印的結果爲:

20
180
70
{'__module__': '__main__', 'age': 20, 'height': 180, 'weight': 70, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
{}

注意
Q:爲什麼可以通過對象訪問到類屬性?
A:和Python對象的屬性查找機制有關
優先在對象自身查找屬性,若找到則結束,否則根據__class__找到對象對應的類,在類中查找

  1. 通過類名修改
class Person:
    age = 20
    height = 180
    weight = 70


Person.age = 666
print(Person.age)
print(Person.__dict__)

打印的結果爲:

666
{'__module__': '__main__', 'age': 666, 'height': 180, 'weight': 70, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
  1. 能否通過對象進行修改?
    不能
class Person:
    age = 20
    height = 180
    weight = 70


Person.age = 666
print(Person.age)
p = Person()
p.age = 777
print(Person.age)
print(Person.__dict__)
print(p.__dict__)

打印的結果爲:

666
666
{'__module__': '__main__', 'age': 666, 'height': 180, 'weight': 70, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
{'age': 777}

我們可以看到age類屬性還是666,經過p.age = 777後,對象p中增加了age對象屬性。

爲什麼呢?
因爲p.age = 777是賦值操作,而不是查詢操作!!!

  1. 通過類名刪除:del 類名.屬性
  2. 能否通過對象刪除?
    不能,因爲del語句只能刪除直系屬性!

限制對象屬性的添加

使用__slots__方法。

class Person:
    __slots__ = ('age', 'height')
    pass


p = Person()
p.age = 777
print(p.age)
p.height = 180
print(p.height)
p.weight = 777
print(p.weight)

打印的結果爲:

777
180
Traceback (most recent call last):
  File "G:/python_work/面向對象/類.py", line 11, in <module>
    p.weight = 777
AttributeError: 'Person' object has no attribute 'weight'

由於weight沒有被放到__slots__中,所以不能綁定weight屬性,試圖綁定weight將得到AttributeError的錯誤。

未完待續。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章