python3全棧開發-內置函數補充,反射,元類,__str__,__del__,exec,type,__call__方法
一、內置函數補充
1、isinstance(obj,cls)檢查是否obj是否是類 cls 的對象
class Foo(object): pass obj = Foo() print(isinstance(obj, Foo)) #結果為True
2、issubclass(sub, super)檢查sub類是否是 super 類的派生類
class Foo(object): pass class Bar(Foo): pass print(issubclass(Bar, Foo)) #結果為True
二、 反射
1 、什麽是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了計算機科學領域關於應用反射性的研究。它首先被程序語言的設計領域所采用,並在Lisp和面向對象方面取得了成績。
2 、python面向對象中的反射:通過字符串的形式操作對象相關的屬性。python中的一切事物都是對象(都可以使用反射)
四個可以實現自省的函數:
hasattr、getattr、setattr、delattr
下列方法適用於類和對象(一切皆對象,類本身也是一個對象)
# 1、hasattr # print(hasattr(People,‘country‘)) #True# print(‘country‘ in People.__dict__) #不知道hasattr方法時,用的方法 # print(hasattr(obj,‘name‘)) #True # print(hasattr(obj,‘country‘)) #True # print(hasattr(obj,‘tell‘)) #True # 2、getattr # x=getattr(People,‘country1‘,None) #查找指定屬性,沒有此屬性(提前預防報錯寫None)顯示None,有就返回值 # print(x)# f=getattr(obj,‘tell‘,None)#obj.tell # print(f == obj.tell) #True # f() #正常的調用函數 # obj.tell() # 3、setattr # People.x=111 # setattr(People,‘x‘,111) #添加x屬性,值為111 # print(People.x) # obj.age=18 # setattr(obj,"age",18) # 添加age屬性,值為18 # print(obj.__dict__) # 4、delattr # del People.country #原始的方法 # delattr(People,"country") # print(People.__dict__) # del obj.name # delattr(obj,"name") # print(obj.__dict__)
三、__str__
class People: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def __str__(self): # print(‘========>‘) return ‘<名字:%s 年齡:%s 性別:%s>‘ %(self.name,self.age,self.sex) obj=People(‘duoduo‘,18,‘male‘) print(obj) #print(obj.__str__()) 在print時觸發__str__
四、 __del__
當對象在內存中被釋放時,自動觸發執行。
註:如果產生的對象僅僅只是python程序級別的(用戶級),那麽無需定義__del__,如果產生的對象的同時還會向操作系統發起系統調用,即一個對象有用戶級與內核級兩種資源
import time class People: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def __del__(self): # 在對象被刪除的條件下,自動執行 print(‘__del__‘) obj=People(‘duoduo‘,18,‘male‘) #del obj #obj.__del__() #先刪除的情況下,直接執行__del__ time.sleep(5) #可以更形象的看出在資源回收前執行__del__
典型的應用場景:
創建數據庫類,用該類實例化出數據庫鏈接對象,對象本身是存放於用戶空間內存中,而鏈接則是由操作系統管理的,存放於內核空間內存中
當程序結束時,python只會回收自己的內存空間,即用戶態內存,而操作系統的資源則沒有被回收,這就需要我們定制__del__,在對象被刪除前向操作系統發起關閉數據庫鏈接的系統調用,回收資源
這與文件處理是一個道理:
f=open(‘a.txt‘) #做了兩件事,在用戶空間拿到一個f變量,在操作系統內核空間打開一個文件 del f #只回收用戶空間的f,操作系統的文件還處於打開狀態 #所以我們應該在del f之前保證f.close()執行,即便是沒有del,程序執行完畢也會自動del清理資源,於是文件操作的正確用法應該是 f=open(‘a.txt‘) 讀寫... f.close() #很多情況下大家都容易忽略f.close,這就用到了with上下文管理 class MyOpen: #自己寫個打開讀文件類,封裝內置的open def __init__(self,filepath,mode="r",encoding="utf-8"): self.filepath=filepath self.mode=mode self.encoding=encoding self.fobj=open(filepath,mode=mode,encoding=encoding) #申請系統內存 def __str__(self): msg=""" filepath:%s mode:%s encoding:%s """ %(self.filepath,self.mode,self.encoding) return msg def __del__(self): self.fobj.close() f=MyOpen(‘aaa.py‘,mode=‘r‘,encoding=‘utf-8‘) # print(f.filepath,f.mode,f.encoding) # print(f) # print(f.fobj) res=f.fobj.read() #一樣可以讀 print(res)
五、exec
#例子 一 code=""" #global x #shsh聲明x為全局變量 x=0 y=2 """ global_dic={‘x‘:100000} local_dic={} #字符串中聲明全局就是全局,不聲明就是局部 exec(code,global_dic,local_dic) # # print(global_dic) # print(local_dic) #例子 二 # code=""" # x=1 # y=2 # def f1(self,a,b): # pass # """ # local_dic={} # exec(code,{},local_dic) # print(local_dic)
六、元類
1、什麽是元類:
類的類就是元類
#我們用class定義的類使用來產生我們自己的對象的
#內置元類type是用來專門產生class定義的類的
#一切皆為對象: # Chinese=type(...) class Chinese: country="China" def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def speak(self): print(‘%s speak Chinese‘ %self.name) # print(Chinese) # p=Chinese(‘duoduo‘,18,‘male‘) # print(type(p)) #最上層的類 type # print(type(Chinese))
2、用內置的元類type,來實例化得到我們的類
#2、用內置的元類type,來實例化得到我們的類 class_name=‘Chinese‘ class_bases=(object,) lass_body=""" country="China" def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def speak(self): print(‘%s speak Chinese‘ %self.name) """ class_dic={} exec(class_body,{},class_dic) #類的三大要素 # print(class_name,class_bases,class_dic) Chinese=type(class_name,class_bases,class_dic) # print(Chinese) p=Chinese(‘duoduo‘,18,‘male‘) # print(p.name,p.age,p.sex)
3、 __call__
對象後面加括號,觸發執行。
註:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()
class Foo: def __init__(self): pass def __str__(self): return ‘123123‘ def __del__(self): pass # 調用對象,則會自動觸發對象下的綁定方法__call__的執行, # 然後將對象本身當作第一個參數傳給self,將調用對象時括號內的值 #傳給*args與**kwargs def __call__(self, *args, **kwargs): print(‘__call__‘,args,kwargs) obj=Foo() # print(obj) obj(1,2,3,a=1,b=2,c=3) #
4、自定義元類
class Mymeta(type): # 來控制類Foo的創建 def __init__(self,class_name,class_bases,class_dic): #self=Foo # print(class_name) # print(class_bases) # print(class_dic) if not class_name.istitle(): #加上判斷 raise TypeError(‘類名的首字母必須大寫‘) if not class_dic.get(‘__doc__‘): raise TypeError(‘類中必須寫好文檔註釋‘) super(Mymeta,self).__init__(class_name,class_bases,class_dic) # 控制類Foo的調用過程,即控制實例化Foo的過程 def __call__(self, *args, **kwargs): #self=Foo,args=(1111,) kwargs={} # print(self) # print(args) # print(kwargs) #1 造一個空對象obj obj=object.__new__(self) #2、調用Foo.__init__,將obj連同調用Foo括號內的參數一同傳給__init__ self.__init__(obj,*args,**kwargs) return obj #Foo=Mymeta(‘Foo‘,(object,),class_dic) class Foo(object,metaclass=Mymeta): """ 文檔註釋 """ x=1 def __init__(self,y): self.Y=y def f1(self): print(‘from f1‘) obj=Foo(1111) #Foo.__call__() # print(obj) # print(obj.y) # print(obj.f1) # print(obj.x)
5、單例模式
import settings #調用配置文件的IP,PORT class MySQL: __instance=None def __init__(self,ip,port): self.ip=ip self.port=port @classmethod #綁定方法 def singleton(cls): if not cls.__instance: obj=cls(settings.IP, settings.PORT) cls.__instance=obj return cls.__instance obj1=MySQL(‘1.1.1.2‘,3306) obj2=MySQL(‘1.1.1.3‘,3307) obj3=MySQL(‘1.1.1.4‘,3308) # obj4=MySQL(settings.IP,settings.PORT) # print(obj4.ip,obj4.port) obj4=MySQL.singleton() obj5=MySQL.singleton() obj6=MySQL.singleton() print(obj4 is obj5 is obj6) #Ture
python3全棧開發-內置函數補充,反射,元類,__str__,__del__,exec,type,__call__方法