python是一門動(dòng)態(tài)語(yǔ)言,而反射機(jī)制被視為動(dòng)態(tài)語(yǔ)言的關(guān)鍵!
創(chuàng)新互聯(lián)建站于2013年開(kāi)始,先為達(dá)孜等服務(wù)建站,達(dá)孜等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為達(dá)孜企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。
反射機(jī)制指的是:在程序的運(yùn)行過(guò)程中,動(dòng)態(tài)的獲取程序的信息和對(duì)象的功能!
‘動(dòng)態(tài)’:指一開(kāi)始不知道程序的信息和對(duì)象的功能,只有等到運(yùn)行到那的時(shí)候才會(huì)動(dòng)態(tài)獲?。。。?/p>
比如:x=18
在程序運(yùn)行的時(shí)候,python才會(huì)通過(guò)反射機(jī)制動(dòng)態(tài)的獲取到這個(gè)值是整型,并不需要一開(kāi)始定義的時(shí)候,就規(guī)定這個(gè)18位整型!
當(dāng)我們獲取一個(gè)對(duì)象時(shí),很多場(chǎng)景下,我們是并不知道這個(gè)對(duì)象里面是有什么屬性和方法的,我們需要通過(guò)反射機(jī)制,動(dòng)態(tài)的獲取到該對(duì)象的屬性和方法!!
案例:當(dāng)我們?cè)诮邮沼脩糨斎胫噶畹臅r(shí)候,我們接收的是一個(gè)用戶輸入的字符串類型的指令,我們需要通過(guò)反射機(jī)制判斷,這個(gè)字符串是不是該對(duì)象的功能,如果是調(diào)用該功能,如果不是返回提示信息!
案例代碼化:
class Func:
def put(self):
print('正在執(zhí)行上傳功能')
def get(self):
print('正在執(zhí)行下載功能')
# 該函數(shù)是用來(lái)接收用戶的操作指令,并判斷該對(duì)象是否有該功能,有則執(zhí)行,沒(méi)有則提示沒(méi)有該功能
def action(self):
action = input('請(qǐng)輸入操作指令:')
if hasattr(self,action):
getattr(self,action)()
else:
print('沒(méi)有該功能')
obj = Func()
obj.action()
其實(shí)就是四個(gè)內(nèi)置函數(shù)的使用!
class People:
def __init__(self,name):
self.name = name
def say(self):
pass
obj = People('zhang')
# 1.可以通過(guò)dir方法獲取obj對(duì)象有哪些屬性
print(dir(obj)) # 格式是一個(gè)列表套字符串的形式
# 2.通過(guò)字符串反射到真正的屬性上,從而得到屬性,操作屬性
# 四個(gè)內(nèi)置函數(shù)的使用
print(hasattr(obj,'name')) # hasattr()判斷obj這個(gè)對(duì)象有沒(méi)有name這個(gè)屬性,name是字符串格式
print(getattr(obj,'name')) # 等同于obj.name
setattr(obj,'name','yang') # 等同于obj.name='yang'
delattr(obj,'name') # 等同于 del obj.name
print(obj.__dict__) # 結(jié)果為{}
# 上述四個(gè)方法也可以括號(hào)里放個(gè)類,判讀類是否有該函數(shù)
res = getattr(People,'say') # 等同于People.say
print(res)
定義在類的內(nèi)部,以__開(kāi)頭__結(jié)尾的方法
特點(diǎn)是在滿足某種情況下自動(dòng)觸發(fā)該方法?。。?!
為了自定義定制我們的類or對(duì)象
class Func:
def put(self):
print('正在執(zhí)行上傳功能')
def __str__(self):
return 'w1e' # 打印對(duì)象是返回的值,必須位字符串類型
obj = Func()
print(obj) # 等同于print(obj.__str__())
# 不定義__str__方法,印出來(lái)為<__main__.Func object at 0x00000149DE206FA0>
# 定義__str__方法,可以在__str__內(nèi)部函數(shù)指定返回的東西,return后面必須是字符串類型
該方法是在清理對(duì)象之前觸發(fā),會(huì)先執(zhí)行該方法
class Func:
def put(self):
print('正在執(zhí)行上傳功能')
def __del__(self):
print('run...')
# 在del內(nèi)部更多的是進(jìn)行清理該對(duì)象占用系統(tǒng)的資源,對(duì)象清理了需要發(fā)起系統(tǒng)調(diào)用,清理對(duì)象占據(jù)的系統(tǒng)資源!
obj = Func()
del obj # 清理對(duì)象了,清理完之后會(huì)直接調(diào)用__del__方法,然后在執(zhí)行下面的代碼;如果不手動(dòng)清理,在執(zhí)行代碼全部運(yùn)行完之后,程序也會(huì)清理,打印run
print('====')
如果想要讓一個(gè)對(duì)象可以加括號(hào)調(diào)用,需要在該對(duì)象的類中添加一個(gè)__call__方法
class Person(object):
def __init__(self,name):
self.name=name
def __call__(self, *args, **kwargs):
print(args,kwargs) #a()里傳入的參數(shù)
return 123 # __call__的返回值就是a()的返回值
a = Person('zhang')
res = a(1,2,3,a=4,b=5) # 如果想要讓對(duì)象a可以加括號(hào)調(diào)用,就必須在該對(duì)象的類中定義__call__方法,不添加則報(bào)錯(cuò)
print(res)
同樣,如果想要類可以加括號(hào)調(diào)用,需要在該類的元類里添加一個(gè)__call__方法
調(diào)用__call__方法完成了三件事:
1.調(diào)用該類中的__new__方法造出一個(gè)空對(duì)象
2.調(diào)用該類中的__init__方法造出一個(gè)初始化對(duì)象(給上面的空對(duì)象添加屬性,穿衣服)
3.返回初始化好的對(duì)象
了解:這些內(nèi)置方法__str__等又稱魔法方法!
# __init__:類實(shí)例化會(huì)觸發(fā)
# __str__:打印對(duì)象會(huì)觸發(fā)
# __call__:對(duì)象()觸發(fā),類也是對(duì)象 類(),類的實(shí)例化過(guò)程調(diào)用元類的__call__
# __new__:在類實(shí)例化會(huì)觸發(fā),它比__init__早(造出裸體的人,__init__穿衣服)
# __del__:del 對(duì)象,對(duì)象回收的時(shí)候觸發(fā)
# __setattr__,__getattr__:(.攔截方法),當(dāng)對(duì)象.屬性--》賦值會(huì)調(diào)用setattr,如果是取值會(huì)調(diào)用getattr
# __getitem__,__setitem__:([]攔截)
# __enter__和__exit__ 上下文管理器
上下文管理器應(yīng)用:
class Person:
def __enter__(self):
print("我在with管理的時(shí)候,會(huì)觸發(fā)")
print('進(jìn)入with語(yǔ)句塊時(shí)執(zhí)行此方法,此方法如果有返回值會(huì)賦值給as聲明的變量')
return 'oo'
def __exit__(self, exc_type, exc_val, exc_tb):
print('退出with代碼塊時(shí)執(zhí)行此方法')
print('1', exc_type)
print('2', exc_val)
print('3', exc_tb)
with Person() as p: # 這句話執(zhí)行,會(huì)觸發(fā)類的__enter__
print(p)
小練習(xí):類中可以通過(guò)對(duì)象.屬性的方式獲取值和設(shè)置值,但是不可以通過(guò)對(duì)象['鍵']=值設(shè)置值和獲取值,思考如何可以實(shí)現(xiàn)呢?
class Person:
def __init__(self,name):
self.name = name
def __setitem__(self, key, value): # 重寫類的__setitem__方法
setattr(self,key,value) # 當(dāng)對(duì)象['鍵']=值觸發(fā)該方法,調(diào)用setattr是觸發(fā)self.key=value
def __getitem__(self, item): # 同上
return getattr(self,item)
p = Person('zy')
print(p.name)
p['name']=10
print(p['name'])
元類就是用來(lái)實(shí)例化產(chǎn)生類的類
關(guān)系:元類--->實(shí)例化--->類--->實(shí)例化--->對(duì)象(obj)
其實(shí),我們使用class定義的各種類和內(nèi)置的類都是由內(nèi)置的元類type幫我們實(shí)例化產(chǎn)生的
我們可以使用type()函數(shù)查看內(nèi)置的元類
例如:在python中int、dict內(nèi)置元類都繼承自object類,int和dict又都是type元類的對(duì)象
print(type(int)) # <class 'type'>
print(type(dict)) # <class 'type'>
那么type和object又是什么關(guān)系呢?我們來(lái)type一下object和type!
print(type(type)) #<class 'type'>
print(type(object)) #<class 'type'>
其實(shí):
1.object的元類其實(shí)是type類,object是由type類構(gòu)造出來(lái)的對(duì)象
2.type是自己的對(duì)象(指針指向了自己)
3.type類又繼承了object類
calss其實(shí)底層執(zhí)行了以下四個(gè)步驟,造出了類!
class Func:
def put(self):
print('正在執(zhí)行上傳功能')
def __del__(self):
print('run...')
# 1.得到類名
class_name = 'Func'
# 2.得到類的基類
class_bases = (object,)
# 3.執(zhí)行類體代碼拿到名稱空間!
class_dict = {}
class_body = """
def put(self):
print('正在執(zhí)行上傳功能')
def __del__(self):
print('run...')
"""
# exec第一個(gè)參數(shù)是類體代碼、第二個(gè)是類體代碼中的全局變量、第三的是一個(gè)空字典容器
exec (class_body,{},class_dict)
print(class_dict)
# 4.調(diào)用元類,得到People類
Func = type(class_name,class_bases,class_dict)
print(Func)
# Func類就是type元類實(shí)例化產(chǎn)生出來(lái)的對(duì)象?。。?!
在3.3中,我們是使用type元類控制Func類的產(chǎn)生。其實(shí),我們也可以自定義元類來(lái)控制類產(chǎn)生
class MyMeta(type): # 只有繼承了type的類才是元類
def __init__(self,x,y,z): # 注意調(diào)用MyMeta這個(gè)類其實(shí)傳入了四個(gè)參數(shù)分別是self、class_name,class_bases,class_dict
print('run...')
print(x) # x對(duì)應(yīng)class_name
print(y) # y對(duì)應(yīng)class_bases
print(z) # z對(duì)應(yīng)class_dict
class Func(metaclass=MyMeta):
def put(self):
print('正在執(zhí)行上傳功能')
def __del__(self):
print('run...')
# 在自定義類的時(shí)候,metaclass默認(rèn)等于type,我們可以通過(guò)指定metaclass=MyMeta來(lái)自定義元類
# 指定了metaclass=MyMeta,其實(shí)就執(zhí)行了第四步調(diào)用元類Func = MyMeta(class_name,class_bases,class_dict)
# 調(diào)用MyMeta(class_name,class_bases,class_dict)發(fā)生了三件事!
# 注意?。?!調(diào)用它就等于調(diào)用了type的__call__方法?。。?!
# 1.先造一個(gè)空對(duì)象---Func--這里其實(shí)先調(diào)用了MyMeta類里的__new__()方法
# 2.調(diào)用MyMeta這個(gè)類的__init__方法,完成初始化對(duì)象操作
# 3.返回初始化好的對(duì)象
"""
完成上述操作之后,我們就可以在自定義的MyMeta元類里面的init方法里面,規(guī)定一下類的產(chǎn)生必須滿足那些條件!
"""
首先,切記?。「割惒皇窃悾。?/strong>
對(duì)象.屬性查找是先從自己那找,再到類中,再到該類的父類中,最后到object類
類.屬性查找是先從該類的父類中找,再到父類的父類中找,再到object中找,最后還要到該類的元類中找
網(wǎng)頁(yè)標(biāo)題:面向?qū)ο蟾呒?jí)--反射、內(nèi)置方法和元類
文章出自:http://redsoil1982.com.cn/article46/dsogceg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司、移動(dòng)網(wǎng)站建設(shè)、定制網(wǎng)站、Google、標(biāo)簽優(yōu)化、品牌網(wǎng)站設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)