isinstance和issubclass isinstance()判斷一個對象是不是這個類的對象,傳兩個參數(對象,類) issubclass()判斷一個類是不是另一類的子類,傳兩個參數(子類,父類) class Foo: pass class Son(Foo): pass s = Son() # ...
isinstance和issubclass
isinstance()判斷一個對象是不是這個類的對象,傳兩個參數(對象,類)
issubclass()判斷一個類是不是另一類的子類,傳兩個參數(子類,父類)
class Foo: pass class Son(Foo): pass s = Son() #判斷一個對象是不是這個類的對象,傳兩個參數(對象,類) print(isinstance(s,Son)) print(isinstance(s,Foo)) #type更精準 print(type(s) is Son) print(type(s) is Foo) #判斷一個類是不是另一類的子類,傳兩個參數(子類,父類) print(issubclass(Son,Foo)) print(issubclass(Son,object)) print(issubclass(Foo,object)) print(issubclass(int,object))test
反射
反射的概念是由Smith在1982年首次提出的,主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了電腦科學領域關於應用反射性的研究。它首先被程式語言的設計領域所採用,併在Lisp和麵向對象方面取得了成績。
python面向對象中的反射:通過字元串的形式操作對象相關的屬性。python中的一切事物都是對象(都可以使用反射)
四個可以實現反射的函數:hasattr,getattr,setattr,delattr。
hasattr判斷object,類中有沒有一個name字元串對應的方法或屬性,返回bool。
class People: country='China' def __init__(self,name): self.name=name # def walk(self): # print('%s is walking' %self.name) p=People('egon') #hasattr是否有這個屬性 print('name' in p.__dict__)#True print(hasattr(p,'name'))#True print(hasattr(p,'name1213'))#Falsehasattr
getattr,通過資費穿的方式直接操作。
res=getattr(p,'country') #拿到返回值相當於res=p.country print(res)#China f=getattr(p,'walk') #t=p.walk print(f)#<bound method People.walk of <__main__.People object at 0x000000000221DE10>> f1=getattr(People,'walk') print(f1)#<function People.walk at 0x000000000221BA60> f()#egon is walking f1(p)#egon is walkinggetattr
print(getattr(p,'xxxxxxxx','這個屬性確實不存在'))
p.sex='male' print(p.sex)#male print(p.__dict__)#{'name': 'egon', 'sex': 'male'} setattr(p,'age',18) print(p.__dict__)#{'age': 18, 'name': 'egon', 'sex': 'male'} print(p.age)#18 print(getattr(p,'age'))#18setattr
# print(p.__dict__) # del p.name # print(p.__dict__) print(p.__dict__)#{'name': 'egon', 'sex': 'male', 'age': 18} delattr(p,'name') print(p.__dict__)#{'sex': 'male', 'age': 18}delattr
#反射當前模塊的屬性也就是模塊級別的反射 import sys x=1111 class Foo: pass def s1(): print('s1') def s2(): print('s2') # print(__name__) this_module = sys.modules[__name__]#獲取當前模塊的對象 print(this_module)#拿到當前的模塊了 print(hasattr(this_module, 's1'))#模塊有沒有這個屬性 print(getattr(this_module, 's2')) print(this_module.s2)#下麵兩者等價於上面 print(this_module.s1)模塊級別的反射
import sys def add(): print('add') def change(): print('change') def search(): print('search') def delete(): print('delete') this_module=sys.modules[__name__] while True: cmd=input('>>:').strip() if not cmd:continue if hasattr(this_module,cmd): func=getattr(this_module,cmd) func() # if cmd in func_dic: #hasattr() # func=func_dic.get(cmd) #func=getattr() # func() # func_dic={ 'add':add, 'change':change, 'search':search, 'delete':delete } while True: cmd=input('>>:').strip() if not cmd:continue if cmd in func_dic: #hasattr() func=func_dic.get(cmd) #func=getattr() func()早前就一直使用的函數反射
總的來說反射其實就是在找他們的名稱空間是否有這些名稱,也就是是否有我們需要的屬性,然後返回相關的值。
class Foo: x=1 def __init__(self,name): self.name=name def walk(self): print('walking......') f=Foo('egon') Foo.__dict__={'x':1,'walk':....} 'x' in Foo.__dict__ #hasattr(Foo,'x') Foo.__dict__['x'] #getattr(Foo,'x') print(Foo.x) #'x' in Foo.__dict__反射就是找名稱空間
可插拔機制
在現實生產環境經常會遇到兩名程式員共同完成一個項目的情況,比如一個人寫server端另一個人寫client端,但是server的這個程式員某些功能還沒寫完就請假了,client的程式員需要用到他還未完成的功能,
使用反射機制可以實現可插拔機制。反射的好處就是,可以事先定義好介面,介面只有在被完成後才會真正執行,這實現了即插即用,這其實是一種‘後期綁定’,即你可以事先把主要的邏輯寫好(只定義介面),然後後期再去實現介面的功能。
class FtpClient: 'ftp客戶端,但是還麽有實現具體的功能' def __init__(self,addr): print('正在連接伺服器[%s]' %addr) self.addr=addr def test(self): print('test') def get(self): print('get------->')ftpclient
import ftpclient # # print(ftpclient) # print(ftpclient.FtpClient) # obj=ftpclient.FtpClient('192.168.1.3') # # print(obj) # obj.test()他還沒寫test所以會出錯 # f1=ftpclient.FtpClient('192.168.1.1') if hasattr(f1,'get'):#對方實現我就用 func=getattr(f1,'get') func() else: print('其他邏輯')ftpserver
字元串導入模塊
#不推薦 m=input("請輸入你要導入的模塊:") m1=__import__(m) print(m1) print(m1.time())__import__
#推薦使用方法 import importlib t=importlib.import_module('time') print(t.time())導入模塊
__setattr__,__getattr__,__delattr__
__setattr__為對象設置修改屬性時觸發運行。
class Foo: def __init__(self,x): self.name=x # def __setattr__(self, key, value): # self.key=value#字元串類型不能使用這個方式要使用反射 # setattr(self,key_str,value) #self.key_attribute=value相當於再次觸發了 __setattr__產生遞歸 self.__dict__[key]=value#設置時加入dict f1=Foo('egon') #f1.name='egon' f1.age=18#設置時觸發 __setattr____setattr__
__delattr__刪除對象屬性時觸發。
def __delattr__(self, item): print('delattr:%s' %item) print(type(item)) # delattr(self,item) # del self.item self.__dict__.pop(item) print(f1.__dict__) del f1.age print(f1.__dict__) print(f1.age)__delattr__
__getattr__只有當查找屬性不存在時才會觸發,存在就直接返回了。
class Foo: def __init__(self,x): self.name=x #屬性不存在的情況下才會觸發 def __getattr__(self, item): print('getattr-->%s %s' %(item,type(item))) f=Foo('egon') print(f.name)#返回x print(f.xxxxxxx)#調用__getattr____getattr__
定製自己的數據類型
我們之前學習的列表,字典等都是數據類型,我們可以通過繼承派生出自己的數據類型。
class List(list): pass l=List([1,2,3]) print(l) l.append(4) print(l)list
當然我們定製不僅僅是繼承,還要派生自己的屬性。
class List(list): def append(self, p_object): # print('--->',p_object) if not isinstance(p_object,int):#只讓append數字 raise TypeError('must be int') # self.append(p_object)遞歸 super().append(p_object) def insert(self, index, p_object): if not isinstance(p_object,int): raise TypeError('must be int') # self.append(p_object) super().insert(index,p_object) l=List([1,2,3]) # print(l) # l.append(4) # print(l) # l.append('5') print(l) # l.insert(0,-1) l.insert(0,'-1123123213') print(l)list++
註:__annotations__可以看到你要求的類型。
def test(x:int,y:int)->int: return x+y print(test.__annotations__) #{'x': <class 'int'>, 'return': <class 'int'>, 'y': <class 'int'>} print(test(1,2))__annotations__
不能用繼承,來實現open函數(不是類)的功能,授權的方式實現定製自己的數據類型。
import time class Open: def __init__(self,filepath,m='r',encode='utf-8'): self.x=open(filepath,mode=m,encoding=encode)#正常打開文件的操作保存給open類的私有屬性 self.filepath=filepath self.mode=m self.encoding=encode def write(self,line): print('f自己的write',line) t=time.strftime('%Y-%m-%d %X') self.x.write('%s %s' %(t,line))#self.x就是文件句柄 def __getattr__(self, item):#授權,找不到屬性就找他 # print('=------>',item,type(item)) return getattr(self.x,item) # # f=Open('b.txt','w') # # print(f) # f.write('111111\n') # f.write('111111\n') # f.write('111111\n') f=Open('b.txt','r+') # print(f.write) print(f.read) res=f.read() #self.x.read() print(res) print('=-=====>',f.read()) f.seek(0) print(f.read()) # f.flush() # f.close()自製open類
item系列,把對象操作屬性模擬成字典的格式。用.方法調用的就是__attr__系列,用[key]方式就是調用__item__系列。
class Foo: def __init__(self,name): self.name=name def __setattr__(self, key, value):#與他的區別就在於item是調用的k,v的格式 print('setattr===>') def __getitem__(self, item): # print('getitem',item) return self.__dict__[item] def __setitem__(self, key, value): print('setitem-----<') self.__dict__[key]=value def __delitem__(self, key): self.__dict__.pop(key) # self.__dict__.pop(key) # def __delattr__(self, item): # print('del obj.key時,我執行') # self.__dict__.pop(item) f=Foo('egon')#調用__setattr__ # f.name='egonlin' f['name']='egonlinhai'#調用__setitem__ # print(f.name) # f.name='egonlin' # f['age']=18 # print(f.__dict__) # del f['age'] #del f.age print(f.__dict__) print(f['name'])#__getitem__item系列
__str__列印時觸發,__repr__與前者差不多,前者輸出更友好。
__format__自定製格式化字元串
__slots__
class People: __slots__=['x','y','z']#對象不會再創建名稱空間,對象都用類的名稱空間 p=People() # print(People.__dict__)沒dict p.x=1 p.y=2 p.z=3 p.a=4#__slots__使類只開闢x,y,z空間,對象名稱不能加入 print(p.x,p.y,p.z,p.a) # print(p.__dict__) p1=People() p1.x=10 p1.y=20 p1.z=30 print(p1.x,p1.y,p1.z) print(p1.__dict__)__slots__
__iter__,__next__
class Foo: def __init__(self,start): self.start=start def __iter__(self): return self def __next__(self): if self.start > 10: raise StopIteration n=self.start self.start+=1 return n f=Foo(0) print(next(f)) #f.__next__() for i in f: # res=f.__iter__() #next(res) print(i)View Code
class Range: '123' def __init__(self,start,end): self.start=start self.end=end def __iter__(self): return self def __next__(self): if self.start == self.end: raise StopIteration n=self.start self.start+=1 return n for i in Range(0,3): print(i)自製range
__doc__,__moudle__,__class__
class Foo: '我是描述信息' pass class Bar(Foo): pass print(Bar.__doc__) #None該屬性無法繼承給子類 b=Bar() print(b.__class__)#<class '__main__.Bar'> print(b.__module__)#__main__ print(Foo.__module__)#__main__ print(Foo.__class__) #<class 'type'>View Code
__del__析構方法,當對象在記憶體中被釋放時,自動觸發執行,此方法一般無須定義,因為Python是一門高級語言,程式員在使用時無需關心記憶體的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。
f=open('a.txt') #做了兩件事,在用戶空間拿到一個f變數,在操作系統內核空間打開一個文件 del f #只回收用戶空間的f,操作系統的文件還處於打開狀態 #所以我們應該在del f之前保證f.close()執行,即便是沒有del,程式執行完畢也會自動del清理資源,於是文件操作的正確用法應該是 f=open('a.txt') 讀寫... f.close()#清理的時候就調用析構方法 很多情況下大家都容易忽略f.close,這就用到了with上下文管理
import time class Open: def __init__(self,filepath,mode='r',encode='utf-8'): self.f=open(filepath,mode=mode,encoding=encode) def write(self): pass def __getattr__(self, item): return getattr(self.f,item) def __del__(self): print('----->del') self.f.close() f=Open('a.txt','w') f1=f del f print('=========>')f.close
__enter__和__exit__
with open('a.txt') as f:叫做上下文管理協議,即with語句,為了讓一個對象相容with語句,必須在這個對象的類中聲明__enter__和__exit__方法。
class Open: def __init__(self,name): self.name=name def __enter__(self): print('出現with語句,對象的__enter__被觸發,有返回值則賦值給as聲明的變數') # return self def __exit__(self, exc_type, exc_val, exc_tb): print('with中代碼塊執行完畢時執行我啊') with Open('a.txt') as f: print('=====>執行代碼塊') # print(f,f.name)上下文管理協議
__exit__()中的三個參數分別代表異常類型,異常值和追溯信息,with語句中代碼塊出現異常,則with後的代碼都無法執行。
如果__exit()返回值為True,那麼異常會被清空,就好像啥都沒發生一樣,with後的語句正常執行
class Foo: def __enter__(self): print('=======================》enter') return 111111111111111 def __exit__(self, exc_type, exc_val, exc_tb):#with代碼塊已執行完就會觸發__exit__ print('exit') print('exc_type',exc_type) print('exc_val',exc_val) print('exc_tb',exc_tb) return True # with Foo(): #觸發res=Foo().__enter__()拿到返回值 # pass with Foo() as obj: #res=Foo().__enter__() #obj=res print('with foo的自代碼塊',obj)#obj就是__enter__的返回值 raise NameError('名字沒有定義') print('************************************')#他是不會執行的拋異常已經觸發__exit__了 print('1111111111111111111111111111111111111111')#返回ture異常解決,否則拋異常不執行了