Python入門(mén)課程系列:
- Python學(xué)習(xí) day1:認(rèn)識(shí)Python
- Python學(xué)習(xí) day2:判斷語(yǔ)句與循環(huán)控制
- Python學(xué)習(xí) day3:高級(jí)數(shù)據(jù)類(lèi)型
- Python學(xué)習(xí) day4:函數(shù)基礎(chǔ)
- Python學(xué)習(xí) day5:函數(shù)
- Python學(xué)習(xí) day6:內(nèi)置函數(shù)
- Python學(xué)習(xí) day7:面向?qū)ο蠡A(chǔ)·上
- Python學(xué)習(xí) day8:面向?qū)ο蠡A(chǔ)·中
目標(biāo):
- 通過(guò)聲明私有化屬性谍咆、方法虹统,保護(hù)和控制數(shù)據(jù)(重點(diǎn))
- 通過(guò)property屬性的使用,即控制好數(shù)據(jù)又方便訪(fǎng)問(wèn)(重點(diǎn)童叠、難點(diǎn))
- 明確 _ new _ 方法的作用和用法(重點(diǎn))
- 通過(guò)單例模式控制實(shí)例個(gè)數(shù)(難點(diǎn))
- 使用異常處理機(jī)制鲜结,處理異常媒至,提高代碼健壯性
- 利用動(dòng)態(tài)語(yǔ)言特點(diǎn)今膊,動(dòng)態(tài)添加屬性和方法
- 利用 _ slot _ 屬性控制可動(dòng)態(tài)的屬性
1. 私有化屬性
前面學(xué)習(xí)面對(duì)對(duì)象過(guò)程中崎苗,修改類(lèi)屬性都是直接通過(guò)類(lèi)名修改的狐粱。如果有些重要屬性不想被被人修改,或者防止意外修改胆数,就可以將屬性定義為私有屬性肌蜻,并添加一個(gè)可調(diào)用的方式去訪(fǎng)問(wèn)。
語(yǔ)法:兩個(gè)下劃線(xiàn)開(kāi)頭必尼,聲明該屬性為私有蒋搜,不能在類(lèi)的外部被使用或直接訪(fǎng)問(wèn)。
使用私有屬性的場(chǎng)景:1. 把特定的一個(gè)屬性隱藏起來(lái)判莉,不想被類(lèi)的外部直接調(diào)用豆挽;2. 保護(hù)屬性的值不被隨意改變;3. 保護(hù)屬性不被派生類(lèi)【子類(lèi)】繼承
class Person:
def __init__(self):
self.__name='lele' #實(shí)例屬性前加兩個(gè)下劃線(xiàn)將其私有化
self.age=14
pass
def __str__(self):
return '{}的年齡是{}'.format(self.__name,self.age) #私有化的屬性在內(nèi)部可以使用
yt=Person()
print(yt.__name) #私有化后不能在類(lèi)的外部直接訪(fǎng)問(wèn)
# AttributeError: 'Person' object has no attribute '__name'
print(yt) #在類(lèi)的內(nèi)部依然可以使用
#lele的年齡是14
class Student(Person):
pass
stu=Student()
print(stu.__name) #父類(lèi)的私有化屬性券盅,子類(lèi)不能繼承
# AttributeError: 'Person' object has no attribute '__name'
小結(jié):
- 私有化的【實(shí)例】屬性不能在外部直接訪(fǎng)問(wèn)帮哈,但可以在類(lèi)的內(nèi)部可以訪(fǎng)問(wèn)、修改锰镀。
- 子類(lèi)不能繼承父類(lèi)的私有化屬性娘侍,只能繼承父類(lèi)公共的屬性和行為
- 在屬性前面加兩個(gè)下劃線(xiàn)就可以定義私有屬性
2. 私有化方法
私有化方法與私有化屬性一樣咖刃,有些重要的方法,不允許外部調(diào)用憾筏,防止子類(lèi)意外重寫(xiě)僵缺,把普通的方法設(shè)置成私有化方法。
語(yǔ)法:在方法名前面加兩個(gè)下劃線(xiàn)
class Animal:
def __eat(self): #實(shí)例方法
print('乖乖吃')
pass
def run(self):
print('飛快跑')
pass
class Bird(Animal):
pass
b1=Bird()
b1.run()
#飛快跑
b1.__eat()
#AttributeError: 'Bird' object has no attribute '__eat'
訪(fǎng)問(wèn)和修改私有變量:
一般寫(xiě)兩個(gè)方法一個(gè)訪(fǎng)問(wèn)踩叭,一個(gè)修改磕潮,由方法去控制訪(fǎng)問(wèn)。
class Person:
def __init__(self):
self.__age=18 #定義一個(gè)私有化屬性容贝,屬性名字前面加兩個(gè)__下劃線(xiàn)
def get_age(self): #訪(fǎng)問(wèn)私有類(lèi)屬性
return self.__age
def set_age(self,age): #修改私有屬性
if age<0:
print('年齡不能小于0')
else:
self.__age=age
(這樣操作給調(diào)用者的感覺(jué)就是調(diào)用了一個(gè)方法自脯,并不是訪(fǎng)問(wèn)屬性。如何讓調(diào)用者直接以訪(fǎng)問(wèn)屬性的方式訪(fǎng)問(wèn)而且以我們能控制的方式提供給調(diào)用者斤富?這是就可以使用屬性函數(shù)property膏潮。)
單下劃線(xiàn)、雙下劃線(xiàn)满力、頭尾下劃線(xiàn)說(shuō)明:
- _ xxx前面加一個(gè)下劃線(xiàn)焕参,以單下劃線(xiàn)開(kāi)頭的表示是protected類(lèi)型的變量,即保護(hù)類(lèi)型只允許其本身與子類(lèi)訪(fǎng)問(wèn)油额,不能使用from xxx import*的方式導(dǎo)入叠纷。(一般使用雙前下劃線(xiàn))
- _ xxx _ 前后兩個(gè)下劃線(xiàn),為魔法方法潦嘶,一般是python自有涩嚣,開(kāi)發(fā)者不要?jiǎng)?chuàng)建這類(lèi)型的方法。
- xxx _ 后單下劃線(xiàn)掂僵,避免屬性名與python關(guān)鍵字沖突
3. Property屬性
前面學(xué)習(xí)中航厚,我們一直在用“類(lèi)對(duì)象.屬性”的方式訪(fǎng)問(wèn)類(lèi)中定義的屬性,其實(shí)這種做法是欠妥的锰蓬,因?yàn)樗茐牧祟?lèi)的封裝原則幔睬。正常情況下,類(lèi)包含的屬性應(yīng)該是隱藏的芹扭,只允許通過(guò)類(lèi)提供的方法來(lái)間接實(shí)現(xiàn)對(duì)類(lèi)屬性的訪(fǎng)問(wèn)和操作麻顶。因此,在不破壞類(lèi)封裝原則的基礎(chǔ)上冯勉,為了能夠有效操作類(lèi)中的屬性澈蚌,類(lèi)中應(yīng)包含讀(或?qū)懀╊?lèi)屬性的多個(gè) getter(或 setter)方法,這樣就可以通過(guò)“類(lèi)對(duì)象.方法(參數(shù))”的方式操作屬性灼狰。此外宛瞄,Python 中提供了 property() 函數(shù),可以實(shí)現(xiàn)在不破壞類(lèi)封裝原則的前提下,讓開(kāi)發(fā)者依舊使用“類(lèi)對(duì)象.屬性”的方式操作類(lèi)中的屬性份汗。
實(shí)現(xiàn)方式:
1.在類(lèi)型定義值為property對(duì)象的類(lèi)屬性
property() 函數(shù)的基本使用格式:
屬性名=property(fget=None, fset=None, fdel=None, doc=None)盈电。
fget 參數(shù):用于指定獲取該屬性值的類(lèi)方法。
fset 參數(shù):用于指定設(shè)置該屬性值的方法杯活。
fdel 參數(shù):用于指定刪除該屬性值的方法
doc 參數(shù):是一個(gè)文檔字符串匆帚,用于說(shuō)明此函數(shù)的作用。
在使用 property() 函數(shù)時(shí)旁钧,以上 4 個(gè)參數(shù)可以?xún)H指定第 1 個(gè)吸重、或者前 2 個(gè)、或者前 3 個(gè)歪今,當(dāng)前也可以全部指定嚎幸。也就是說(shuō),property() 函數(shù)中參數(shù)的指定并不是完全隨意的寄猩。
#方法1
class Person(object):
def __init__(self):
self.__age=18 # 定義一個(gè)函數(shù)嫉晶,屬性名字前面加兩個(gè)下劃線(xiàn)
def get_age(self): # 訪(fǎng)問(wèn)私有化實(shí)例屬性
return self.__age
def set_age(self,age): # 修改私有化實(shí)例屬性
if age < 0:
print('年齡不能小于0')
else:
self.__age=age
age=property(get_age,set_age)
# 定義一個(gè)類(lèi)屬性,當(dāng)對(duì)這個(gè)age設(shè)置值時(shí)調(diào)用set_age田篇,當(dāng)獲取值時(shí)調(diào)用get_age.注意:必須時(shí)以get,set開(kāi)頭的方法名替废,才能被調(diào)用。
#通過(guò)調(diào)用函數(shù)property并將存取方法作為參數(shù)創(chuàng)建了一個(gè)特性泊柬,然后將名稱(chēng)age關(guān)聯(lián)到這個(gè)特性椎镣。這樣就能以同樣的方式對(duì)待get_age、set_age和age彬呻,而無(wú)需關(guān)心它們是如何實(shí)現(xiàn)的衣陶。
xiaoming=Person()
print(xiaoming.age) #若不設(shè)置property,這一行會(huì)報(bào)錯(cuò)
#18
xiaoming.age=15 #只需設(shè)置age即可闸氮,不必管類(lèi)的內(nèi)部get_age和set_age是如何運(yùn)作。通過(guò)property封裝的age是類(lèi)的接口
print(xiaoming.age)
#15
#方法2
class Person(object):
def __init__(self):
self.__age=18 # 定義一個(gè)函數(shù)教沾,屬性名字前面加兩個(gè)下劃線(xiàn)
@property #使用裝飾器對(duì)age進(jìn)行裝飾蒲跨,提供一個(gè)getter方法
def age(self): # 訪(fǎng)問(wèn)私有化實(shí)例屬性
return self.__age
@age.setter # 使用裝飾器進(jìn)行裝飾,提供一個(gè)setter方法
def age(self,age): # 修改私有實(shí)例屬性
if age < 0:
print('年齡不能小于0')
else:
self.__age=age
xiaoming=Person()
print(xiaoming.age)
#18
xiaoming.age=15
print(xiaoming.age)
#15
修改私有屬性的途徑:
- 通過(guò)方法去實(shí)現(xiàn)(set get)
- 借助屬性函數(shù)property去實(shí)現(xiàn)
4. _ new _ 方法
- _ new _ 方法的作用是:創(chuàng)建并返回一個(gè)實(shí)例對(duì)象授翻,如果 _ new _ 方法只調(diào)用了一次或悲,就會(huì)得到一個(gè)對(duì)象。繼承自object的新式類(lèi)才有new這一魔法方法堪唐。
- 注意事項(xiàng)
- _ new _ 是在一個(gè)對(duì)象實(shí)例化的時(shí)候所調(diào)用的第一個(gè)方法
- _ new _ 至少必須要有一個(gè)參數(shù)cls巡语,代表要實(shí)例化的類(lèi) ,此參數(shù)在實(shí)例化時(shí)由Python解釋器自動(dòng)提供淮菠,其他參數(shù)是要來(lái)直接傳遞給_ init _ 方法
- _ new _ 決定是否要使用該 _ init _ 方法男公,因?yàn)?_ new _ 可以調(diào)用其他類(lèi)的構(gòu)造方法或者直接返回別的實(shí)例對(duì)象來(lái)作為本類(lèi)的實(shí)例,如果 _ new _ 沒(méi)有返回實(shí)例對(duì)象合陵,則 _ init _ 不會(huì)被調(diào)用
- 在 _ new _ 方法中枢赔,不能調(diào)用自己的 _ new _ 方法澄阳,即:return cls. _ new _ (cls),否則會(huì)報(bào)錯(cuò)(RescursionError: maximum recursion depth exceeded:超過(guò)最大遞歸深度)
- 盡管沒(méi)有添加標(biāo)識(shí)踏拜,但new方法是一個(gè)靜態(tài)方法
class Animal():
def __init__(self):
self.color='紅色'
pass
#在python當(dāng)中碎赢,如果不重寫(xiě)new方法,如下是默認(rèn)的new
def __new__(cls, *args, **kwargs): #cls表示當(dāng)前class
#方法1 用super來(lái)創(chuàng)建
return super().__new__(cls, *args, **kwargs) #super是調(diào)用父類(lèi)
#方法2 用object來(lái)創(chuàng)建
return object.__new__(cls, *args, **kwargs)
pass
tiger=Animal() #實(shí)例化的過(guò)程中會(huì)自動(dòng)調(diào)用new去創(chuàng)建實(shí)例
print(tiger.color)
#紅色
在新式類(lèi)(python3)中速梗,_ new _ 才是真正的實(shí)例化方法肮塞,為類(lèi)提供外殼制造出實(shí)例框架,然后調(diào)用該框架內(nèi)的構(gòu)造方法 _ init _ 來(lái)進(jìn)行豐滿(mǎn)操作姻锁。
以建房子來(lái)比喻峦嗤,new方法負(fù)責(zé)開(kāi)發(fā)地皮,打地基屋摔,并將原料存放在工地上烁设,而init負(fù)責(zé)從工地取原料,建造出地皮開(kāi)發(fā)圖紙規(guī)定的大樓钓试,并負(fù)責(zé)細(xì)節(jié)設(shè)計(jì)装黑、建造、最終完成弓熏。
5. 單例模式
單例模式要求一個(gè)類(lèi)有且只有一個(gè)實(shí)例恋谭,并且提供了一個(gè)全局的訪(fǎng)問(wèn)點(diǎn)。
- 單例模式是常用設(shè)計(jì)模式的一種挽鞠。目的:確保某一個(gè)類(lèi)只有一個(gè)實(shí)例存在疚颊。就比如我們打開(kāi)電腦的回收站 ,在系統(tǒng)中只能打開(kāi)一個(gè)回收站信认,也就是說(shuō)這整個(gè)系統(tǒng)中只有一個(gè)實(shí)例材义,重復(fù)打開(kāi)也是使用這個(gè)實(shí)例。
- 簡(jiǎn)單的說(shuō)就是不管創(chuàng)建多少次對(duì)象嫁赏,類(lèi)返回的對(duì)象都是最初創(chuàng)建的其掂,不會(huì)再新建其他對(duì)象。
#基于 _ new _ 方法實(shí)現(xiàn)單例對(duì)象的創(chuàng)建
#例1
class SingleCase(object):
__instance=None #保存實(shí)例對(duì)象
def __init__(self,name,age):
print(name,age)
def __new__(cls, *args, **kwargs):
#如果類(lèi)屬性__instance的值為None,那么創(chuàng)建一個(gè)對(duì)象
#如果類(lèi)屬性__instance的值不為None,返回 __instance保存的對(duì)象
if not cls.__instance:
cls.__instance=super(SingleCase, cls).__new__(cls) #調(diào)用父類(lèi)_new_方法生成一個(gè)實(shí)例對(duì)象
return cls.__instance
else:
return cls.__instance
obj1=SingleCase('huahua',18)
obj2=SingleCase('miao',8)
print(id(obj1))
print(id(obj2))
#huahua 18
#miao 8
#140691412397840 #id相同潦蝇,說(shuō)明實(shí)例化兩次對(duì)象款熬,實(shí)際上都是一個(gè)對(duì)象
#140691412397840
#例2
class DataBaseClass(object):
def __new__(cls, *args, **kwargs):
# cls._instance=cls.__new__(cls) 不能使用自身的new方法,容易造成一個(gè)深度遞歸攘乒,應(yīng)該調(diào)用父類(lèi)的new方法
if not hasattr(cls,'_instance'): #如果不存在就開(kāi)始創(chuàng)建
#hasattr()函數(shù)用于判斷對(duì)象是否包含對(duì)應(yīng)的屬性
cls._instance=super().__new__(cls, *args, **kwargs)
return cls._instance
pass
db1=DataBaseClass()
print(id(db1))
db2=DataBaseClass()
print(id(db2))
#140663654493968
#140663654493968 #并不是只能返回同一個(gè)對(duì)象贤牛,而是每次返回相同的對(duì)象
利用類(lèi)屬性保存初次創(chuàng)建的實(shí)例對(duì)象,第二次實(shí)例化的 時(shí)候就判斷類(lèi)屬性是否有保存實(shí)例對(duì)象 则酝,如果有就返回類(lèi)屬性保存的殉簸,如果沒(méi)有就調(diào)用父類(lèi) _ new _ 方法創(chuàng)建新的實(shí)例對(duì)象
- 應(yīng)用 :網(wǎng)站的計(jì)數(shù)器模塊、權(quán)限驗(yàn)證模塊、windows資源管理器喂链、系統(tǒng)回收站返十、數(shù)據(jù)庫(kù)連接池等等
6. 錯(cuò)誤與異常處理
在代碼出現(xiàn)錯(cuò)誤時(shí) ,當(dāng)程序執(zhí)行到錯(cuò)誤代碼的時(shí)候椭微,程序會(huì)直接終止并報(bào)錯(cuò)洞坑,這是因?yàn)?python檢測(cè)到一個(gè)錯(cuò)誤時(shí),解釋器就無(wú)法繼續(xù)執(zhí)行了 蝇率,出現(xiàn)了錯(cuò)誤的提示迟杂,這就是“異常”本慕。
語(yǔ)法格式:
- try:可能出現(xiàn)錯(cuò)誤的代碼塊
- except:出錯(cuò)之后執(zhí)行的代碼塊
- else:沒(méi)有出錯(cuò)的代碼塊
- finally:不管有沒(méi)有出錯(cuò)都執(zhí)行的代碼塊
- try ... except語(yǔ)句:
將可能出錯(cuò)的代碼放到try里面 排拷,except可以指定類(lèi)型捕獲異常。用來(lái)檢測(cè)try語(yǔ)句塊中的錯(cuò)誤锅尘,從而讓except語(yǔ)句捕獲異常信息并處理监氢。如果你不想在異常發(fā)生時(shí)結(jié)束你的程序,只需在try里捕獲它藤违。這樣程序員就不會(huì)因?yàn)橐欢未a包異常而導(dǎo)致整個(gè)程序崩潰
- except在捕獲錯(cuò)誤異常的時(shí)候浪腐,是需要根據(jù)具體的錯(cuò)誤類(lèi)型來(lái)捕獲的。
- 用一個(gè)塊可以捕獲多個(gè)不同類(lèi)型的異常顿乒,但一次只能捕獲一個(gè)異常
print(b) #因?yàn)檫@一步的錯(cuò)誤導(dǎo)致后面的代碼都無(wú)法運(yùn)行
print('你好')
print(3333)
try:
print(b)
pass
except NameError as msg:
#捕獲到的錯(cuò)誤才會(huì)在這里執(zhí)行
print(msg) #輸出異常
pass
except IndexError as msg:
#多設(shè)置幾種類(lèi)型的錯(cuò)誤议街,就可以多捕獲幾種類(lèi)型的錯(cuò)誤
print(msg) #輸出異常
pass
except Exception as result: #??可以捕獲所有的錯(cuò)誤類(lèi)型,使用這個(gè)就不必設(shè)置要捕獲的錯(cuò)誤類(lèi)型
print(result)
#在此去處理捕獲到的錯(cuò)誤
pass
print('你好')
print(3333)
#name 'b' is not defined
#你好
#3333
- 不需要在每個(gè)可能出錯(cuò)的地方去捕獲璧榄,只要在合適的層次去捕獲錯(cuò)誤就可以了
def A(s):
return 10/int(s)
pass
def B(s):
return A(s)*2
def main():
try:
B('0')
pass
except Exception as msg:
print(msg)
pass
pass
main()
#division by zero
異常的拋出機(jī)制:
如果在運(yùn)行時(shí)發(fā)生異常特漩,解釋器會(huì)查找相應(yīng)的異常捕獲類(lèi)型。如果在當(dāng)前函數(shù)里面沒(méi)有找到的話(huà)骨杂,它會(huì)將異常值傳遞給上層的調(diào)用函數(shù)涂身,看能否處理。如果在最外層沒(méi)有找到的話(huà) 腊脱,解釋器就會(huì)退出访得,程序down掉。
- try ... except...else語(yǔ)句:
try:
print (aa)
pass
except Exception as msg:
print(msg)
else:
print('當(dāng)try里面的代碼沒(méi)有出現(xiàn)異常的情況下陕凹,我才會(huì)執(zhí)行')
#name 'aa' is not defined
try:
print ('我是沒(méi)有錯(cuò)誤的')
pass
except Exception as msg:
print(msg)
else:
print('當(dāng)try里面的代碼沒(méi)有出現(xiàn)異常的情況下,我才會(huì)執(zhí)行')
#我是沒(méi)有錯(cuò)誤的
#當(dāng)try里面的代碼沒(méi)有出現(xiàn)異常的情況下鳄炉,我才會(huì)執(zhí)行
- try ... except...finally語(yǔ)句:
try:
int('fff')
pass
except Exception as msg:
print(msg)
pass
finally:
print('釋放文件的資源杜耙、數(shù)據(jù)庫(kù)的資源等等')
print('不管有沒(méi)有出錯(cuò)都執(zhí)行的代碼塊')
#invalid literal for int() with base 10: 'fff'
#釋放文件的資源、數(shù)據(jù)庫(kù)的資源等等
#不管有沒(méi)有出錯(cuò)都執(zhí)行的代碼塊
- 自定義異常
- 自定義異常都要直接或間接即成Error或Exception類(lèi)
- 由開(kāi)發(fā)者主動(dòng)拋出自定義異常拂盯,在python中使用raise關(guān)鍵字
class ToolongException(Exception): ##自定義異常類(lèi)型需要繼承Exception
def __init__(self,leng):
'''
:param leng: 長(zhǎng)度
'''
self.len=leng
pass
def __str__(self):
return '您輸入的姓名數(shù)據(jù)長(zhǎng)度是'+str(self.len)+'超出限定長(zhǎng)度'
pass
def name_Test():
name=input('請(qǐng)輸入姓名:')
try:
if len(name)>5:
raise ToolongException(len(name))
else:
print(name)
pass
pass
except ToolongException as result:
print(result)
pass
finally:
print('')
name_Test()
??python中常見(jiàn)的異常錯(cuò)誤類(lèi)型:
異常名稱(chēng) | 描述 |
---|---|
BaseException | 所有異常的基類(lèi) |
ArithmeticError | 所有數(shù)值計(jì)算錯(cuò)誤的基類(lèi) |
AssertionError | 斷言語(yǔ)句失敗 |
AttributeError | 對(duì)象沒(méi)有這個(gè)屬性 |
DeprecationWarning | 關(guān)于被棄用的特征的警告 |
EnvironmentError | 操作系統(tǒng)錯(cuò)誤的基類(lèi) |
EOFError | 沒(méi)有內(nèi)建輸入,到達(dá)EOF 標(biāo)記 |
Exception | 常規(guī)錯(cuò)誤的基類(lèi) |
FloatingPointError | 浮點(diǎn)計(jì)算錯(cuò)誤 |
FutureWarning | 關(guān)于構(gòu)造將來(lái)語(yǔ)義會(huì)有改變的警告 |
GeneratorExit | 生成器(generator)發(fā)生異常來(lái)通知退出 |
ImportError | 導(dǎo)入模塊/對(duì)象失敗 |
IndentationError | 縮進(jìn)錯(cuò)誤 |
IndexError | 序列中沒(méi)有此索引(index) |
IOError | 輸入/輸出操作失敗 |
KeyboardInterrupt | 用戶(hù)中斷執(zhí)行(通常是輸入^C) |
KeyError | 映射中沒(méi)有這個(gè)鍵 |
LookupError | 無(wú)效數(shù)據(jù)查詢(xún)的基類(lèi) |
MemoryError | 內(nèi)存溢出錯(cuò)誤(對(duì)于Python 解釋器不是致命的) |
NameError | 未聲明/初始化對(duì)象 (沒(méi)有屬性) |
NotImplementedError | 尚未實(shí)現(xiàn)的方法 |
OSError | 操作系統(tǒng)錯(cuò)誤 |
OverflowError | 數(shù)值運(yùn)算超出最大限制 |
OverflowWarning | 舊的關(guān)于自動(dòng)提升為長(zhǎng)整型(long)的警告 |
PendingDeprecationWarning | 關(guān)于特性將會(huì)被廢棄的警告 |
ReferenceError | 弱引用(Weak reference)試圖訪(fǎng)問(wèn)已經(jīng)垃圾回收了的對(duì)象 |
RuntimeError | 一般的運(yùn)行時(shí)錯(cuò)誤 |
RuntimeWarning | 可疑的運(yùn)行時(shí)行為(runtime behavior)的警告 |
StandardError | 所有的內(nèi)建標(biāo)準(zhǔn)異常的基類(lèi) |
StopIteration | 迭代器沒(méi)有更多的值 |
SyntaxError | Python 語(yǔ)法錯(cuò)誤 |
SyntaxWarning | 可疑的語(yǔ)法的警告 |
SystemError | 一般的解釋器系統(tǒng)錯(cuò)誤 |
SystemExit | 解釋器請(qǐng)求退出 |
TabError | Tab 和空格混用 |
TypeError | 對(duì)類(lèi)型無(wú)效的操作 |
UnboundLocalError | 訪(fǎng)問(wèn)未初始化的本地變量 |
UnicodeDecodeError | Unicode 解碼時(shí)的錯(cuò)誤 |
UnicodeEncodeError | Unicode 編碼時(shí)錯(cuò)誤 |
UnicodeError | Unicode 相關(guān)的錯(cuò)誤 |
UnicodeTranslateError | Unicode 轉(zhuǎn)換時(shí)錯(cuò)誤 |
UserWarning | 用戶(hù)代碼生成的警告 |
ValueError | 傳入無(wú)效的參數(shù) |
Warning | 警告的基類(lèi) |
WindowsError | 系統(tǒng)調(diào)用失敗 |
ZeroDivisionError | 除(或取模)零 (所有數(shù)據(jù)類(lèi)型) |
7.Python動(dòng)態(tài)添加屬性和方法
動(dòng)態(tài)語(yǔ)言:運(yùn)行時(shí)可以改變其結(jié)構(gòu)的語(yǔ)言佑女,例如新的函數(shù)、對(duì)象、甚至代碼可以被引進(jìn)团驱,已有的函數(shù)可以被刪除或事其他結(jié)構(gòu)上的變化摸吠。如 php、JavaScript嚎花、Python都是動(dòng)態(tài)語(yǔ)言寸痢,C、C#紊选、java是靜態(tài)語(yǔ)言
所以python可以在程序運(yùn)行過(guò)程中添加屬性和方法
- 動(dòng)態(tài)添加類(lèi)屬性和實(shí)例屬性
class Animal(object):
def __init__(self,name,age):
self.name=name
self.age=age
pass
#定義了兩個(gè)初始屬性name和age啼止,但沒(méi)有顏色,想去添加顏色又不能修改類(lèi)
cat=Animal('小白',5)
cat.color='白色' #動(dòng)態(tài)綁定color屬性(只針對(duì)實(shí)例對(duì)象兵罢,類(lèi)本身不改變)
print(cat.color)
#白色
Animal.size='mini' #動(dòng)態(tài)添加類(lèi)屬性
print(cat.size)
#mini
- 動(dòng)態(tài)添加實(shí)例方法(需要用到types)
#案例1
class Animal(object):
def __init__(self,name,age):
self.name=name
self.age=age
pass
cat=Animal('kitty',3)
import types #添加方法的庫(kù)
def run(self): #動(dòng)態(tài)添加實(shí)例方法
print('飛快跑')
cat.run=types.MethodType(run,cat) #動(dòng)態(tài)方法的綁定方式 run是要綁定的方法献烦,cat是要綁定的實(shí)例
cat.run()
#飛快跑
#案例2
import types
def dynamicMethod(self):
print('{}的體重是{}kg,在{}讀大學(xué)'.format(self.name,self.weight,Student.school))
pass
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
pass
def __str__(self):
return '{}今年{}歲了'.format(self.name,self.age)
pass
zyh=Student('小華',20)
print(zyh)
#小華今年20歲了
zyh.weight=50 #動(dòng)態(tài)添加實(shí)例屬性
Student.school='北航' #動(dòng)態(tài)添加類(lèi)屬性
zyh.printInfo=types.MethodType(dynamicMethod,zyh) #動(dòng)態(tài)的綁定方式
zyh.printInfo()
#小華的體重是50kg卖词,在北航讀大學(xué)
- 動(dòng)態(tài)添加類(lèi)方法和靜態(tài)方法
(綁定到對(duì)象就僅限那個(gè)對(duì)象使用巩那,綁定到類(lèi)里面就以后從這個(gè)類(lèi)實(shí)例化出的對(duì)象都可以使用)
使用方法:類(lèi)名.方法名=xxxx
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
pass
def __str__(self):
return '{}今年{}歲了'.format(self.name,self.age)
pass
@classmethod
def classTest(cls):
print('這是一個(gè)類(lèi)方法')
pass
Student.TestMethod=classTest
Student.TestMethod()
#這是一個(gè)類(lèi)方法
xx=Student('maomao',20)
xx.TestMethod()
#這是一個(gè)類(lèi)方法
@staticmethod
def staticTest():
print('這是一個(gè)靜態(tài)方法')
pass
Student.StaticTest=staticTest
Student.StaticTest()
#這是一個(gè)靜態(tài)方法
hh=Student('huihui',20)
hh.StaticTest()
#這是一個(gè)靜態(tài)方法
8. _ slots _ 屬性
python是動(dòng)態(tài)語(yǔ)言,在運(yùn)行的時(shí)候可以動(dòng)態(tài)添加屬性此蜈。如果要限制在運(yùn)行的時(shí)候給類(lèi)添加屬性即横,python允許在定義class的時(shí)候,定義一個(gè)特殊的 _ slots _ 變量舶替,來(lái)限制該class實(shí)例能添加的屬性令境。
只有在 _ slots _ 變量中的屬性才可以被添加,沒(méi)有在 _ slots _ 變量中的屬性會(huì)添加失敗顾瞪√蚴可以防止其他人在調(diào)用類(lèi)的時(shí)候胡亂添加屬性或方法。 _ slots _ 屬性子類(lèi)不會(huì)繼承陈醒,只在當(dāng)前類(lèi)中有效惕橙。
作用:
- 限制要添加的實(shí)例屬性
- 節(jié)約內(nèi)存空間
class Animal(object):
__slots__ = ('name','age') #元組類(lèi)型
pass
dog=Animal()
dog.name='旺財(cái)'
print(dog.name)
#旺財(cái)
# dog.color='白色'
# print(dog.color)
# #AttributeError: 'Animal' object has no attribute 'color'
print(dog.__dict__) #所有可用的屬性都在這里儲(chǔ)存,非常占用內(nèi)存钉跷。
#可以看到弥鹦,在定義了slots變量之后,student類(lèi)的實(shí)例已經(jīng)不能隨意創(chuàng)建不在_slots_定義的屬性了
#同時(shí)爷辙,實(shí)例當(dāng)中也不再有__dict__結(jié)構(gòu)
在繼承關(guān)系當(dāng)中使用slots:子類(lèi)未聲明 _ slots _ 時(shí)彬坏,不會(huì)繼承父類(lèi)的 _ slots _ ,此時(shí)子類(lèi)是可以隨意進(jìn)行屬性賦值的
class Student(object):
__slots__=('name','age')
pass
class subStudent(Student):
pass
ln=subStudent()
ln.gender='男'
ln.pro='計(jì)算機(jī)信息管理'
print(ln.gender,ln.pro)
#男 計(jì)算機(jī)信息管理
如果子類(lèi)聲明了 _ slots _ 時(shí) 膝晾,也會(huì)繼承父類(lèi)的 _ slots _ 栓始,這時(shí)子類(lèi) _ slots _ 的范圍為自身+父類(lèi)的 _ slots _ 。
class Student(object):
__slots__=('name','age')
pass
class subStudent(Student):
__slots__ = ('gender')
pass
ln=subStudent()
ln.name='lili'
print(ln.name)
#lili
ln.pro='計(jì)算機(jī)信息管理'
#AttributeError: 'subStudent' object has no attribute 'pro'
print(ln.pro)
總結(jié):
- 私有化屬性:兩個(gè)下劃線(xiàn)開(kāi)頭血当,聲明該屬性為私有幻赚,不能在類(lèi)的外部被使用或訪(fǎng)問(wèn)
- 私有化方法:即在方法名前加兩個(gè)下劃線(xiàn)
-
Property屬性:
類(lèi)屬性禀忆,即在類(lèi)中定義為property對(duì)象的類(lèi)屬性
裝飾器,即在方法上使用裝飾器 - _ new _ 方法:: _ new _方法的作用是創(chuàng)建 并返回一個(gè)實(shí)例對(duì)象
- 單例模式:不管創(chuàng)建多少次對(duì)象落恼,類(lèi)返回的對(duì)象都是最初創(chuàng)建的箩退,不會(huì)再新建其他對(duì)象
-
錯(cuò)誤與異常處理:
try:可能出現(xiàn)錯(cuò)誤的代碼塊
except:出錯(cuò)之后執(zhí)行的代碼塊
else:沒(méi)有出錯(cuò)的代碼塊
finally:不管有沒(méi)有出錯(cuò)都執(zhí)行的代碼塊 - python動(dòng)態(tài)添加屬性和方法:在程序運(yùn)行過(guò)程中添加屬性和方法
- _ slots _ 方法: 在定義class的時(shí)候,定義一個(gè)特殊的 _ slots _ 變量佳谦,來(lái)限制該class實(shí)例能添加的屬性
課后作業(yè)·問(wèn)答題
- Python中的new方法作用是什么戴涝?
- 什么是單例模式?單例模式適用于什么場(chǎng)景吠昭?
- 私有化方式與私有化屬性在子類(lèi)中能否繼承喊括?
- 在Python中什么是異常?
- Python中是如何處理異常的矢棚?
- Python中異常處理語(yǔ)句的一般格式郑什,可以使用偽代碼的形式描述。
- _ slots _ 屬性的作用
- 私有化屬性的作用蒲肋?
- 在類(lèi)外面是否能修改私有屬性
- 如果一個(gè)類(lèi)中蘑拯,只有指定的屬性或者方法能被外部修改,那么該如何限制外部修改
課后作業(yè)·實(shí)操題
- 編寫(xiě)一段代碼已完成下面的要求:
定義一個(gè)Person類(lèi)兜粘,類(lèi)中要有初始化方法申窘,方法中要有人的姓名和年齡兩個(gè)私有屬性
提供獲取用戶(hù)信息的函數(shù)
提供獲取私有屬性的方法
提供可以設(shè)置私有屬性的方法
設(shè)置年齡的范圍在0-120的方法,如果不在這個(gè)范圍內(nèi)孔轴,不能設(shè)置成功 - 請(qǐng)寫(xiě)一個(gè)單例模式
- 創(chuàng)建一個(gè)類(lèi)剃法,并定義兩個(gè)私有化屬性,提供一個(gè)獲取屬性的方法和設(shè)置屬性的方法路鹰。利用property屬性給調(diào)用者提供屬性方法的調(diào)用獲取和設(shè)置私有屬性方法的方式
- 創(chuàng)建一個(gè)Animal類(lèi)贷洲,實(shí)例化一個(gè)cat對(duì)象,請(qǐng)給cat對(duì)象動(dòng)態(tài)綁定一個(gè)run方法晋柱,給類(lèi)綁定一個(gè)類(lèi)屬性color优构,給類(lèi)綁定一個(gè)類(lèi)方法打印字符串“ok”。