Python之面向對象(一)
基本概念
什麼是對象
在Python中萬物皆對象。
對象是具體的物體。該物體擁有屬性、行爲,對象就是把很多零散的東西封裝成一個整體。
e.g.
Javier_Ji 擁有姓名、年齡、身高、體重…(這些既是屬性);
Javier_Ji能走路、吃飯、睡覺…(這些既是行爲)。
Javier_Ji就是一個對象,一個實例。
面向過程&面向對象
面向過程的程序設計的核心是過程(流水線式思維),過程即解決問題的步驟,面向過程的設計就像流水線,能做到什麼在時候做什麼事情。在解決問題的時候關注的是解決問題的每一個過程(步驟)。
優點是:極大的降低了寫程序的複雜度,只需要順着要執行的步驟,堆疊代碼即可。
缺點是:一套流水線或者流程就是用來解決一個問題,代碼牽一髮而動全身。
面向對象在解決問題的時候,關注的是解決問題所需要的對象。
優點是:解決了程序的擴展性。對某一個對象單獨修改,會立刻反映到整個體系中,如對遊戲中一個人物參數的特徵和技能修改都很容易。
缺點:可控性差,無法向面向過程的程序設計流水線式的可以很精準的預測問題的處理流程與結果,面向對象的程序一旦開始就由對象之間的交互解決問題,即便是上帝也無法預測最終結果。於是我們經常看到一個遊戲人某一參數的修改極有可能導致陰霸的技能出現,一刀砍死3個人,這個遊戲就失去平衡。
舉個栗子:
如何從面向過程編程的思想,過渡到面向對象編程?
- 一樣的,列舉出一個任務的具體實現步驟
- 試圖分離這些實現步驟中的功能代碼塊
- 將這些功能代碼塊,劃分到某一個對象中
- 根據這個對象以及對應的行爲,抽象出對應的類
類
由對象抽象出對應的類,如由Javier_Ji抽象出人類,人類擁有年齡、性別、身高等屬性,吃飯、睡覺等行爲。
類的作用
根據抽象出的類,生產具體的對象。
我們可以通過人類這個類生成張三、李四、王五等等不同的對象,這些對象的模板就是人類。
類的組成
名稱、屬性、方法
其中的屬性和方法都是抽象的概念。只有在產生對象之後,對象才擁有具體的屬性值和方法實現
列舉生活中的類:
- 類:錢
對象:具體的1毛、1元、5元…… - 類:動物
對象:貓、狗、老虎 - 類:汽車
對象:凱迪拉克、寶馬、奧迪
對象和類的關係
面向對象在python中的實現
如何定義一個類
class 類名:
pass
怎樣通過類創建(或者說實例化)一個對象
對象名 = 類名()
通過類創建對象時底層執行機制
話不多說,上碼
class Person:
pass
p = Person()
Person是一個變量名,引用了Person這個類,即該變量指向了Person這個類的地址。Person()
使程序在內存中開闢了一塊新的空間用來存放對象,即上圖中的橢圓形。p也是一個變量,指向了根據Person這個類產生的對象的地址。
在產生的對象中有一個屬性值__class__
關聯着Person類。
>>> p.__class__
<class '__main__.Person'>
屬性相關
屬性和變量的區別及判定依據
- 區別:
概念:變量是“可以改變的量值”。屬性是“屬於某個對象的特性”。
訪問權限:變量是根據不同的位置,存在不同的訪問權限(全局變量、局部變量……)。屬性只能通過對象來進行訪問,所以必須先找到對象才能調用其屬性,並且對象也是通過變量名來引用,而既然是變量,也有其相對應的訪問權限。
2.判定依據:是否存在宿主。
如果是變量,則直接寫給變量即可。如果是屬性,則需要寫對象.屬性
。
根據宿主的不同可以劃分爲:對象屬性和類屬性
對象屬性
增
- 直接通過對象,動態添加
語法:對象.屬性 = 值
class Person:
pass
p = Person()
p.age = 18
print(p.age)
打印的結果爲:18
我們可以使用內置方法:__dict__
來查看是否真的將age
屬性存到了p
對象中。
對象.__dict__
表示的是當前該對象中的所有屬性
print(p.__dict__)
打印的結果爲:{'age': 18}
該屬性是如何存儲的呢?
在內存中開闢一塊空間存儲18
,age
中存放的是18
的唯一標識,即age
指向18
。
當我們輸入p.age
時,是通過p
變量找到對應的對象
,通過對象
找到age屬性
,age
的值指向18
。
- 通過類的初始化方法(構造方法)
__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
)即可查看(或叫訪問)該屬性的值。
注意:不同的對象之間不可以互相訪問對方的屬性!!!
類屬性
增
類名.類屬性 = 值
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
屬性確實被添加進去了。
- 在類定義是添加類屬性
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}
可以看到屬性age
、height
和weight
都被添加進去了
查
-
通過類訪問:
類名.屬性
-
通過對象訪問:
對象.類屬性
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__
找到對象對應的類,在類中查找
改
- 通過類名修改
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}
- 能否通過對象進行修改?
不能
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
是賦值操作,而不是查詢操作!!!
刪
- 通過類名刪除:
del 類名.屬性
- 能否通過對象刪除?
不能,因爲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
的錯誤。