一逼泣、模塊介紹
一個.py文件就是一個模塊,模塊中可以定義函數(shù)舟舒、類和變量拉庶。
- 模塊包括:內(nèi)置模塊、三方模塊和自定義模塊秃励。
- 模塊的優(yōu)點:
提高代碼的可維護性
提高代碼的復用性
避免了函數(shù)名和變量名的沖突
可以引用其他模塊
1. 引用模塊
- import語句:
import 模塊1[, 模塊2..., 模塊n]
import 模塊名.函數(shù)名
import 模塊名.變量名
- from...import...語句
from 模塊名 import 方法1[, 方法2, ...方法n]
從模塊中導入指定的方法到當前命名空間
from 模塊名 import *
把模塊中的所有內(nèi)容全部導入到當前命名空間
- 導入模塊指定別名
from 模塊名 import 方法1 as name
從模塊中導入方法1并指定別名為name氏仗,調(diào)用時name.XXX或name(XXX)
- 引用模塊的方法注意事項:
同一模塊無論被import多少次,為了防止重復引入夺鲜,均只會被引入一次皆尔。
可一次性引入多個模塊,不同模塊之間用逗號分隔
2. 模塊中特殊屬性
2.1. __name__
屬性
模塊就是一個可執(zhí)行的.py文件币励,一個模塊被另一個程序引入慷蠕。
如果不想讓模塊中的某些代碼執(zhí)行,可以用__name__
屬性食呻。每個模塊都有一個__name__
屬性流炕。
當前文件如果為程序的入口文件時澎现,則__name__ == "__main__"
。當__name__
屬性的值為"__main__"
時每辟,則表明該模塊自身在執(zhí)行剑辫;否則被引用其他文件。
3. 包
防止模塊命名沖突影兽,引入按目錄來組織模塊的方法揭斧,稱為包package。
引入包后峻堰,只要頂層的包與其他文件不沖突讹开,此包下的模塊就不會與其他文件發(fā)生沖突。
每個包下必須存在一個__init__.py
文件捐名,此文件內(nèi)容可為空旦万。
__init__.py
文件的作用:避免一些濫竽充數(shù)的名字,且目錄下只有存在此文件才可認為此目錄為一個包镶蹋。
4. 安裝第三方模塊
(1)前提:安裝python時安裝有pip
查看是否安裝有pip方法成艘,命令行輸入pip -V
C:\Users\admin>pip -V
pip 18.1 from d:\programs\python\python36\lib\site-packages\pip (python 3.6)
(2)安裝三方模塊
- pip install 模塊名
安裝模塊時有時會報錯,提示升級pip版本贺归。 - pip install --upgrade pip:升級pip版本
(1)安裝Pillow模塊:
C:\Users\admin>pip install Pillow
Requirement already satisfied: Pillow in d:\programs\python\python36\lib\site-packages (5.3.0)
You are using pip version 18.1, however version 19.1.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.
---報錯淆两,提示升級pip
(2)升級pip
遇到過升級pip后無法找到pip模塊:
File "D:\Programs\Python\Python36\Scripts\pip.exe\__main__.py", line 5, in <module>
ModuleNotFoundError: No module named 'pip'。但實際上有pip文件拂酣。
解決方案:
首先執(zhí)行:python -m ensurepip
再升級pip:python -m pip install --upgrade pip
(3)查看pip安裝的模塊
- pip list:列出所有的模塊信息
- pip show -V 模塊名 | findstr Version:window下獲取某個模塊的版本號
- pip show -V 模塊名 | grep Version:Linux下獲取某個模塊的版本號
二秋冰、面向?qū)ο?/h2>
1. 面向過程和面向?qū)ο蟮慕榻B
1.1. 面向過程:
- 程序從上到下順序執(zhí)行的代碼 。
- 面向過程強調(diào)的是功能行為
1.2. 函數(shù)式:
- 將功能代碼封裝到函數(shù)中婶熬,無需重復編寫剑勾,僅調(diào)用函數(shù)。
1.3. 面向?qū)ο螅?/h4>
- 把數(shù)據(jù)及對數(shù)據(jù)的操作方法放在一起赵颅,作為一個相互依賴的整體虽另,這就是對象。
- 把對同類對象抽象出其共性饺谬,形成類捂刺。
類中的大多數(shù)數(shù)據(jù),只能用本類的方法進行處理商蕴;
類通過一個簡單的外部接口與外界發(fā)生聯(lián)系叠萍,對象與對象之間通過消息進行通信;
程序流程由用戶在使用中決定绪商;
- 面向?qū)ο笫腔诿嫦蜻^程的苛谷。
- 面向?qū)ο笫菍⒐δ芊庋b成對象,強調(diào)的是具備功能的對象
- 面向?qū)ο罂梢詫碗s的事情簡單化
- 面向?qū)ο驩O(object-oriented)的三大特性:多態(tài)格郁、封裝腹殿、繼承独悴。
2. 類
2.1. 類的介紹
- 類是用來描述事件的屬性和行為動作。
屬性:對應(yīng)類中的成員變量锣尉;
行為:對應(yīng)類中成員方法或功能刻炒;
定義類就是定義類中的成員(成員變量和成員方法),擁有相同屬性和行為的對象都可以使用此類自沧。
設(shè)計類包括:類名坟奥、屬性、行為(方法/功能)拇厢。
2.2. 創(chuàng)建類
- 類是一種數(shù)據(jù)類型爱谁,本身并不占內(nèi)存空間。用類創(chuàng)建實例化對象(變量)孝偎,對象占內(nèi)存空間访敌。
- 類以class 關(guān)鍵詞開頭,后接類名(類名通常是以大寫開頭的單詞)
- 定義有繼承的類衣盾,則在類名后緊跟以括號括起來的父類名寺旺,表示該類是從此父類繼承下來的。一個類可以繼承多個類势决,類之間用逗號分隔阻塑。
若無合適的繼承類,可使用object類(object類是所有類最終都會繼承的類果复。)---object類又稱基類和超類叮姑。
- 類中定義的函數(shù),第一個參數(shù)永遠是self据悔,并且調(diào)用時不用傳遞該參數(shù)。self代表類的實例耘沼,即某個對象极颓。(注:沒有在類中定義的函數(shù),參數(shù)中無需添加變量self)
-----創(chuàng)建類的格式:
class 類名(父類1, 父類2...):
屬性
行為
-----訪問類
1. 使用類實例化對象
實例化對象格式:對象名 = 類名(參數(shù)列表)
注:類沒有參數(shù)群嗤,類名后的小括號也不可省略菠隆。
2. 訪問屬性
訪問屬性格式:對象名.屬性名
賦新值:對象名.屬性名 = 新值
3. 訪問方法
訪問方法格式:對象名.方法名(參數(shù)列表)
# 創(chuàng)建不含繼承的類
class Student1:
name = "zhangsan" # 屬性
def getScore(self, score): # 方法
print("這個學生的分數(shù)是:", score)
# 獲取類的實例化對象
student1 = Student1()
# 訪問屬性
getName = student1.name
print(getName) # zhangsan
# 訪問方法
student1.getScore(90) # 這個學生的分數(shù)是: 90
# 創(chuàng)建含繼承的類
class Student2(object):
name = "zhangsan" # 屬性
def getScore(self, score): # 方法
print("這個學生的分數(shù)是:", score)
# 獲取類的實例化對象
student2 = Student2()
# 訪問屬性
getName = student2.name
print(getName) # zhangsan
# 訪問方法
student2.getScore(80) # 這個學生的分數(shù)是: 80
2.3. 構(gòu)造函數(shù)
- 構(gòu)造函數(shù)
__init__()
:即對象的初始化,使用類創(chuàng)建對象的時候自動調(diào)用狂秘。
-----創(chuàng)建類的格式:
class 類名(父類1, 父類2...):
def __init__(self, 屬性1, 屬性2,...): # 屬性
self.屬性1 = 屬性1
self.屬性2 = 屬性2
...
def 方法函數(shù)(self, 方法參數(shù)1, 方法參數(shù)2, ...)
行為
-----訪問類
1. 使用類實例化對象
實例化對象格式:對象名 = 類名(屬性參數(shù)列表)
注:類沒有參數(shù)骇径,類名后的小括號也不可省略。
2. 訪問屬性
訪問屬性格式:對象名.屬性名
賦新值:對象名.屬性名 = 新值
3. 訪問方法
訪問方法格式:對象名.方法名(方法參數(shù)列表)
# 創(chuàng)建含構(gòu)造函數(shù)的類
class Student3(object):
def __init__(self, name):
self.name = name
def getScore(self, score):
print("這個學生的分數(shù)是:", score)
# 獲取類的實例化對象
student3 = Student3("liNing")
# 訪問屬性
print(student3.name) # liNing
# 訪問方法
student3.getScore("70") # 這個學生的分數(shù)是: 70
2.4. self介紹
- self代表類的實例者春,而非類破衔。
哪個對象調(diào)用方法,那么該方法中的self就代表哪個對象钱烟。
self不是python的關(guān)鍵字晰筛,將對象方法中的self換成其他標識符也可以嫡丙,但一般常規(guī)是用self。
1. -----類的內(nèi)部訪問屬性和方法-----
訪問屬性格式:self.屬性名
訪問方法格式:self.方法名(參數(shù))
獲取類名:self.__class__
2. -----類的外部訪問屬性和方法-----
訪問屬性格式:類的實例化對象.屬性名
訪問方法格式:類的實例化對象.方法(參數(shù))
"""類的內(nèi)部和外部分別獲取屬性和方法"""
class Student4(object):
def __init__(self, name):
self.name = name
def getScore(self, score):
return score
def getStudentInfo(self, score):
print("姓名:%s读第,分數(shù):%d" % (self.name, self.getScore(score))) # 類的內(nèi)部訪問屬性和方法
def getClassName(self): # 獲取類名
print(self.__class__)
def createObject(self): # 創(chuàng)建對象
newObject = self.__class__("LiHong")
print(newObject)
# 獲取類的實例化對象
student4 = Student4("LiMing")
# 類的外部訪問屬性
print(student4.name) # LiMing
# 類的外部訪問方法
student4.getStudentInfo(80) # 姓名:LiMing曙博,分數(shù):80
student4.getClassName() # <class '__main__.Student4'>
student4.createObject() # <__main__.Student4 object at 0x000000000234E240>
2.5. 析構(gòu)函數(shù)
- 析構(gòu)函數(shù)
__del__()
:釋放對象時自動調(diào)用,一般不需要手動添加析構(gòu)函數(shù)怜瞒。
只有當對象的引用數(shù)為0時才會自動調(diào)用析構(gòu)函數(shù)來回收資源父泳。
在函數(shù)中定義的對象,會在函數(shù)結(jié)束時自動釋放吴汪,以減小內(nèi)存空間的浪費惠窄。
del 對象:手動刪除對象時會調(diào)用析構(gòu)函數(shù)。對象釋放后不可再訪問此對象浇坐。
- 構(gòu)造函數(shù)和析構(gòu)函數(shù)的區(qū)別
創(chuàng)建一個對象時一定會調(diào)用構(gòu)造函數(shù)睬捶;
對象結(jié)束時一定會調(diào)用析構(gòu)函數(shù)。
class Student5(object):
def __init__(self, name):
self.name = name
def getScore(self, score):
return score
def getStudentInfo(self, score):
print("%s的分數(shù)是%d" % (self.name, self.getScore(score)))
def __del__(self):
print("這是個析構(gòu)函數(shù)")
student5 = Student5("LiMing")
print(student5.getScore(80))
student5.getStudentInfo(80)
# del student5 # 刪除student5對象
# student5.getStudentInfo() # 刪除student5對象后近刘,不可再使用此對象擒贸,否則會提示對象未被定義
print("代碼結(jié)束")
"""運行結(jié)果:
80
LiMing的分數(shù)是80
代碼結(jié)束
這是個析構(gòu)函數(shù)
"""
2.6. 類中特殊方法__str__()
和__repr__()
-
__str__()
:在調(diào)用print打印對象時自動調(diào)用,是給用戶使用的觉渴,是一個用來描述對象的方法介劫。
-
__repr__()
:在python解釋器中輸入對象名時,調(diào)用的方法案淋。
注意:在沒有__str__
座韵,但有__repr__
時,調(diào)用print打印對象時會自動調(diào)用__repr__
踢京。
優(yōu)點:當一個對象的屬性值很多誉碴,并且都需要打印多次時,可將屬性信息添加到此方法中瓣距,簡化代碼黔帕。
__str__()
和__repr__()
方法使用任意一種即可,一般使用__str__()
蹈丸。
class Student6(object):
def __init__(self, name, sex, score):
self.name = name
self.sex = sex
self.score = score
def getStudentInfo(self):
print("%s的分數(shù)是%d" % (self.name, self.score))
def __str__(self): # 這是個__str__函數(shù)
return "name=%s, sex=%s, score=%d" % (self.name, self.sex, self.score)
def __repr__(self): # 這是個__repr__函數(shù)
return "name=%s, sex=%s, score=%d" % (self.name, self.sex, self.score)
# 獲取類的實例化對象
student6 = Student6("LiMing", "female", 80)
# 打印對象
print(student6) # name=LiMing, sex=female, score=80
2.7. 類中私有屬性
- 在屬性前加兩個下劃線成黄,則表示該屬性為私有屬性。在類的外部不可使用或訪問私有屬性逻杖,但在類的內(nèi)部可以正常訪問奋岁。
- 若在類的外部直接訪問私有屬性,python解釋器會把該私有屬性名變?yōu)?code>_類名__私有屬性名(即_Person1__money)荸百,且不同的解釋器將該私有屬性名修改的名字可能不同闻伶,故不允許使用類直接訪問私有屬性。-----私有屬性并不是絕對私有
- 可通過自定義的方法修改私有屬性的值和獲取私有屬性的值-----類的外部間接訪問私有屬性管搪。
私有屬性一般會通過添加set方法和get方法來訪問虾攻。
- 在屬性前后均加兩個下劃線铡买,則該屬性并不是私有屬性,而是特殊變量霎箍,類內(nèi)外部均可直接訪問奇钞。
"""外部無法訪問私有屬性"""
class Person1(object):
def __init__(self, name, sex, money):
self.name = name
self.sex = sex
self.__money = money
def getInfo(self):
print("%s擁有%d錢" % (self.name, self.__money)) # 內(nèi)部可以使用私有屬性__money
person1 = Person1("LiMing", "female", 1000)
# print(person1.__money) # 報錯,外部無法訪問私有屬性__money
# person1.__money = 100 # 外部也可以訪問此私有屬性漂坏,但此私有屬性名已發(fā)生改變景埃,故不允許此用法
"""外部修改和獲取私有屬性的方法"""
class Person2(object):
def __init__(self, name, sex, money):
self.name = name
self.sex = sex
self.__money = money
def setMoney(self, money): # 修改私有屬性的值
if money < 0:
money = 0
self.__money = money
def getMoney(self): # 獲取私有屬性的值
return self.__money
person2 = Person2("LiMing", "female", 1000)
print(person2.getMoney()) # 1000
person2.setMoney(200)
print(person2.getMoney()) # 200
3. 面向?qū)ο蟮暮唵卫?/h3>
"""用例:人開車
分析:需要創(chuàng)建三個類,人顶别、車谷徙、油箱
人---類名:Person;屬性:car驯绎;方法:開車完慧、加油
車---類名:Car;屬性:油箱剩失;方法:車跑
油箱---類名:OilBox屈尼;屬性:油
"""
class OilBox(object):
"""創(chuàng)建一個油箱"""
def __init__(self, oil):
self.oil = oil
class Car(object):
"""創(chuàng)建一個車"""
def __init__(self, oilBox):
self.oilBox = oilBox # 油箱
def run(self):
"""車執(zhí)行跑操作"""
if self.oilBox.oil == 0:
print("沒有油了")
else:
self.oilBox.oil -= 10
print("剩余油量", self.oilBox.oil)
class Person(object):
"""創(chuàng)建一個人"""
def __init__(self, car):
self.car = car
def driver(self):
"""人要開車, 車要跑"""
self.car.run()
def addOil(self, oil):
"""給車加油"""
self.car.oilBox.oil = oil
"""使用面向?qū)ο髮崿F(xiàn)人開車操作"""
from Examples.Example1.person import Person
from Examples.Example1.car import Car
from Examples.Example1.oilBox import OilBox
oilBox = OilBox(100) # 創(chuàng)建一個油箱對象
car = Car(oilBox) # 創(chuàng)建一個車對象
person = Person(car) # 創(chuàng)建一個人對象
person.driver() # 人開車
person.addOil(200) # 人加油
person.driver()
三拴孤、繼承
1. 繼承定義
- 類A繼承類B脾歧,則繼承者(A)稱為子類(派生類),被繼承者(B)稱為父類(基類或超類)演熟。
object類是所有類的父類(基類或超類)鞭执。
子類可以直接使用父類中的屬性和方法,而不用重新編寫代碼芒粹;
子類可以重新定義父類中的某個屬性和重寫某個方法兄纺,從而覆蓋父類中原有的屬性和方法;
子類可以添加新的屬性和方法化漆。
- 繼承的優(yōu)點:簡化代碼囤热,減小冗余;提高了代碼的健壯性和安全性获三。
- 繼承的缺點:繼承的耦合性很高(因為父類發(fā)生改變,子類也會發(fā)生改變)锨苏。
耦合性:模塊之間相互聯(lián)系的緊密程度疙教,越緊密耦合性越強;
內(nèi)聚性:一個模塊內(nèi)部各個元素彼此結(jié)合的緊密程度伞租。
耦合與內(nèi)聚是描述類與類之間的關(guān)系的贞谓,耦合性越低內(nèi)聚性越高,代碼越好葵诈。
- 繼承分為:單繼承裸弦、多繼承祟同。
2. 單繼承
- 把數(shù)據(jù)及對數(shù)據(jù)的操作方法放在一起赵颅,作為一個相互依賴的整體虽另,這就是對象。
- 把對同類對象抽象出其共性饺谬,形成類捂刺。
類中的大多數(shù)數(shù)據(jù),只能用本類的方法進行處理商蕴;
類通過一個簡單的外部接口與外界發(fā)生聯(lián)系叠萍,對象與對象之間通過消息進行通信;
程序流程由用戶在使用中決定绪商; - 面向?qū)ο笫腔诿嫦蜻^程的苛谷。
- 面向?qū)ο笫菍⒐δ芊庋b成對象,強調(diào)的是具備功能的對象
- 面向?qū)ο罂梢詫碗s的事情簡單化
- 面向?qū)ο驩O(object-oriented)的三大特性:多態(tài)格郁、封裝腹殿、繼承独悴。
2. 類
2.1. 類的介紹
- 類是用來描述事件的屬性和行為動作。
屬性:對應(yīng)類中的成員變量锣尉;
行為:對應(yīng)類中成員方法或功能刻炒;
定義類就是定義類中的成員(成員變量和成員方法),擁有相同屬性和行為的對象都可以使用此類自沧。
設(shè)計類包括:類名坟奥、屬性、行為(方法/功能)拇厢。
2.2. 創(chuàng)建類
- 類是一種數(shù)據(jù)類型爱谁,本身并不占內(nèi)存空間。用類創(chuàng)建實例化對象(變量)孝偎,對象占內(nèi)存空間访敌。
- 類以class 關(guān)鍵詞開頭,后接類名(類名通常是以大寫開頭的單詞)
- 定義有繼承的類衣盾,則在類名后緊跟以括號括起來的父類名寺旺,表示該類是從此父類繼承下來的。一個類可以繼承多個類势决,類之間用逗號分隔阻塑。
若無合適的繼承類,可使用object類(object類是所有類最終都會繼承的類果复。)---object類又稱基類和超類叮姑。 - 類中定義的函數(shù),第一個參數(shù)永遠是self据悔,并且調(diào)用時不用傳遞該參數(shù)。self代表類的實例耘沼,即某個對象极颓。(注:沒有在類中定義的函數(shù),參數(shù)中無需添加變量self)
-----創(chuàng)建類的格式:
class 類名(父類1, 父類2...):
屬性
行為
-----訪問類
1. 使用類實例化對象
實例化對象格式:對象名 = 類名(參數(shù)列表)
注:類沒有參數(shù)群嗤,類名后的小括號也不可省略菠隆。
2. 訪問屬性
訪問屬性格式:對象名.屬性名
賦新值:對象名.屬性名 = 新值
3. 訪問方法
訪問方法格式:對象名.方法名(參數(shù)列表)
# 創(chuàng)建不含繼承的類
class Student1:
name = "zhangsan" # 屬性
def getScore(self, score): # 方法
print("這個學生的分數(shù)是:", score)
# 獲取類的實例化對象
student1 = Student1()
# 訪問屬性
getName = student1.name
print(getName) # zhangsan
# 訪問方法
student1.getScore(90) # 這個學生的分數(shù)是: 90
# 創(chuàng)建含繼承的類
class Student2(object):
name = "zhangsan" # 屬性
def getScore(self, score): # 方法
print("這個學生的分數(shù)是:", score)
# 獲取類的實例化對象
student2 = Student2()
# 訪問屬性
getName = student2.name
print(getName) # zhangsan
# 訪問方法
student2.getScore(80) # 這個學生的分數(shù)是: 80
2.3. 構(gòu)造函數(shù)
- 構(gòu)造函數(shù)
__init__()
:即對象的初始化,使用類創(chuàng)建對象的時候自動調(diào)用狂秘。
-----創(chuàng)建類的格式:
class 類名(父類1, 父類2...):
def __init__(self, 屬性1, 屬性2,...): # 屬性
self.屬性1 = 屬性1
self.屬性2 = 屬性2
...
def 方法函數(shù)(self, 方法參數(shù)1, 方法參數(shù)2, ...)
行為
-----訪問類
1. 使用類實例化對象
實例化對象格式:對象名 = 類名(屬性參數(shù)列表)
注:類沒有參數(shù)骇径,類名后的小括號也不可省略。
2. 訪問屬性
訪問屬性格式:對象名.屬性名
賦新值:對象名.屬性名 = 新值
3. 訪問方法
訪問方法格式:對象名.方法名(方法參數(shù)列表)
# 創(chuàng)建含構(gòu)造函數(shù)的類
class Student3(object):
def __init__(self, name):
self.name = name
def getScore(self, score):
print("這個學生的分數(shù)是:", score)
# 獲取類的實例化對象
student3 = Student3("liNing")
# 訪問屬性
print(student3.name) # liNing
# 訪問方法
student3.getScore("70") # 這個學生的分數(shù)是: 70
2.4. self介紹
- self代表類的實例者春,而非類破衔。
哪個對象調(diào)用方法,那么該方法中的self就代表哪個對象钱烟。
self不是python的關(guān)鍵字晰筛,將對象方法中的self換成其他標識符也可以嫡丙,但一般常規(guī)是用self。
1. -----類的內(nèi)部訪問屬性和方法-----
訪問屬性格式:self.屬性名
訪問方法格式:self.方法名(參數(shù))
獲取類名:self.__class__
2. -----類的外部訪問屬性和方法-----
訪問屬性格式:類的實例化對象.屬性名
訪問方法格式:類的實例化對象.方法(參數(shù))
"""類的內(nèi)部和外部分別獲取屬性和方法"""
class Student4(object):
def __init__(self, name):
self.name = name
def getScore(self, score):
return score
def getStudentInfo(self, score):
print("姓名:%s读第,分數(shù):%d" % (self.name, self.getScore(score))) # 類的內(nèi)部訪問屬性和方法
def getClassName(self): # 獲取類名
print(self.__class__)
def createObject(self): # 創(chuàng)建對象
newObject = self.__class__("LiHong")
print(newObject)
# 獲取類的實例化對象
student4 = Student4("LiMing")
# 類的外部訪問屬性
print(student4.name) # LiMing
# 類的外部訪問方法
student4.getStudentInfo(80) # 姓名:LiMing曙博,分數(shù):80
student4.getClassName() # <class '__main__.Student4'>
student4.createObject() # <__main__.Student4 object at 0x000000000234E240>
2.5. 析構(gòu)函數(shù)
- 析構(gòu)函數(shù)
__del__()
:釋放對象時自動調(diào)用,一般不需要手動添加析構(gòu)函數(shù)怜瞒。
只有當對象的引用數(shù)為0時才會自動調(diào)用析構(gòu)函數(shù)來回收資源父泳。
在函數(shù)中定義的對象,會在函數(shù)結(jié)束時自動釋放吴汪,以減小內(nèi)存空間的浪費惠窄。
del 對象:手動刪除對象時會調(diào)用析構(gòu)函數(shù)。對象釋放后不可再訪問此對象浇坐。 - 構(gòu)造函數(shù)和析構(gòu)函數(shù)的區(qū)別
創(chuàng)建一個對象時一定會調(diào)用構(gòu)造函數(shù)睬捶;
對象結(jié)束時一定會調(diào)用析構(gòu)函數(shù)。
class Student5(object):
def __init__(self, name):
self.name = name
def getScore(self, score):
return score
def getStudentInfo(self, score):
print("%s的分數(shù)是%d" % (self.name, self.getScore(score)))
def __del__(self):
print("這是個析構(gòu)函數(shù)")
student5 = Student5("LiMing")
print(student5.getScore(80))
student5.getStudentInfo(80)
# del student5 # 刪除student5對象
# student5.getStudentInfo() # 刪除student5對象后近刘,不可再使用此對象擒贸,否則會提示對象未被定義
print("代碼結(jié)束")
"""運行結(jié)果:
80
LiMing的分數(shù)是80
代碼結(jié)束
這是個析構(gòu)函數(shù)
"""
2.6. 類中特殊方法__str__()
和__repr__()
-
__str__()
:在調(diào)用print打印對象時自動調(diào)用,是給用戶使用的觉渴,是一個用來描述對象的方法介劫。 -
__repr__()
:在python解釋器中輸入對象名時,調(diào)用的方法案淋。
注意:在沒有__str__
座韵,但有__repr__
時,調(diào)用print打印對象時會自動調(diào)用__repr__
踢京。
優(yōu)點:當一個對象的屬性值很多誉碴,并且都需要打印多次時,可將屬性信息添加到此方法中瓣距,簡化代碼黔帕。
__str__()
和__repr__()
方法使用任意一種即可,一般使用__str__()
蹈丸。
class Student6(object):
def __init__(self, name, sex, score):
self.name = name
self.sex = sex
self.score = score
def getStudentInfo(self):
print("%s的分數(shù)是%d" % (self.name, self.score))
def __str__(self): # 這是個__str__函數(shù)
return "name=%s, sex=%s, score=%d" % (self.name, self.sex, self.score)
def __repr__(self): # 這是個__repr__函數(shù)
return "name=%s, sex=%s, score=%d" % (self.name, self.sex, self.score)
# 獲取類的實例化對象
student6 = Student6("LiMing", "female", 80)
# 打印對象
print(student6) # name=LiMing, sex=female, score=80
2.7. 類中私有屬性
- 在屬性前加兩個下劃線成黄,則表示該屬性為私有屬性。在類的外部不可使用或訪問私有屬性逻杖,但在類的內(nèi)部可以正常訪問奋岁。
- 若在類的外部直接訪問私有屬性,python解釋器會把該私有屬性名變?yōu)?code>_類名__私有屬性名(即_Person1__money)荸百,且不同的解釋器將該私有屬性名修改的名字可能不同闻伶,故不允許使用類直接訪問私有屬性。-----私有屬性并不是絕對私有
- 可通過自定義的方法修改私有屬性的值和獲取私有屬性的值-----類的外部間接訪問私有屬性管搪。
私有屬性一般會通過添加set方法和get方法來訪問虾攻。 - 在屬性前后均加兩個下劃線铡买,則該屬性并不是私有屬性,而是特殊變量霎箍,類內(nèi)外部均可直接訪問奇钞。
"""外部無法訪問私有屬性"""
class Person1(object):
def __init__(self, name, sex, money):
self.name = name
self.sex = sex
self.__money = money
def getInfo(self):
print("%s擁有%d錢" % (self.name, self.__money)) # 內(nèi)部可以使用私有屬性__money
person1 = Person1("LiMing", "female", 1000)
# print(person1.__money) # 報錯,外部無法訪問私有屬性__money
# person1.__money = 100 # 外部也可以訪問此私有屬性漂坏,但此私有屬性名已發(fā)生改變景埃,故不允許此用法
"""外部修改和獲取私有屬性的方法"""
class Person2(object):
def __init__(self, name, sex, money):
self.name = name
self.sex = sex
self.__money = money
def setMoney(self, money): # 修改私有屬性的值
if money < 0:
money = 0
self.__money = money
def getMoney(self): # 獲取私有屬性的值
return self.__money
person2 = Person2("LiMing", "female", 1000)
print(person2.getMoney()) # 1000
person2.setMoney(200)
print(person2.getMoney()) # 200
3. 面向?qū)ο蟮暮唵卫?/h3>
"""用例:人開車
分析:需要創(chuàng)建三個類,人顶别、車谷徙、油箱
人---類名:Person;屬性:car驯绎;方法:開車完慧、加油
車---類名:Car;屬性:油箱剩失;方法:車跑
油箱---類名:OilBox屈尼;屬性:油
"""
class OilBox(object):
"""創(chuàng)建一個油箱"""
def __init__(self, oil):
self.oil = oil
class Car(object):
"""創(chuàng)建一個車"""
def __init__(self, oilBox):
self.oilBox = oilBox # 油箱
def run(self):
"""車執(zhí)行跑操作"""
if self.oilBox.oil == 0:
print("沒有油了")
else:
self.oilBox.oil -= 10
print("剩余油量", self.oilBox.oil)
class Person(object):
"""創(chuàng)建一個人"""
def __init__(self, car):
self.car = car
def driver(self):
"""人要開車, 車要跑"""
self.car.run()
def addOil(self, oil):
"""給車加油"""
self.car.oilBox.oil = oil
"""使用面向?qū)ο髮崿F(xiàn)人開車操作"""
from Examples.Example1.person import Person
from Examples.Example1.car import Car
from Examples.Example1.oilBox import OilBox
oilBox = OilBox(100) # 創(chuàng)建一個油箱對象
car = Car(oilBox) # 創(chuàng)建一個車對象
person = Person(car) # 創(chuàng)建一個人對象
person.driver() # 人開車
person.addOil(200) # 人加油
person.driver()
三拴孤、繼承
1. 繼承定義
- 類A繼承類B脾歧,則繼承者(A)稱為子類(派生類),被繼承者(B)稱為父類(基類或超類)演熟。
object類是所有類的父類(基類或超類)鞭执。
子類可以直接使用父類中的屬性和方法,而不用重新編寫代碼芒粹;
子類可以重新定義父類中的某個屬性和重寫某個方法兄纺,從而覆蓋父類中原有的屬性和方法;
子類可以添加新的屬性和方法化漆。
- 繼承的優(yōu)點:簡化代碼囤热,減小冗余;提高了代碼的健壯性和安全性获三。
- 繼承的缺點:繼承的耦合性很高(因為父類發(fā)生改變,子類也會發(fā)生改變)锨苏。
耦合性:模塊之間相互聯(lián)系的緊密程度疙教,越緊密耦合性越強;
內(nèi)聚性:一個模塊內(nèi)部各個元素彼此結(jié)合的緊密程度伞租。
耦合與內(nèi)聚是描述類與類之間的關(guān)系的贞谓,耦合性越低內(nèi)聚性越高,代碼越好葵诈。
- 繼承分為:單繼承裸弦、多繼承祟同。
2. 單繼承
"""用例:人開車
分析:需要創(chuàng)建三個類,人顶别、車谷徙、油箱
人---類名:Person;屬性:car驯绎;方法:開車完慧、加油
車---類名:Car;屬性:油箱剩失;方法:車跑
油箱---類名:OilBox屈尼;屬性:油
"""
class OilBox(object):
"""創(chuàng)建一個油箱"""
def __init__(self, oil):
self.oil = oil
class Car(object):
"""創(chuàng)建一個車"""
def __init__(self, oilBox):
self.oilBox = oilBox # 油箱
def run(self):
"""車執(zhí)行跑操作"""
if self.oilBox.oil == 0:
print("沒有油了")
else:
self.oilBox.oil -= 10
print("剩余油量", self.oilBox.oil)
class Person(object):
"""創(chuàng)建一個人"""
def __init__(self, car):
self.car = car
def driver(self):
"""人要開車, 車要跑"""
self.car.run()
def addOil(self, oil):
"""給車加油"""
self.car.oilBox.oil = oil
"""使用面向?qū)ο髮崿F(xiàn)人開車操作"""
from Examples.Example1.person import Person
from Examples.Example1.car import Car
from Examples.Example1.oilBox import OilBox
oilBox = OilBox(100) # 創(chuàng)建一個油箱對象
car = Car(oilBox) # 創(chuàng)建一個車對象
person = Person(car) # 創(chuàng)建一個人對象
person.driver() # 人開車
person.addOil(200) # 人加油
person.driver()
object類是所有類的父類(基類或超類)鞭执。
子類可以直接使用父類中的屬性和方法,而不用重新編寫代碼芒粹;
子類可以重新定義父類中的某個屬性和重寫某個方法兄纺,從而覆蓋父類中原有的屬性和方法;
子類可以添加新的屬性和方法化漆。
耦合性:模塊之間相互聯(lián)系的緊密程度疙教,越緊密耦合性越強;
內(nèi)聚性:一個模塊內(nèi)部各個元素彼此結(jié)合的緊密程度伞租。
耦合與內(nèi)聚是描述類與類之間的關(guān)系的贞谓,耦合性越低內(nèi)聚性越高,代碼越好葵诈。
單繼承即僅繼承一個類。
2.1. 子類屬性的繼承和重寫
- 子類中無構(gòu)造函數(shù)
子類中若無構(gòu)造函數(shù)理疙,則子類也可直接使用父類的屬性晕城。 - 子類中構(gòu)造函數(shù)的重寫
父類中存在構(gòu)造函數(shù),子類中也有構(gòu)造函數(shù)窖贤,則子類的構(gòu)造函數(shù)需要調(diào)用父類的構(gòu)造函數(shù)砖顷。
子類構(gòu)造函數(shù)中也可添加有新的屬性。
子類中構(gòu)造函數(shù)調(diào)用父類構(gòu)造函數(shù)有兩種方法:
第一種:父類.__init__(self, 參數(shù)1, 參數(shù)2, ...)
第二種:super(子類, self).__init__(參數(shù)1, 參數(shù)2, ...)
2.2. 子類方法的繼承和重寫
- 子類中無與父類相同的方法赃梧,則子類可以直接使用父類的方法滤蝠。
- 子類中存在與父類相同的方法,則子類的方法會覆蓋父類的方法授嘀。
2.3. 子類繼承單個父類的例子
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self, food):
print("%s正在吃%s" % (self.name, food))
"""------子類使用父類的屬性和方法------"""
class Teacher1(Person):
pass
# 子類使用父類的屬性
teacher1 = Teacher1("A", 20)
print(teacher1.name, teacher1.age) # A 20
# 子類使用父類的方法
teacher1.eat("rice") # A正在吃rice
"""------子類重寫父類的屬性物咳、直接使用父類的方法------"""
class Teacher2(Person):
def __init__(self, name, age):
"""子類重寫父類屬性"""
# Person.__init__(self, name, age) # 重寫構(gòu)造函數(shù)的第一種方法
super(Teacher2, self).__init__(name, age) # 重寫構(gòu)造函數(shù)的第二種方法
# 子類使用父類的屬性
teacher2 = Teacher2("A", 20)
print(teacher2.name, teacher2.age) # A 20
# 子類直接使用父類的方法
teacher2.eat("fish") # A正在吃fish
"""------子類重寫父類屬性且添加新的屬性,子類重寫父類方法------"""
class Teacher3(Person):
def __init__(self, name, age, sex):
"""子類重寫父類屬性"""
# Person.__init__(self, name, age) # 重寫構(gòu)造函數(shù)的第一種方法
super(Teacher3, self).__init__(name, age) # 重寫構(gòu)造函數(shù)的第二種方法
self.sex = sex
def eat(self, food):
"""子類重寫父類方法"""
print("%s is eating %s" % (self.name, food))
teacher3 = Teacher3("A", 20, "female")
print(teacher3.name, teacher3.age, teacher3.sex) # A 20 female
# 子類直接使用父類的方法
teacher3.eat("fish") # A is eating fish
3. 多繼承
多繼承即同時繼承多個類蹄皱。
3.1. 子類屬性的繼承和重寫
- 子類需要重寫父類的構(gòu)造函數(shù)览闰,且也可添加屬于自己的新屬性。
子類構(gòu)造函數(shù)中也可添加有新的屬性夯接。
父類1.__init__(self, 參數(shù)1, 參數(shù)2, ...)
父類2.__init__(self, 參數(shù)1, 參數(shù)2, ...)
...
父類n.__init__(self, 參數(shù)1, 參數(shù)2, ...)
3.2. 子類方法的繼承和重寫
- 子類繼承多個父類焕济,且父類中存在相同的方法名。
若子類中未重寫此方法盔几,子類使用此方法時晴弃,默認調(diào)用的是括號中排在前面的父類方法;
若子類中重寫有此方法逊拍,則會使用子類中的方法上鞠。
3.3. 子類繼承多個父類的例子
- 子類Person既是程序員又是廚師
class Programmer(object): # 程序員
def __init__(self, language):
self.language = language
def writeCode(self):
print("用%s語言寫代碼" % self.language)
def phone(self):
print("程序員在打電話")
class Chef(object): # 廚師
def __init__(self, food):
self.food = food
def cooking(self):
print("烹飪%s" % self.food)
def phone(self):
print("廚師在打電話")
"""------子類繼承多個父類,子類重寫父類的屬性------"""
class Person1(Programmer, Chef):
def __init__(self, name, age, language, food):
"""子類重寫父類屬性"""
Programmer.__init__(self, language)
Chef.__init__(self, food)
self.name = name
self.age = age
# 創(chuàng)建類的實例化對象
person1 = Person1("A", 18, "Python", "fish")
# 對象的屬性
print(person1.name, person1.age, person1.language, person1.food) # A 18 Python fish
# 子類使用父類方法
person1.writeCode() # 用Python語言寫代碼
person1.cooking() # 烹飪fish
# 父類存在相同的方法芯丧,子類使用時默認使用括號中排名在前的方法
person1.phone() # 程序員在打電話
"""------子類繼承多個父類芍阎,子類重寫父類的屬性且重寫父類方法------"""
class Person2(Programmer, Chef):
def __init__(self, name, age, language, food):
"""子類重寫父類屬性"""
Programmer.__init__(self, language)
Chef.__init__(self, food)
self.name = name
self.age = age
def phone(self):
print("%s在打電話" % self.name)
person2 = Person2("A", 20, "Python", "fish")
person2.phone() # A在打電話
四、多態(tài)
多態(tài):一種事件的多種形態(tài)缨恒。意味著即使不知道變量指向什么對象谴咸,也能夠?qū)Υ藢ο髨?zhí)行操作,且操作的行為跟隨對象所必的類型而變骗露。
class Animal(object):
def __init__(self, name):
self.name = name
def run(self):
print("%s在跑步" % self.name)
"""采用多態(tài)方式實現(xiàn)"""
class Person(object):
def leadAnimalRun(self, animal): # animal采用的多態(tài)方式
print("人訓練動物跑步")
animal.run()
person = Person()
cat = Animal("Cat")
person.leadAnimalRun(cat)
dog = Animal("Dog")
person.leadAnimalRun(dog)
五岭佳、對象屬性和類屬性
一個類所包含的屬性有:對象屬性和類屬性。
1. 類屬性
- 在類中萧锉,方法外面定義的變量稱為類屬性珊随。
在類的內(nèi)部和外部,類屬性值均可以通過類或?qū)ο髞碓L問,但只能通過類來修改叶洞。
1.1. 訪問類屬性
- 通過類訪問類屬性
在類的內(nèi)部和外部訪問:類名.類屬性
- 通過對象訪問類屬性
在類的內(nèi)部訪問:self.類屬性
在類的外部訪問:實例化對象.類屬性
1.2. 修改類屬性
-
類名.類屬性 = 新值
通過類來修改類屬性值鲫凶,由于按全局變量的方式修改,則整個類中的此屬性值均發(fā)生變化衩辟。 -
self.類屬性 = 新值
或實例化對象.類屬性 = 新值
此方法相當于把類屬性變成實例化對象屬性螟炫,相當于局部變量,僅會對當前對象生效惭婿,對此類創(chuàng)建的其他對象不生效不恭。
2. 對象屬性
- 在類中,
__init()__
方法中定義的屬性稱為對象屬性财饥。
在類的內(nèi)部訪問:self.對象屬性
在類的內(nèi)部修改值:self.對象屬性 = 新值
在類的外部訪問:實例化對象.對象屬性
在類的外部修改值:實例化對象.對象屬性 = 新值
- 可動態(tài)的給對象添加新的對象屬性换吧,但此對象只對當前對象生效,對此類創(chuàng)建的其他對象無用钥星。
- 在同一類中沾瓦,若類屬性名與對象屬性名相同,則對象屬性的優(yōu)先級高于類屬性谦炒。
class Person1(object):
count = 0 # 類屬性
def __init__(self, name): # 對象屬性
self.name = name
def testClassAttribute(self):
"""通過類修改類屬性值"""
Person1.count = 50 # 通過類名的方式給類屬性值賦新值贯莺,相當于全局變量
print(Person1.count) # 50
print(self.count) # 50
"""通過對象修改類屬性值"""
self.count = 60 # 通過對象的方式給類屬性值賦新值,相當于局部變量宁改,僅對當前對象生效
print(Person1.count) # 50
print(self.count) # 60
def testObjectAttribute(self):
"""對象屬性"""
self.name = 'B'
print(self.name) # B
person1 = Person1("A")
person1.testClassAttribute()
print(Person1.count) # 50
print(person1.count) # 60
person1.testObjectAttribute()
person1.name = "C" # 類外部修改對象屬性值
person1.age = 20 # 類外部新建新的屬性缕探,并賦值
print(person1.name, person1.age) # C 20
六、動態(tài)給實例添加屬性和方法
1. 動態(tài)給實例添加屬性和方法
- 動態(tài)給實例添加屬性
實例對象.新屬性 = 屬性值 - 動態(tài)給實例添加方法
先導入模塊from types import MethodType
實例對象.新方法 = MethodType(方法名, 實例對象)
class Person(object):
pass
person = Person()
"""給對象動態(tài)添加屬性"""
person.name = "LiMing"
print(person.name) # LiMing
"""給對象動態(tài)添加方法"""
from types import MethodType
def getAge(self, age):
print("%s的年齡:%d" % (self.name, age))
person.ageMethod = MethodType(getAge, person)
person.ageMethod(20) # LiMing的年齡:20
2. 限制對象中添加的動態(tài)屬性
定義類時定義一個特殊的屬性__slots__
还蹲,此屬性可限制動態(tài)添加的屬性爹耗。
from types import MethodType
class Student:
__slots__ = ("name", "age", "sex", "scoreInfo") # 表示給Student類添加屬性時僅可添加name、age谜喊、sex潭兽、scoreInfo
student = Student()
student.name = "LiHong"
print(student.name) # LiHong
# student.work = "Doctor" # 會報錯提示此對象無work屬性
# print(student.work)
def getScore(self, score):
print("%s的分數(shù):%d" % (self.name, score))
student.scoreInfo = MethodType(getScore, student)
student.scoreInfo(90) # LiHong的分數(shù):90
七、運算符重載
對兩個對象執(zhí)行運算操作斗遏,則提示類型不支持(TypeError: unsupported operand type(s))山卦,因此需要借助運算符重載。
1. 常用的運算符重載
構(gòu)造函數(shù)__init__
解析函數(shù)__del__
打印函數(shù)__repr__诵次、__str__
函數(shù)調(diào)用__call__
函數(shù)屬性__getattr__账蓉、__setattr__、__delattr__
數(shù)字運算符函數(shù):__add__(self, other)逾一、__sub__(self, other)剔猿、__mul__(self, other)、__div__(self, other)
...
class Student:
def __init__(self, score):
self.score = score
def __add__(self, other):
return Student(self.score + other.score)
def __str__(self):
return "score=%d" % self.score
student1 = Student(70)
student2 = Student(80)
print(student1 + student2) # score=150
print(student1.__add__(student2).score) # 150
2. __call__
介紹:
__call__
是一個可調(diào)用對象嬉荆,而函數(shù)和類都屬于可調(diào)用對象。
通過__call__
方法可以將一個類實例化對象變成一個可調(diào)用對象酷含。使用__call__
還可以
class Person:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def __call__(self, name, sex):
self.name = name
self.sex = sex
person = Person("LiMing", 20, "female") # 實例化對象
person("LiHong", "male") # 將實例變?yōu)榭烧{(diào)用的對象
print(person.name, person.sex, person.age) # LiHong male 20