python基礎之面向對象編程 面向對象編程思想 面向對象是一門編程思想,編程思想僅僅是一門思想,與任何技術無關 核心是對象兩字,對象可以理解為特征與技能的結合體 基於該編程思想編寫程式,就好比創造世界,一種造物主的思維方式 優點:可擴張性強 缺點:編寫程式的複雜難度比面向過程高 以上都是純理論,理 ...
python基礎之面向對象編程
面向對象編程思想
- 面向對象是一門編程思想,編程思想僅僅是一門思想,與任何技術無關
- 核心是對象兩字,對象可以理解為特征與技能的結合體
- 基於該編程思想編寫程式,就好比創造世界,一種造物主的思維方式
- 優點:可擴張性強
- 缺點:編寫程式的複雜難度比面向過程高
以上都是純理論,理解下用自己的話能編出來就行,下麵來說說核心對象
在現實世界中,通過一個個的對象,根據相同的特征和行為,再分門別類。
但是在程式中,必須先有類,再通過調用類,創建對象。
那麼,咱們如何定義類,又如何創建對象呢?(暫時還是先說理論吧,不然看代碼,估計直接懵逼了……)
關於類的致命三問:什麼是類?有什麼用?怎麼使用?
-
類的定義:就是類型、類別,跟現實的分類類似。是一系列對象之間相同特征和行為(技能)的結合體
-
類的作用:個人理解,就是為了創建對象用的。
(終於要寫代碼了,哈哈哈哈哈哈哈)
- 類的語法:
class 類名:
特征 # 在python 中,用變數來表示特征
行為 # 在python 中,用函數來表示行為,也就是大家所說的技能
現在,我們來寫一個人類,人類的特征有名字,年齡,性別,行為有吃飯,跑步,玩,擼代碼了!
"""
人類
特征:名字、年齡、性別
行為:吃飯、跑、玩
"""
class Person:
# 這些都是人的特征
name = "dawn" # 姓名
age = 27 # 年齡
sex = "男" # 性別
# 這些都是人的行為(技能)
def eat(self):
# 吃飯
print("民以食為天o(∩_∩)o 哈哈")
def run(self):
# 跑步
print("英雄救美,不存在的!別慫!趕緊跑!!!")
def play(self):
# 玩
print("大爺!歡迎下次來玩兒啊!")
print(Person)
print(Person.name)
print(Person.play)
輸出結果
<class '__main__.Person'> # Person 的列印結果
dawn # Person.name 的列印結果
<function Person.play at 0x0000022E54FA7DC8> # Person.play 的列印結果
瞅了這麼久,發現了嗎?類名,類的行為,類的屬性都是咋用的?(理論又來了~~~)
- 類名的命名規範:使用駝峰命名法,即單詞的首字母得大寫!
- 類提供了一種便捷的獲取名字的方式,就是
類名.名字
。類的名字包含特征和行為。咱們將類的特征稱之為屬性,類的行為稱之為方法 - 在類的內部定義函數(也就是行為的時候,預設有一個參數
self
),這個是幹啥的,等會說
通過輸出的內容來看,類名指向的是類的記憶體地址。如何來查看類的名稱空間呢?看代碼……
print(Person.__dict__)
輸出結果
{'__module__': '__main__', 'name': 'dawn', 'age': 27, 'sex': '男', 'eat': <function Person.eat at 0x00000228C1683558>, 'run': <function Person.run at 0x00000228C1683B88>, 'play': <function Person.play at 0x00000228C1687DC8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
驚不驚喜!意不意外!對,這就是Person類的名稱空間中的內容!!!也就是說類的名稱空間是在定義階段產生
到這裡,咱們就該聊聊類是如何使用的了。前面咱就說了,類的調用就是對象的創建。說的類的使用就得知道對象是啥了!耐心點,好玩的還在後面!
哈哈哈哈哈!我三連問回來啦!——什麼是對象?有什麼用?怎麼使用?
-
對象的定義:特征與技能的結合體
-
語法:
類名()
咱們來瞅瞅對象是如何創建的,類又是如何調用的 !
# 上面咱定義了一個Person類,這裡直接拿來用
# 調用Person類後會產生一個對象,使用一個變數接收
p1 = Person()
# 輸出p1 的屬性
print(p1.name, p1.age, p1.sex)
# 使用p1 的方法
p1.play()
p1.run()
p1.eat()
輸出結果
dawn 27 男 # p1的屬性
大爺!歡迎下次來玩兒啊! # p1.play()的結果
英雄救美,不存在的!別慫!趕緊跑!!! # p1.run()的結果
民以食為天o(∩_∩)o 哈哈 # p1.eat()的結果
剛剛獲取了對象的屬性(也就是查詢),發現沒有,這些屬性都是類的,我們能否對對象的屬性做個增刪改呢?如果修改了對象的屬性,類是否隨之改變呢?動手試試
修改對象的屬性,其實就是對象自己增加了屬性
# 修改屬性
print(Person.__dict__) # 修改前,Person的名稱空間
print(p1.__dict__) # 修改前,p1的名稱空間
p1.name = "haha" # 修改對象的name 屬性,實際上是p1對象自己新增了name 屬性
print(Person.__dict__) # 修改後,Person的名稱空間
print(p1.__dict__) # 修改後,p1的名稱空間
輸出結果
增加對象的屬性
# 增加屬性
print(p1.__dict__)
print(Person.__dict__)
p1.hobby = "read"
print(p1.__dict__)
print(Person.__dict__)
輸出結果
刪除對象的屬性
# 刪除屬性
del p1.sex
print(p1.sex)
print(Person.__dict__)
輸出結果
縱觀以上的結果,咱說了那些屬性都在類的名稱空間里,那麼有沒有什麼方法,讓這些屬性是通過對象來增刪改查的呢?
當然有的啦!那就是__init__()
!我們來看看使用方式
# 定義一個類
class Person:
# 這些都是人的特征
name = "dawn" # 姓名
# __init__()
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
# 這些都是人的行為(技能)
def eat(self):
# 吃飯
print("民以食為天o(∩_∩)o 哈哈")
# 通過類創建兩個對象,分別是p1和p2
p1 = Person("haha", 39, "男")
p2 = Person("lee", 21, "女")
# 查看Person類的名稱空間
print(Person.__dict__)
# 查看對象p1的名稱空間
print(p1.__dict__)
# 查看對象p2的名稱空間
print(p2.__dict__)
輸出結果
發現什麼了沒有?
__init__()
實現了對象的個性化定製,而且創建對象在傳參時,沒有傳self這個參數。
那是因為__init__()
在調用時,會將對象本身作為第一個參數傳入。原因後期學習以後,才知道。現在就做一個總結好了
- 由對象來調用類的內部函數,稱為對象的綁定方法。對象的綁定方法特殊之處在於:會將對象本身當作第一個參數傳入方法(咱可以回頭看看定義類的時候,是不是每個行為也就是方法,都有self參數)
__init__()
在調用類時觸發,會做以下事情:- 將對象本身當作第一個參數傳入方法(原因:對象的綁定方法)
- 調用時,傳入的其他參數一併被
__init__()
接收
接著,我們來看看,對象是如何對屬性做增刪改查的
# 獲取p1的屬性
print(f"姓名:{p1.name},性別:{p1.sex},年齡:{p1.age}")
# 修改p1的屬性
print(f"修改前,p1的名稱空間:{p1.__dict__}")
p1.age = 27
print(f"修改後,p1的屬性值:{p1.age}")
print(f"修改後,p1的名稱空間:{p1.__dict__}")
輸出結果
再來看看增加(前面就已經舉例了,算了還是再舉一個吧)和刪除
# 獲取p1的屬性
print(f"姓名:{p1.name},性別:{p1.sex},年齡:{p1.age}")
# 增加屬性
print(f"增加hobby前:{p1.__dict__}")
p1.hobby = "read"
print(f"hobby的取值:{p1.hobby}")
print(f"增加hobby後:{p1.__dict__}")
# 刪除屬性
print(f"刪除sex前:{p1.__dict__}")
del p1.sex
print(f"刪除sex後:{p1.__dict__}")
輸入結果
還有個地方,就是咱剛纔一直在說名稱空間,那麼類的名稱空間和對象的名稱空間,有什麼關係呢?
咱們繼續看代碼
# 通過類創建一個對象
p1 = Person("haha", 39, "男")
# 查看Person類的名稱空間和屬性
print(f"Person的名稱空間:{Person.__dict__}")
print(f"Person的name屬性值:{Person.name}")
# 查看對象p1的名稱空間和屬性
print(f"p1的名稱空間:{p1.__dict__}")
print(f"p1的name屬性值:{p1.name}")
# 刪除p1的屬性name,再列印p1的名稱空間和屬性
del p1.name
print(f"刪除name屬性後,p1的名稱空間:{p1.__dict__}")
print(f"刪除name屬性後,p1的name屬性值:{p1.name}")
輸出結果
看到沒?對象的屬性刪除後,再去調用這個屬性,並沒有報錯,而是將類中的同名屬性值獲取了過來
那如果類中沒有這個屬性呢?我們再來看看
class Person:
# 這些都是人的特征
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
# 通過類創建一個對象
p1 = Person("haha", 39, "男")
# 查看對象p1的名稱空間和屬性
print(f"p1的名稱空間:{p1.__dict__}")
print(f"p1的name屬性值:{p1.name}")
# 刪除p1的屬性name,再列印p1的名稱空間和屬性
del p1.name
print(f"刪除name屬性後,p1的名稱空間:{p1.__dict__}")
print(f"刪除name屬性後,p1的name屬性值:{p1.name}")
輸出結果
報錯了!!!由此我們可以總結下:
對象先從自身名稱空間查找,沒有就去類的名稱空間查找,再沒有就會報錯。
對象名字的查找順序:
對象自身 ----→ 類 ----→ 都沒有,報錯
定義類及調用的固定模式
class 類名:
def __init__(self,參數1,參數2):
self.對象的屬性1 = 參數1
self.對象的屬性2 = 參數2
def 方法名(self):pass
def 方法名2(self):pass
對象名 = 類名(1,2) #對象就是實例,代表一個具體的東西
#類名() : 類名+括弧就是實例化一個類,相當於調用了__init__方法
#括弧里傳參數,參數不需要傳self,其他與init中的形參一一對應
#結果返回一個對象
對象名.對象的屬性1 #查看對象的屬性,直接用 對象名.屬性名 即可
對象名.方法名() #調用類中的方法,直接用 對象名.方法名() 即可