屬性 | 含義 |
---|---|
_name_ | 類,函數(shù),方法等的名字 |
_module_ | 類定義所現(xiàn)在的模塊名 |
_class_ | 對(duì)象或類所屬的類 |
_bases_ | 類的基類的元素,順序?yàn)樗麄冊(cè)诨惲斜碇谐霈F(xiàn)的順序 |
_doc_ | 類/函數(shù)的文檔字符傳,如果沒(méi)有定義則為None |
_mro_ | 類的mro,class.mro()返回 |
_dict_ | 類或?qū)嵗膶傩裕蓪懙淖值?/td> |
_dir_ | 返回了類或者對(duì)象所有成員列表,dir()函數(shù)調(diào)用的是_dir_(),如果提供了_dir_(),則返回屬性列表,否則盡可能從__dict__屬性中收集信息 |
獲取類和函數(shù)的名字
創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括潯陽(yáng)網(wǎng)站建設(shè)、潯陽(yáng)網(wǎng)站制作、潯陽(yáng)網(wǎng)頁(yè)制作以及潯陽(yáng)網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,潯陽(yáng)網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到潯陽(yáng)省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B(A):
pass
def C():
pass
print (A.__name__,B.__name__,C.__name__,sep='\n')
類定義所在的模塊名
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B:
pass
print (A.__module__,B.__module__)
#!/usr/local/bin/python3.6
#coding:utf-8
import disp
print (disp.A.__module__,disp.B.__module__,sep='\n')
對(duì)象或類所屬的類
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B(A):
pass
a=A()
b=B()
print (A.__class__,B.__class__,sep='\n') #類所屬的類是class
print (a.__class__,b.__class__,sep='\n') # 對(duì)象所屬的類是實(shí)實(shí)在在的類
類的基類的元組,順序是他們?cè)诨惲斜碇谐霈F(xiàn)的順序
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B(A):
pass
class C(B):
pass
class E:
pass
class D(E,C):
pass
print (A.__bases__,B.__bases__,C.__bases__,D.__bases__,sep='\n')
結(jié)果如下
文檔字符串,針對(duì)類和函數(shù)有效,若不存在,則返回為None
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
'''this is class'''
pass
def B():
'''this is function'''
pass
class C:
pass
print (A.__doc__,B.__doc__,C.__doc__,sep='\n')
結(jié)果如下
類的mro。返回多繼承中的查找順序
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B(A):
pass
class C(B):
pass
class E:
pass
class D(E,C):
pass
print (A.__mro__,B.__mro__,C.__mro__,D.__mro__,sep='\n')
結(jié)果如下
類或者實(shí)例的屬性,可寫的字典
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
a=10
def __init__(self,x):
self.x=5
a=A(3)
print (A.__dict__)
print (a.__dict__)
結(jié)果如下
dir 返回了類或者對(duì)象所有成員名稱列表,dir()函數(shù)調(diào)用的是_dir_(),如果提供了_dir_() ,則返回屬性的列表,否則會(huì)盡量從__dict__屬性中收集
dir() 對(duì)于不同類型的對(duì)象具有不同的行為:
1 如果對(duì)象是模塊對(duì)象,則列表包含模塊的屬性名
#!/usr/local/bin/python3.6
#coding:utf-8
import re
def foo(x):
y=1
print (dir()) # 輸出當(dāng)前模塊信息,此處會(huì)打印當(dāng)前導(dǎo)入的模塊和導(dǎo)入的函數(shù)
print (dir(re))
print ('+'*20)
print (dir(foo))
結(jié)果如下
2 如果對(duì)象是類型或者類對(duì)象,列表包含類的屬性名,以及其他基類的屬性名
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
a='1234'
def __init__(self):
pass
class B(A): # 此處調(diào)用父類,其dir中會(huì)包含父類的屬性
pass
print (dir()) # 輸出當(dāng)前模塊信息,此處會(huì)打印當(dāng)前導(dǎo)入的模塊和導(dǎo)入的函數(shù)
print ('*'*40)
print (dir(A),dir(B),sep='\n') # 此中DIR屬性父類和子類是完全相同的,但dict中卻是不同的
print (A.__dict__,B.__dict__,sep='\n')
3 如果是對(duì)象,列表包含對(duì)象的屬性名,它的類的屬性名和基類的屬性名
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
a='1234'
def __init__(self):
self.x=10
class B(A): # 此處調(diào)用父類,其dir中會(huì)包含父類的屬性
pass
a=A()
print (dir()) # 輸出當(dāng)前模塊信息,此處會(huì)打印當(dāng)前導(dǎo)入的模塊和導(dǎo)入的函數(shù)
print ('*'*40)
print (dir(A),dir(B),dir(a),sep='\n') #此處若是打印實(shí)例的屬性,則會(huì)吧類的屬性也打印上來(lái)
結(jié)果如下
4此處對(duì)屬性名進(jìn)行了重寫操作
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
a='1234'
def __init__(self):
self.x=10
class B(A): # 此處調(diào)用父類,其dir中會(huì)包含父類的屬性
def __dir__(self): # 此處是針對(duì)實(shí)例設(shè)置的,和類本身并無(wú)關(guān)系
return ['this is class A '] # 此處是dir返回是列表,若使用字符串,則會(huì)處理成列表進(jìn)行返回
a=A()
b=B()
print (dir()) # 輸出當(dāng)前模塊信息,此處會(huì)打印當(dāng)前導(dǎo)入的模塊和導(dǎo)入的函數(shù),以及實(shí)例后的對(duì)象
print ('*'*40)
print (dir(A),dir(B),dir(a),dir(b),sep='\n') #此處若是打印實(shí)例的屬性,則會(huì)吧類的屬性也打印上來(lái)
結(jié)果如下
都是字典惹的禍
字典為了提升查詢效率,必須用空間換時(shí)間
一般來(lái)說(shuō)一個(gè)對(duì)象,屬性多一點(diǎn),都存儲(chǔ)在字典中便于查詢,問(wèn)題不大,但是數(shù)百萬(wàn)個(gè)對(duì)象,那么字典就占得有點(diǎn)大了,這個(gè)時(shí)候,python便提供了_slots_
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class A:
x=123
__slots__ = ('p1',) # 此處只放置了一個(gè)槽位,則只能使用p1變量,不能使用其他
def __init__(self):
self.p1=1
self.p2=2
def show(self):
print ('this is test1,{}'.format(self.p1))
print (A().__dict__)
結(jié)果如下
此處的p2屬性不能使用
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class A:
x=123
__slots__ = ('p1','p2') # 此處只放置了一個(gè)槽位,則只能使用p1變量,不能使用其他
def __init__(self):
self.p1=1
self.p2=2
def show(self):
print ('this is test1,{}'.format(self.p1))
print ('slots',A().__slots__) #實(shí)例的此屬性可以被打印出來(lái),但實(shí)例的字典屬性卻不存在
print (A.__dict__) # 類的字典屬性不受影響
print ('dict',A().__dict__)
結(jié)果如下
添加實(shí)例屬性如下
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class A:
x=123
__slots__ = 'p1','p2' # 此處只放置了一個(gè)槽位,則只能使用p1變量,不能使用其他
def __init__(self):
self.p1=1
self.p2=2
def show(self):
print ('this is test1,{}'.format(self.p1))
print ('slots',A().__slots__) #實(shí)例的此屬性可以被打印出來(lái),但實(shí)例的字典屬性卻不存在
print (A.__dict__) # 類的字典屬性不受影響
A.p4=300 #類添加屬性,只會(huì)影響類的__dict__,實(shí)例中不會(huì)顯示,而__slots__ 不會(huì)對(duì)類造成影響
try:
setattr(A(),'p5',30)
except AttributeError as a:
print (A(),'不能添加屬性')
finally:
print (A().__slots__) #查看
try:
A().P3=300
except AttributeError as a:
print (A(),'不能添加屬性')
finally:
print (A().__slots__) #查看
結(jié)果如下
_slots_ 告訴解釋器,實(shí)例的屬性都叫什么,一般來(lái)說(shuō),既要節(jié)約內(nèi)存,最好還是使用元祖來(lái)存儲(chǔ)__slots__梳理,這樣就阻止了實(shí)例產(chǎn)生__dict__來(lái)保存實(shí)例的屬性
繼承
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class A:
x=123
__slots__ = 'p1','p2' # 此處只放置了一個(gè)槽位,則只能使用p1變量,不能使用其他
def __init__(self):
self.p1=1
self.p2=2
def show(self):
print ('this is test1,{}'.format(self.p1))
class B(A):
def __init__(self):
super().__init__()
self.b1=200
b=B()
b.b2=300
print (b.__dict__) # 繼承則失效
結(jié)果如下
使用需要構(gòu)建在數(shù)百萬(wàn)以上對(duì)象,且內(nèi)存容量較為緊張的場(chǎng)景
描述 | 方法 |
---|---|
初始化和銷毀 | _init__和_del\ |
在字典和set中使用 | _hash_ |
布爾類型,常用于判斷語(yǔ)句 | _bool_ |
可視化,用于輸出對(duì)應(yīng)的類型 | _str__和_repr\ |
運(yùn)算符重載 | _eq_,_ne_,_gt_,__lt__等 |
容器和大小相關(guān)和操作相關(guān)屬性 | _getitem_,__setitem__等 |
可調(diào)用對(duì)象,將實(shí)例化的對(duì)象當(dāng)成一個(gè)函數(shù)去調(diào)用,一旦可以當(dāng)函數(shù)調(diào)用 | _call_ |
上下文管理(with open(x) as f 等形式 | _enter_,_exit_ |
反射 | _getattr_, _setattr_,_delattr_ |
描述器 | Object._get_(self,instance,owner)Object._set_(self,instance,value)Object._delete_(self,instance) |
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self,name):
self.name=name
self.x=10
print ("init instance")
def __del__(self):
print ('delete {}'.format(self.name))
a=X('a')
del a # 因?yàn)閜ython自身的垃圾回收機(jī)制,而del刪除實(shí)例的操作不確定何時(shí)執(zhí)行,因此需要使用del進(jìn)行清除處理
結(jié)果如下
hash 中最基礎(chǔ)的hash就是取模運(yùn)算。
list 不能hash的原因
list 源碼: 其中hash=None,在調(diào)用None的時(shí)候自然是不能hash的
判斷是否可hash
#!/usr/local/bin/python3.6
#coding:utf-8
from collections import Hashable
class X:
def __init__(self,x):
self.x=x
def __hash__(self):
return 1
print (isinstance(X(1),Hashable))
print (isinstance([],Hashable))
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
from collections import Hashable
class X:
def __init__(self):
self.x=10
__hash__=None
print (isinstance(X(),Hashable)) #判斷是否可hash,返回為bool類型
print (hash(X()))
結(jié)果如下
實(shí)例如下
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self): # 此處是定義的是實(shí)例的hash,和類沒(méi)關(guān)系
return None # 此處設(shè)置hash的返回為None,模擬列表
# 另一種方式定義不可哈希類型 __hash__=None
class Y: #此類未設(shè)置相關(guān)的hash屬性
def __init__(self):
pass
class Z: # 此類定義了hash的返回值為1 ,則實(shí)例化后調(diào)用hash返回為1
def __hash__(self):
return 1
print (hash(Y())) # 此處返回整數(shù)
print (hash(Z())) # 此處返回為固定數(shù)
print (hash(X())) #進(jìn)行判斷是否能夠進(jìn)行hash操作,未進(jìn)行hash,直接拋出異常
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self):
return 1
lst=[X(),X()] # 此處進(jìn)行實(shí)例化并裝載到列表中
print (lst) # 此處打印列表的值,指定的是內(nèi)存地址
s=set(lst) # 此處定義一個(gè)集合,集合本身具有去重功能,上述的hash的返回值是相同的,則說(shuō)明其hash相同,則表明其key相同,常理推論可得
# 其會(huì)走set的去重屬性進(jìn)行處理
print (len(s))
for i in s: # 打印其中的值,如下
print (hash(i))
結(jié)果如下
此處s集合中的元素hash后的結(jié)果是相同的,但是其卻沒(méi)有進(jìn)行去重操作,則此處表明hash相等的函數(shù)不一定就是相同的,此處沒(méi)有直接的相等關(guān)系
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self):
return 1
def __eq__(self, other): # 此處是判斷是否相等的原因,及就是其值必須相等的情況下才能說(shuō)是同一個(gè),而不是hash相同就認(rèn)為是同一個(gè),此處返回bool值,當(dāng)然可以是0或非0的數(shù)
return True
lst=[X(),X()] # 此處進(jìn)行實(shí)例化并裝載到列表中
print (lst) # 此處打印列表的值,指定的是內(nèi)存地址
s=set(lst) # 此處定義一個(gè)集合,集合本身具有去重功能,
# 其會(huì)走set的去重屬性進(jìn)行處理
print (len(s))
for i in s: # 打印其中的值,如下
print (hash(i))
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self):
return 1
def __eq__(self, other): # 此處是判斷是否相等的原因,及就是其值必須相等的情況下才能說(shuō)是同一個(gè),而不是hash相同就認(rèn)為是同一個(gè)
return False
lst=[X(),X()] # 此處進(jìn)行實(shí)例化并裝載到列表中
print (lst) # 此處打印列表的值,指定的是內(nèi)存地址
s=set(lst) # 此處定義一個(gè)集合,集合本身具有去重功能,上述的hash的返回值是相同的,則說(shuō)明其hash相同,則表明其key相同,常理推論可得
# 其會(huì)走set的去重屬性進(jìn)行處理
print (len(s))
for i in s: # 打印其中的值,如下
print (hash(i))
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self):
return 1
def __eq__(self, other): # 此處是判斷是否相等的原因,及就是其值必須相等的情況下才能說(shuō)是同一個(gè),而不是hash相同就認(rèn)為是同一個(gè)
return False
a=X()
lst=[a,a]
print (lst)
s=set(lst)
print (len(s))
for x in s:
print (hash(x))
結(jié)果如下
set判斷是否是同一個(gè)的步驟:
1 先進(jìn)行內(nèi)存地址的判斷,及is判斷,若內(nèi)存地址相同,則肯定是同一個(gè)
2 若內(nèi)存地址不同,再進(jìn)行eq 判斷,及就是==進(jìn)行判斷,若相同,則是同一個(gè),若不同,則不是同一個(gè),此處和hash沒(méi)有任何關(guān)系
及就是: 同假為假,一真一假為真,同真為真
默認(rèn)的能夠使用hash的原因是由于在基類object中實(shí)現(xiàn)了hash方法,一般的,不同的內(nèi)存地址的hash是不相同的,兩個(gè)對(duì)象的hash相同,叫hash沖突
hash 相同不代表一樣
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self,x):
self.x=x
def __hash__(self):
return 1
def __eq__(self, other): # 此處是判斷是否相等的原因,及就是其值必須相等的情況下才能說(shuō)是同一個(gè),而不是hash相同就認(rèn)為是同一個(gè)
return self.x==other.x# 此處表示二元操作,前面調(diào)用方法self.x,后面的作為參數(shù)傳遞進(jìn)去進(jìn)行處理,other表示第二個(gè)對(duì)象對(duì)應(yīng)的方法
print (hash(X(4)))
lst=[X(4),X(6)]
t=tuple(lst)
s=set(lst)
print (s)
for x in s:
print (hash(x))
結(jié)果如下
__hash__方法只是返回一個(gè)hash值作為set的key,但是去重,還需要__eq__來(lái)判斷2個(gè)對(duì)象是否相等,
設(shè)計(jì)二維坐標(biāo)類Point,比較2個(gè)坐標(biāo)是否相等
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self,x,y):
self.x=x
self.y=y
def __hash__(self):
return hash((self.x,self.y)) # 此處返回是一個(gè)元組,是不可變數(shù)據(jù)類型,此處可直接進(jìn)行hash
def __eq__(self, other):
return self.x==other.x and self.y == other.y
a1=Point(3,4)
a2=Point(3,4)
print ( a1 is a2 )
print (a1==a2)
結(jié)果如下
_bool_ 內(nèi)建函數(shù)bool(), 或者對(duì)象放在邏輯表達(dá)式的位置,調(diào)用這個(gè)函數(shù)返回布爾值,沒(méi)有定義_bool_,就找_len_ 返回長(zhǎng)度,非0為真,如果__len__也沒(méi)有定義,則所有的實(shí)例都返回是真。
#!/usr/local/bin/python3.6
#coding:utf-8
class Point: # 此類未定義len和bool,因此其返回值為恒真
def __init__(self):
self.x=3
self.y=4
# def __bool__(self):
# return False
print (bool(Point()))
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __bool__(self): # 此處定義了bool的返回值為False,則調(diào)用bool()返回結(jié)果應(yīng)該為False
return False
print (bool(Point()))
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
# def __bool__(self): # 此處定義了bool的返回值為False,則調(diào)用bool()返回結(jié)果應(yīng)該為False
# return False
def __len__(self): # 此處用于當(dāng)bool不存在時(shí)的找尋位置,為0則表示為空,則為False
return 0
print (bool(Point()))
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __bool__(self): # 同時(shí)存在,則以bool為準(zhǔn)
return False
def __len__(self):
return 1
print (bool(Point()))
結(jié)果如下
這也就是為啥空的字典和空集合以及空列表為False的原因了,因?yàn)槠錄](méi)有定義bool,因此其只能通過(guò)訪問(wèn)len來(lái)實(shí)現(xiàn)了 。
方法 | 意義 |
---|---|
_repr_ | 內(nèi)建函數(shù)repr()對(duì)一個(gè)對(duì)象獲取字符串表達(dá)式,如果一個(gè)類定義了_repr__但沒(méi)有定義_str\,那么在請(qǐng)求該類的實(shí)例的"非正式"的字符串也將調(diào)用_repr_() |
_str_ | str() 函數(shù),內(nèi)建函數(shù)format,print()函數(shù)調(diào)用,需要返回對(duì)象的字符串表達(dá)式 |
_bytes_ | bytes 的時(shí)候,返回一個(gè)獨(dú)享的bytes表達(dá),及返回bytes對(duì)象 |
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __repr__(self):
return str([self.x,self.y]) #此處的返回必須使用字符串進(jìn)行包裹,否則會(huì)報(bào)錯(cuò)
print (Point())
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __repr__(self):
return str([self.x,self.y]) #此處的返回必須使用字符串進(jìn)行包裹,否則會(huì)報(bào)錯(cuò)
def __str__(self): # 若存在此屬性,則上述的表達(dá)式將不會(huì)被調(diào)用
return 'abcdefg'
print (Point())
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __repr__(self):
return str([self.x,self.y]) #此處的返回必須使用字符串進(jìn)行包裹,否則會(huì)報(bào)錯(cuò)
def __str__(self): # 若存在此屬性,則上述的表達(dá)式將不會(huì)被調(diào)用
return 'abcdefg'
print (Point())
p1=Point()
p2=Point()
lst=[p1,p2]
for x in lst:
print (x)
print (lst)
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __repr__(self):
return str([self.x,self.y]) #此處的返回必須使用字符串進(jìn)行包裹,否則會(huì)報(bào)錯(cuò)
def __str__(self): # 若存在此屬性,則上述的表達(dá)式將不會(huì)被調(diào)用
return 'abcdefg'
print (Point())
p1=Point()
p2=Point()
lst=(p1,p2)
for x in lst:
print (x)
print (lst)
print (*lst) #進(jìn)行解包處理,此時(shí)是針對(duì)于對(duì)象上的,此時(shí)應(yīng)該調(diào)用的是str
上述實(shí)例證明,當(dāng)str和repr同時(shí)存在時(shí),如果輸出結(jié)果直接作用于對(duì)象上,則調(diào)用str方法,否則將調(diào)用repr方法
operator 模塊提供以下的特殊方法,可以將類的實(shí)例使用下面操作符來(lái)進(jìn)行操作
運(yùn)算符 | 特殊方法 | 含義 |
---|---|---|
<,<=,==,>,>=,!= | _lt_,_le_,_eq_,_gt_,_ge_,_ne_ | 比較運(yùn)算符 |
+,-,*,/,%,//,**,divmod | _add_,_sub_,_mul_,_truediv_,_mod_,_floordiv_,_pow_,_divmod_ | 算數(shù)運(yùn)算符,移位,位運(yùn)算也有對(duì)應(yīng)的方法 |
+=,-=,*=,/=,%=,//=,**= | _iadd_,_isub_,_imul_,_itruediv_,_imod_,_ifloordiv_,_ipow_ |
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __lt__(self, other):
return self.x < other.x
def __eq__(self, other):
return self.x == other.x
def __ne__(self, other):
return self.x != other.x
def __sub__(self, other):
return self.x - other.x
print (A(10)
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __iadd__(self, other): # 此處定義的是+= 返回的是self=self+other
self.x += other.x
print ('__iadd__')
return self # 此處返回的是一個(gè)實(shí)例,可通過(guò)調(diào)用其方法來(lái)實(shí)現(xiàn)此方法是否執(zhí)行
a1=A(10)
a2=A(20)
print ('*'*30)
a1+=a2
print (a1.x,a2.x)
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __iadd__(self, other): # 此處定義的是+= 返回的是self=self+other
# self.x += other.x
print ('__iadd__')
return A(self.x+other.x ) #此處方法相同
a1=A(10)
a2=A(20)
print ('*'*30)
a1+=a2
print (a1.x,a2.x)
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __iadd__(self, other): # 此處定義的是+= 返回的是self=self+other
# self.x += other.x
print ('__iadd__')
return A(self.x+other.x ) #此處方法相同
def __isub__(self, other):
print ('__isub__')
self.x -= other.x
return self
a1=A(10)
a2=A(20)
print ('*'*30)
a1+=a2
print (a1.x,a2.x)
a1-=a2
print (a1.x,a2.x)
functools.total_ordering 的應(yīng)用
默認(rèn)的
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __lt__(self, other): # 此處定義的是小于,現(xiàn)需要使用大于等于,則默認(rèn)會(huì)報(bào)錯(cuò)
return self.x < other.x
print (A(1) >= A(2))
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
from functools import total_ordering
@total_ordering
class A:
def __init__(self,x):
self.x=x
def __lt__(self, other): # 此處定義的是小于,現(xiàn)需要使用大于等于,則默認(rèn)會(huì)報(bào)錯(cuò)
return self.x < other.x
print (A(1) >= A(2))
print (A(1)==A(2))
print (A(1) != A(2))
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class Add:
def __init__(self,x:int):
self.x=x
def __add__(self, other):
print ('add',self)
return self.x+other.x
def __iadd__(self, other):
print ('iadd',self)
return self.x+other.x
def __radd__(self, other):
print ('radd',self)
return self.x+other.x
class B:
def __init__(self,x):
self.x=x
a=Add(3)
b=B(4)
print (a+b)
print (b+a)
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class Add:
def __init__(self,x:int):
self.x=x
def __add__(self, other):
print ('add',self)
return self.x+other.x
def __iadd__(self, other):
print ('iadd',self)
return self.x+other.x
def __radd__(self, other):
print ('radd',self)
return self+other # 此處self調(diào)用了add,其相當(dāng)于實(shí)例self.__add__(other)進(jìn)行處理的
class B:
def __init__(self,x):
self.x=x
a=Add(3)
b=B(4)
print (a+b)
print (b+a)
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class Add:
def __init__(self,x):
self.x=x
def __add__(self, other):
print ('add',self)
return self.x+other
def __iadd__(self, other):
print ('iadd',self)
return self.x+other.x
def __radd__(self, other):
print ('radd',self)
return self+other # 此處self調(diào)用了add,其相當(dāng)于實(shí)例self.__add__(other)進(jìn)行處理的
class B:
def __init__(self,x):
self.x=x
a=Add(3)
b=B(4)
print (1+a)
print (1+b)
結(jié)果如下
結(jié)論如下:
b+a 等價(jià)于 b.add(a),但是B類沒(méi)有實(shí)現(xiàn)add方法,就去找a的__radd__方法
1+a 等價(jià)于1.add(a),而int 類型實(shí)現(xiàn)了__add__放方法,不過(guò)這個(gè)方法對(duì)于這種加法的返回值是NotImplemented,解釋器發(fā)現(xiàn)了這個(gè)值,就會(huì)對(duì)第二個(gè)操作對(duì)象執(zhí)行__radd__進(jìn)行調(diào)用。
運(yùn)算符重載的應(yīng)用場(chǎng)景
往往是面向?qū)ο髮?shí)現(xiàn)的類,需要做大量的運(yùn)算,而運(yùn)算符是這種運(yùn)算在數(shù)學(xué)上最常見(jiàn)的表達(dá)方式,int 類中,幾乎實(shí)現(xiàn)了所有操作符,可以作為參考
內(nèi)建方法 | 含義 |
---|---|
_len_ | 內(nèi)建函數(shù)len(),返回對(duì)象的長(zhǎng)度(>=0的整數(shù)),其實(shí)即使吧對(duì)象當(dāng)作容器類型來(lái)看,就如同list或dict,bool()函數(shù)調(diào)用的時(shí)候,如果沒(méi)有_bool_()方法,則會(huì)看_len_()方法是否存在,存在返回非0為真,第三方庫(kù)中可能存在size,其和len的含義相同 |
_iter_ | 迭代器時(shí),調(diào)用,返回一個(gè)新的迭代器對(duì)象 |
_contains_ | in成員運(yùn)算符,沒(méi)有實(shí)現(xiàn),就調(diào)用__iter__方法遍歷 |
_getitem_ | 實(shí)現(xiàn)self[key]訪問(wèn),序列對(duì)象,key接受整數(shù)為索引,或者切片,對(duì)于set和dict,key為hashable,key不存在時(shí)引KeyError異常 |
_setitem_ | 和__getitem__的訪問(wèn)相似,是設(shè)置值的方法 |
_missing_ | 字典使用_getitem_()調(diào)用時(shí),key不存在執(zhí)行該方法 |
#!/usr/local/bin/python3.6
#coding:utf-8
class Item:
def __init__(self,name,*args):
self.name=name
self.lst=list(args)
def __len__(self):
return len(self.lst)
def __iter__(self):
return iter(self.lst) # 此處返回是一個(gè)迭代器,必須是一個(gè)迭代器
def __add__(self, other): # 此處使用+ 號(hào)返回一個(gè)列表
self.lst.append(other)
return self
def __getitem__(self, index): # 此處應(yīng)用于列表時(shí),表示為索引,此處應(yīng)用于字典時(shí),表示key
if index > len(self.lst):
print ('Key Error')
else:
return self.lst[index]
def __setitem__(self, index, value): # 此處表示修改屬性列表中的值
if index > len(self.lst):
print ('Key Error')
else:
self.lst[index]=value
return self
# def __missing__(self, key): # 此方法只能適用于字典的處理
# pass
def __repr__(self):
return str(self.lst) # 此處對(duì)其進(jìn)行可視化處理
a=Item('MySQL',12,3,45,678,8909)
print (len(a))
# 此處調(diào)用了__iter__方法
for i in a:
print (i)
print ('++++++++++++++++')
print (a[2]) # 此處調(diào)用了__getitem__方法,用于獲取值
a+10 # 此處使用__add__方法進(jìn)行加入,此處追加到列表的末尾
print (a[-1]) # 獲取列表的最后一個(gè)元素,則得到此值
a[1]=20 # 使用__setitem__方法修改屬性
print (a[1]) #返回對(duì)應(yīng)位置的值
a+10+20+30+40 # 此處進(jìn)行連加操作,因?yàn)槠鋋dd方法返回是self,因此每次賦值后都會(huì)增加
print (a)
結(jié)果如下
在python中一切皆對(duì)象,函數(shù)也不例外
可調(diào)用對(duì)象
方法
__call__類中出現(xiàn)該方法,實(shí)例就可以像函數(shù)一樣調(diào)用,
可調(diào)用對(duì)象: 定義一個(gè)類,并實(shí)例化得到其實(shí)例,將實(shí)例像函數(shù)一樣調(diào)用。調(diào)用是實(shí)例的,不是類的。
#!/usr/local/bin/python3.6
#coding:utf-8
def foo():
print (foo.__module__,foo.__name__)
foo.__call__()# 此處的方法和下面的相同,皆是調(diào)用該函數(shù)
foo()
print (dir(foo))
結(jié)果如下
函數(shù)的可調(diào)用原因是函數(shù)實(shí)現(xiàn)了\call()方法
#!/usr/local/bin/python3.6
#coding:utf-8
def foo():
print (foo.__module__,foo.__name__)
print (foo.__call__) # 此處返回一個(gè)函數(shù)對(duì)象是一個(gè)wrapper
foo.__call__()# 此處的方法和下面的相同,皆是調(diào)用該函數(shù)
foo()
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self):
self.x=1
def __call__(self, *args): # 此處的第一個(gè)是self,表明其是給實(shí)例使用的,并不是給類使用的
return args # 此處返回一個(gè)元組
print (A()(12344)) # 此處第一個(gè)括號(hào)是實(shí)例化,第二個(gè)是傳遞參數(shù)并調(diào)用實(shí)例
利用封裝完成斐波那契額數(shù)列
方法1
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __call__(self,num):
a,b=0,1
for i in range(num):
print (b)
a,b=b,a+b
A()(10)
結(jié)果如下
方法2
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self):
self.lst=[1,1,2]
def __call__(self,num):
if num < 3:
return self.lst[:num]
else:
for i in range(num-3):
self.lst.append(self.lst[-1]+self.lst[-2])
return self.lst
print (A()(10))
結(jié)果如下
添加功能如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __init__(self):
self.lst=[1,1,2]
def __len__(self):
return len(self.lst)
def __call__(self,x):
if len(self.lst) > x:
return self.lst[:x]
for i in range(2,x):
self.lst.append(self.lst[i]+self.lst[i-1])
return self.lst
def __getitem__(self, item):
if item < 0:
return None
if len(self) > item:
return self.lst[item]
def __iter__(self):
return iter(self.lst)
a=A()
print (a(10))
print (a[4])
for x in a:
print (x)
結(jié)果如下
文件IO操作可以對(duì)文件對(duì)象進(jìn)行上下文管理,使用with...as語(yǔ)法
推導(dǎo)過(guò)程
#!/usr/bin/poython3.6
#conding:utf-8
# 此處為默認(rèn)的上下文管理
# with open('test') as f:
# pass
class A:
pass
with A() as f:
pass
結(jié)果如下
提示需要添加 __enter__屬性
添加如下
#!/usr/bin/poython3.6
#conding:utf-8
# 此處為默認(rèn)的上下文管理
# with open('test') as f:
# pass
class A:
def __enter__(self):
pass
with A() as f:
pass
結(jié)果如下
提示需要添加 __exit__屬性
#!/usr/bin/poython3.6
#conding:utf-8
# 此處為默認(rèn)的上下文管理
# with open('test') as f:
# pass
class A:
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with A() as f:
pass
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __enter__(self):
print ('__enter__')
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
with A() as f:
pass
由此圖可知,其調(diào)用順序是先調(diào)用_enter_,后調(diào)用_exit_
方法 | 意義 |
---|---|
_enter_ | 進(jìn)入于此對(duì)象相關(guān)的上下文,如果存在該方法,with語(yǔ)法會(huì)把該方法的返回值作為綁定到as字句中指定的變量上 |
_exit_ | 退出與此對(duì)象的上下文 |
exit 中變量的含義:
1 exc_type: 異常類型,如果沒(méi)有異常,則返回是None
2 exc_tb:異常追蹤信息,如果沒(méi)有異常,則是None
3 exc_va :異常對(duì)應(yīng)的值,如果沒(méi)異常,則是None
此處的return 用于壓制異常,若此處是False,則會(huì)拋出異常,等效True 或 False缺少了enter 進(jìn)不去,缺少了exitc出不來(lái)
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __init__(self):
print ('init instance')
def __enter__(self):
print ('__enter__')
return 1
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
p=A()
with p as f: # 此處的p是__enter__的返回值,是f的參數(shù),若此處__enter__無(wú)return,則默認(rèn)返回為None,無(wú)意義
print (p==f) # 此處用于比較p和f的關(guān)系
print (p is f)
print (p)
print (f)
上述結(jié)論如下:
實(shí)例化對(duì)象的時(shí)候,并不會(huì)調(diào)用enter,進(jìn)入with語(yǔ)句塊會(huì)調(diào)用__enter__方法,然后執(zhí)行語(yǔ)句體,最后離開(kāi)with語(yǔ)句塊的時(shí)候,調(diào)用__exit__方法with 可以開(kāi)啟一個(gè)上下文運(yùn)行環(huán)境,在執(zhí)行前做一些準(zhǔn)備工作,執(zhí)行后做一些收尾工作。
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __init__(self):
print ('init instance')
def __enter__(self):
print ('__enter__')
return 1
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
p=A()
with p as f: # 此處的p是__enter__的返回值,是f的參數(shù),若此處__enter__無(wú)return,則默認(rèn)返回為None,無(wú)意義
raise Exception('Error') # 此處拋出異常,一般的,拋出異常后,語(yǔ)句將不會(huì)再次執(zhí)行
print (p==f) # 此處用于比較p和f的關(guān)系
print (p is f)
print (p)
print (f)
結(jié)果如下
由此證明,當(dāng)異常拋出時(shí),exit對(duì)應(yīng)的語(yǔ)句仍然會(huì)被執(zhí)行。
#!/usr/bin/poython3.6
#conding:utf-8
import sys
class A:
def __init__(self):
print ('init instance')
def __enter__(self):
print ('__enter__')
return 1
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
p=A()
with p as f: # 此處的p是__enter__的返回值,是f的參數(shù),若此處__enter__無(wú)return,則默認(rèn)返回為None,無(wú)意義
sys.exit() # 此處的是直接退出
print (p==f) # 此處用于比較p和f的關(guān)系
print (p is f)
print (p)
print (f)
結(jié)果如下
上述證明,此處滿足上述清理工作,上下文管理非常安全,能夠保證變量的順利清除工作。
#!/usr/bin/poython3.6
#conding:utf-8
import sys
class A:
def __init__(self):
print ('init instance')
def __enter__(self):
print ('__enter__')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
print (exc_tb) #追蹤信息
print (exc_type) # 類型
print (exc_val) # 值
return 1 # 此處設(shè)置為1 是壓制異常,不讓其出現(xiàn)
p=A()
with p as f: # 此處的p是__enter__的返回值,是f的參數(shù),若此處__enter__無(wú)return,則默認(rèn)返回為None,無(wú)意義
raise Exception('Error1234454')
print (p==f) # 此處用于比較p和f的關(guān)系
print (p is f)
print (p)
print (f)
結(jié)果如下
之前的計(jì)算時(shí)長(zhǎng)方式
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
import sys
def wapper(fn):
def _wapper(*args,**kwargs):
start_time=datetime.datetime.now()
ret = fn(*args,**kwargs)
delta=(datetime.datetime.now()-start_time).total_seconds()
print ("{} 函數(shù)的執(zhí)行時(shí)間為: {}".format(fn.__name__,delta))
return ret
return _wapper
@wapper
def add(x,y):
time.sleep(2)
return x+y
add(4,5)
結(jié)果如下
使用上下文管理的方式統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
class Timer:
def __init__(self,fn):
self.fn=fn
def __enter__(self):
self.start_time=datetime.datetime.now()
return self.fn # 此處對(duì)應(yīng)的是as前面的值
def __exit__(self, exc_type, exc_val, exc_tb):
delat=(datetime.datetime.now()-self.start_time).total_seconds()
print ("函數(shù){} 的執(zhí)行時(shí)間為: {}".format(self.fn.__name__,delat))
return 1
def add(x,y):
return x+y
p=Timer(add)
with p as f: # 此處調(diào)用的是__enter__的返回值,重命名為f
time.sleep(2)
print (f(4,5))
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
from functools import wraps
class A:
def __init__(self,fn):
self.fn=fn
def __call__(self,*args,**kwargs): #實(shí)例調(diào)用支持的方法
self.start_time=datetime.datetime.now()
ret = self.fn(*args,**kwargs)
delta=(datetime.datetime.now()-self.start_time).total_seconds()
print ("{} 函數(shù)的執(zhí)行時(shí)間為: {}".format(self.fn.__name__,delta))
return ret
@A #add=A(add)
def add(x,y):
time.sleep(2)
return x+y
print (add(10,20))
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
from functools import wraps
class A:
def __init__(self,fn):
self.fn=fn
def __call__(self,*args,**kwargs): #實(shí)例調(diào)用支持的方法
self.start_time=datetime.datetime.now()
ret = self.fn(*args,**kwargs)
delta=(datetime.datetime.now()-self.start_time).total_seconds()
print ("{} 函數(shù)的執(zhí)行時(shí)間為: {}".format(self.fn.__name__,delta))
return ret
@A #add=A(add)
def add(x,y):
'''this is function'''
time.sleep(2)
return x+y
print (add(10,20))
print (add.__doc__) # 此處打印出文檔
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
from functools import wraps
class A:
def __init__(self,fn):
self.__doc__=fn.__doc__ # 此處只能進(jìn)行部分的屬性覆蓋操作
self.__name__=fn.__name__
self.fn=fn
def __call__(self,*args,**kwargs): #實(shí)例調(diào)用支持的方法
self.start_time=datetime.datetime.now()
ret = self.fn(*args,**kwargs)
delta=(datetime.datetime.now()-self.start_time).total_seconds()
print ("{} 函數(shù)的執(zhí)行時(shí)間為: {}".format(self.fn.__name__,delta))
return ret
@A #add=A(add)
def add(x,y):
'''this is function'''
time.sleep(2)
return x+y
print (add(10,20))
print (add.__doc__) # 此處打印出文檔
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
from functools import wraps
class A:
def __init__(self,fn):
wraps(fn)(self) # 調(diào)用此方法完成屬性的覆蓋操作,此處第一個(gè)是原函數(shù),后面是現(xiàn)在的函數(shù)
self.fn=fn
def __call__(self,*args,**kwargs): #實(shí)例調(diào)用支持的方法
self.start_time=datetime.datetime.now()
ret = self.fn(*args,**kwargs)
delta=(datetime.datetime.now()-self.start_time).total_seconds()
print ("{} 函數(shù)的執(zhí)行時(shí)間為: {}".format(self.fn.__name__,delta))
return ret
@A #add=A(add)
def add(x,y):
'''this is function'''
time.sleep(2)
return x+y
print (add(10,20))
print (add.__doc__) # 此處打印出文檔
結(jié)果如下
是一個(gè)裝飾器實(shí)現(xiàn)上下文管理,裝飾一個(gè)函數(shù),而不像類一樣可以實(shí)現(xiàn)__enter__和__exit__方法
對(duì)下面的函數(shù)有要求,必須有yield,也就是這個(gè)函數(shù)必須返回一個(gè)和生成器,且只有一個(gè)yield的值。
#!/usr/bin/poython3.6
#conding:utf-8
import contextlib
@contextlib.contextmanager
def foo():
print ('enter')
yield
print ('exit')
with foo() as f:
pass
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
import contextlib
@contextlib.contextmanager
def foo():
print ('enter')
yield [1,2,34,56,5867,856,867,] # 此處相當(dāng)分界線,用于分割上面和下面的執(zhí)行
print ('exit')
with foo() as f:
print (f)
#!/usr/bin/poython3.6
#conding:utf-8
import contextlib
@contextlib.contextmanager
def foo():
print ('enter')
yield [1,2,34,56,5867,856,867,] # 此處相當(dāng)分界線,用于分割上面和下面的執(zhí)行
print ('12344exit')
with foo() as f:
try:
raise Exception
finally:
print ('exit')
print (f)
結(jié)果如下
修改異常捕獲如下
#!/usr/bin/poython3.6
#conding:utf-8
import contextlib
@contextlib.contextmanager
def foo():
print ('enter')
try:
yield [1,2,34,56,5867,856,867,] # 此處相當(dāng)分界線,用于分割上面和下面的執(zhí)行
finally: # 放置在此處能夠執(zhí)行后面的相關(guān)操作
print ('12344exit')
with foo() as f:
raise Exception
print (f)
結(jié)果如下
總結(jié): 如果業(yè)務(wù)邏輯簡(jiǎn)單可以使用函數(shù)加裝飾器的方式,如果業(yè)務(wù)復(fù)雜,用類的方式加__enter__和__exit__更方便
1 增強(qiáng)功能
在代碼執(zhí)行的前后增加代碼,以增強(qiáng)其功能,類似裝飾器的功能2 資源管理
打開(kāi)了資源需要關(guān)閉,例如文件對(duì)象,網(wǎng)絡(luò)鏈接,數(shù)據(jù)庫(kù)鏈接等3 權(quán)限驗(yàn)證
在執(zhí)行代碼之前,做權(quán)限的驗(yàn)證,在enter中處理
在代碼進(jìn)入的時(shí)候進(jìn)行處理,在權(quán)限出去則不管
運(yùn)行時(shí):區(qū)別于編譯時(shí),指的是程序被加載到內(nèi)存中執(zhí)行的時(shí)候。
反射:python中,能夠通過(guò)一個(gè)對(duì)象,找出其type,class,attribute或method的能力,成為反射或自醒。
具有反射能力的函數(shù)type(),isinstance(),callable()(查看對(duì)象能否被調(diào)用),dir(),getattr()
object 可以是類或?qū)嵗?
語(yǔ)法格式:
getattr(object,name[,default]) : 通過(guò)name 返回object的屬性值,當(dāng)屬性不存在時(shí),將使用default返回,如果沒(méi)有default,則拋出attributeError,name 必須位字符串
setattr(object,name,value) object 的屬性存在,則覆蓋,若不存在,則新增。
hasattr(object,name) 判斷對(duì)象是否有這個(gè)名字屬性,name必須時(shí)字符串
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=10
def __init__(self):
self.x=5
setattr(A,'y',20) # 動(dòng)態(tài)添加類屬性位y=20
print (A.__dict__) # 打印屬性信息列表
a=A()
setattr(a,'z',100) # 實(shí)例動(dòng)態(tài)增加屬性
print (getattr(A,'y')) # 查看增加的屬性是否存在
print (getattr(A,'x')) # 定義屬性是否存在
print (getattr(a,'y')) # 查看實(shí)例中是否存在該屬性
print (a.__dict__) # 查看實(shí)例屬性信息中是否具有'z'屬性
print (A.__dict__) # 打印屬性信息列表,此處查看當(dāng)實(shí)例屬性信息增加后,類屬性信息是否增加
if hasattr(a,'z'):
print ("{} 函數(shù)存在此屬性 {}".format('a','y'))
結(jié)果如下
進(jìn)階
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=10
def __init__(self,y):
self.x=5
self.y=y
a=A(20)
setattr(A,'printf',lambda self: 1 ) #此處增加一個(gè)類的屬性,并通過(guò)參數(shù)調(diào)用
setattr(a,'myclass',lambda : 10 ) # 此處增加一個(gè)實(shí)例屬性
print (a.printf()) # 打印此類的屬性結(jié)果如下
print (getattr(a,'printf')()) # 因?yàn)榇颂幨呛瘮?shù),因此需要通過(guò)()來(lái)進(jìn)行調(diào)用
print (getattr(a,'myclass')())
if not hasattr(A,'sub'): # 此處添加一個(gè)類的函數(shù)屬性,實(shí)現(xiàn)函數(shù)之前的差運(yùn)算
setattr(A,'sub',lambda self,other : A(self.y- other.y) )
if not hasattr(A,'add'): # 此處添加一個(gè)類的屬性,實(shí)現(xiàn)函數(shù)之間的和的計(jì)算
setattr(A,'add',lambda self,other: (self.y + other.y))
print (a.__dict__)
print (A.__dict__)
b1=A(10)
b2=A(20)
print (b2.sub(b1))
print (b1.add(b2))
結(jié)果如下
注意:
這種動(dòng)態(tài)增加屬性的方式是運(yùn)行時(shí)改變類或者實(shí)例的方式,比裝飾器和Mixin更加靈活,其具有更大的使用用途
實(shí)現(xiàn)分發(fā)器
簡(jiǎn)單雛形
#!/usr/bin/poython3.6
#conding:utf-8
class Dispatcher:
def cmd1(self): # 此處在內(nèi)部定義一個(gè)方法
print ('cmd10')
def run(self): # 此處用于執(zhí)行
while True:
cmd=input("plase input str:") #退出程序命令
if cmd.strip() == 'q' or cmd.strip() == 'quit':
return
getattr(self,cmd.strip(),self.__defaltfun)() # 此處用于獲取該方法,若不存在,則執(zhí)行默認(rèn)程序
def __defaltfun(self):
print ('default')
a=Dispatcher()
a.run()
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class Dispatcher:
def cmd1(self): # 此處在內(nèi)部定義一個(gè)方法
print ('cmd10')
def reg(self,cmd,fn):
if isinstance(cmd,str):
setattr(self.__class__,cmd.strip(),fn) # 此處使用的是類,若是實(shí)例化,則需要進(jìn)行下面將self傳入進(jìn)去的方式進(jìn)行調(diào)用
else:
print ('TypeError')
def run(self):
while True:
cmd = input("plase input str:")
if cmd.strip() == 'q' or cmd.strip() == 'quit':
return
getattr(self,cmd.strip(),self.defaultfun)()
def defaultfun(self):
print ('default')
a=Dispatcher()
a.reg('cmd2',lambda self :print (2))
a.reg('cmd3',lambda self :print (3))
a.run()
結(jié)果如下
魔術(shù)方法 | 意義 |
---|---|
_getattr_() | 當(dāng)通過(guò)搜索實(shí)例,實(shí)例的類以及祖先類查不到的屬性,就會(huì)調(diào)用此方法 |
_setattr_() | 通過(guò)訪問(wèn)實(shí)例屬性,進(jìn)行增加,修改都要調(diào)用它 |
_delattr_() | 當(dāng)通過(guò)實(shí)例刪除屬性的時(shí)候調(diào)用此方法 |
_getattribute_ | 實(shí)例所有的屬性調(diào)用都是從政方法開(kāi)始 |
實(shí)例如下:
#!/usr/bin/poython3.6
#conding:utf-8
class Base:
a=5
class A(Base):
m=6
def __init__(self,x):
print ('init')
self.x=x #此處定義了屬性,所以下面的__setattr__被執(zhí)行了一次,初始化先執(zhí)行,之后__setattr__這個(gè)屬性再執(zhí)行一次
def __getattr__(self, item):#針對(duì)上述無(wú)法查找到的屬性,則執(zhí)行此屬性,可配置其值為None來(lái)彌補(bǔ)此屬性值
print ('__getattr__',item)
self.__dict__[item]=None
def __setattr__(self, key, value): #設(shè)置一個(gè)屬性時(shí),一定要執(zhí)行,至于是否生效,則另當(dāng)別論
print ('__setattr__',key,value)
def __delattr__(self, item): #此處在刪除一個(gè)實(shí)例的屬性進(jìn)行的操作,只要實(shí)例能找到,都能夠刪除
print ('__delattr__',item)
A.n=50 # 此處是正常的添加類屬性,不會(huì)產(chǎn)生其他的報(bào)錯(cuò)
a=A(20)
print (a.__dict__)
a.b # 針對(duì)不存在的屬性進(jìn)行調(diào)用
a.x=30 # 設(shè)置實(shí)例的屬性變化
a.c=200 #添加一個(gè)不存在的屬性
del a.a # 刪除一個(gè)實(shí)例的屬性
print (a.__dict__)
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class Base:
a=5
class A(Base):
m=6
def __init__(self,x):
print ('init')
self.x=x #此處定義了屬性,所以下面的__setattr__被執(zhí)行了一次,初始化先執(zhí)行,之后__setattr__這個(gè)屬性再執(zhí)行一次
def __getattr__(self, item):#針對(duì)上述無(wú)法查找到的屬性,則執(zhí)行此屬性,可配置其值為None來(lái)彌補(bǔ)此屬性值
print ('__getattr__',item)
self.__dict__[item]=None
def __setattr__(self, key, value): #設(shè)置一個(gè)屬性時(shí),一定要執(zhí)行,至于是否生效,則另當(dāng)別論
print ('__setattr__',key,value)
def __delattr__(self, item): #此處在刪除一個(gè)實(shí)例的屬性進(jìn)行的操作,只要實(shí)例能找到,都能夠刪除
print ('__delattr__',item)
def __getattribute__(self, item): #此處是在字典屬性之前進(jìn)行攔截執(zhí)行
print ('__getattribute__',item)
a=A(20)
print (a.x)
結(jié)果如下
實(shí)例的所有屬性的訪問(wèn),第一個(gè)都會(huì)調(diào)用__getattribute__方法,其阻止了屬性查找,該方法應(yīng)該返回(計(jì)算后)值或者拋出一個(gè)attributeError 異常
他的return 值將作為屬性查找的結(jié)果,如果拋出attributeError 異常,則會(huì)直接調(diào)用__getattr__方法,因?yàn)楸硎緦傩詻](méi)有找到
#!/usr/bin/poython3.6
#conding:utf-8
class Base:
a=5
class A(Base):
m=6
def __init__(self,x):
print ('init')
self.x=x #此處定義了屬性,所以下面的__setattr__被執(zhí)行了一次,初始化先執(zhí)行,之后__setattr__這個(gè)屬性再執(zhí)行一次
def __getattr__(self, item):#針對(duì)上述無(wú)法查找到的屬性,則執(zhí)行此屬性,可配置其值為None來(lái)彌補(bǔ)此屬性值
print ('__getattr__',item)
# self.__dict__[item]=None
def __setattr__(self, key, value): #設(shè)置一個(gè)屬性時(shí),一定要執(zhí)行,至于是否生效,則另當(dāng)別論
print ('__setattr__',key,value)
def __delattr__(self, item): #此處在刪除一個(gè)實(shí)例的屬性進(jìn)行的操作,只要實(shí)例能找到,都能夠刪除
print ('__delattr__',item)
def __getattribute__(self, item): #此處是在字典屬性之前進(jìn)行攔截執(zhí)行
print ('__getattribute__',item)
raise AttributeError(item) # 此處若屬性不存在,拋出異常,則直接進(jìn)入getattr中機(jī)型處理
a=A(20)
print (a.x)
#!/usr/bin/poython3.6
#conding:utf-8
class Base:
a=5
class A(Base):
m=6
def __init__(self,x):
print ('init')
self.x=x #此處定義了屬性,所以下面的__setattr__被執(zhí)行了一次,初始化先執(zhí)行,之后__setattr__這個(gè)屬性再執(zhí)行一次
def __getattr__(self, item):#針對(duì)上述無(wú)法查找到的屬性,則執(zhí)行此屬性,可配置其值為None來(lái)彌補(bǔ)此屬性值
print ('__getattr__',item)
# self.__dict__[item]=None
def __setattr__(self, key, value): #設(shè)置一個(gè)屬性時(shí),一定要執(zhí)行,至于是否生效,則另當(dāng)別論
print ('__setattr__',key,value)
def __delattr__(self, item): #此處在刪除一個(gè)實(shí)例的屬性進(jìn)行的操作,只要實(shí)例能找到,都能夠刪除
print ('__delattr__',item)
def __getattribute__(self, item): #此處是在字典屬性之前進(jìn)行攔截執(zhí)行
print ('__getattribute__',item)
# raise AttributeError(item) # 此處若屬性不存在,拋出異常,則直接進(jìn)入getattr中機(jī)型處理
return object.__getattribute__(self,item) #此處表示若不存在,則直接去object中進(jìn)行查找,并得到其訪問(wèn)的值
a=A(20)
print (a.b)
結(jié)果如下
注意:\getattribute\ 方法中為了避免在該方法中無(wú)限遞歸,實(shí)現(xiàn)了應(yīng)該永久調(diào)用基類的同名方法以訪問(wèn)需要的任何屬性,除非你明確知道\getattribute\方法用來(lái)做什么,否則不要使用它。
標(biāo)題名稱:python類之特殊屬性和魔術(shù)方法
網(wǎng)頁(yè)URL:http://weahome.cn/article/pojcih.html