反射、自定義內置方法來定制類的功能、元類
一、反射
1. 定義:通過字符串來操作類或者對象屬性
2. 方法:hasattr、getattr、setattr、delattr
3. 使用方法:
1 class People: 2 def __init__(self,name): 3 self.name=name 4 def put(self): 5 print(‘%s is putting‘%self.name) 6 def get(self): 7 print(‘%s get sth‘%self.name) 8 def run(self):hasattr、setattr、getattr、delattr9 while True: 10 choice=input(‘>>‘).strip() 11 method=getattr(obj,choice,None) 12 13 # # 判斷對象obj裏邊有沒有choice這個屬性 14 # print(hasattr(obj,choice)) 15 16 # # obj.choice=z 17 # setattr(obj,choice,name) 18 19 ## delete boj.msg 20 # delattr(obj,msg) 21 if method is None: 22 print(‘command is not exists‘) 23 else: 24 # getattr 是取得字符串並將該字符串轉成可執行的函數 25 method() 26 27 obj=People(‘大王‘) 28 obj.run()
4.反射的好處:可以事先定義好接口,接口只有在被完成後才會真正執行,這實現了即插即用,這其實是一種‘後期綁定’,什麽意思?即你可以事先把主要的邏輯寫好(只定義接口),然後後期再去實現接口的功能
二、自定義內置方法來實現定制類的功能
1. __str__
class People: def __init__(self,name,age): self.name=name self.age=age # 在打印對象時會自動觸發這個功能 # 此時應該收集跟這個對象有關的信息,輸出到屏幕上 def __str__(self): return ‘<%s : %s>‘%(self.name,self.age) p=People(‘小天使‘,17) print(p)
2.__del__析構方法
class People: def __init__(self,name): self.name=name self.f=open(‘a.txt‘,‘rt‘,encoding=‘utf8‘) # 會在對象刪除之前自動觸發 def __del__(self): # print(‘>>>>>>>‘) # 做回收系統資源相關的事情 self.f.close() p=People(‘魔鬼‘) print(‘主‘)
三、元類
1.定義
在python中一切都是對象,所以用class 關鍵字定義的類本身也是一個對象,負責產生該對象的類稱之為元類,即產生類的類即稱為元類。
2.為何用元類
元類是負責產生類的,所以學習元類或者自定義元類的目的是為了控制類的產生過程,還可以控制對象的產生過程。
知識準備:
內置函數exec的用法:將函數體代碼執行一遍
# 將函數體代碼執行一遍,放至局部{}中 msg=‘‘‘ x=1 def func(): pass ‘‘‘ class_dic={} exec(msg,{},class_dic) print(class_dic)
__call__的用法
如果想要讓實例化出來的對象變成可以調用的對象,則需要在該對象的類中定義一個__call__的方法,該對象會在調用時自動觸發
class Foo: def __call__(self, *args, **kwargs): print(self) print(args) print(kwargs) obj=Foo() obj() obj(1,2,3,x=1,y=2)
執行結果入下圖
3. 創建類的方法有兩種
如果說類也是對象的話,那麽用class關鍵字去創建類的過程也是一個實例化的過程
該實例化的目的是為了得到一個類,調用的是元類
3.1 方式一:用默認的元類type
class People: def __init__(self,name): self.name=name def eat(self): print(‘%s is eating...‘%self.name) print(type(People))
3.1.1 創建類的三個要素 (類名,基類們,類的名稱空間)
class_name=‘People‘ #類名 class_bases=(object,) #基類 class_dic={} #類的名稱空間 class_body=‘‘‘ #類體代碼 class People: def __init__(self,name): self.name=name def eat(self): print(‘%s is eating...‘%self.name) print(type(People)) ‘‘‘ exec(class_body,{},class_dic)
3.2 用的自定義的元類
class Mymeta(type): # Mymeta=type(...) def __init__(self,class_name,class_bases,class_dic): super(Mymeta, self).__init__(class_name,class_bases,class_dic) class People(object,metaclass=Mymeta): # People=Mymeta(類名,基類們,類的名稱空間) def __init__(self,name): self.name=name def eat(self): print(‘%s is eating...‘%self.name) p=People(‘小三炮‘) p.eat()
原理:
3.2.1 得到一個字符串的類名 class_name = ‘People‘
3.2.2 得到一個類的基類們 class_bases = (object,)
3.3.3 執行類體代碼,得到一個類的名稱空間 class_dic = {...}
3.3.4 調用 People = type(class_name,class_bases,class_dic)
3.3 應用
自定義元類控制類的產生過程,類的產生過程其實就是元類的調用過程
class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): super(Mymeta, self).__init__(class_name,class_bases,class_dic) print(class_dic) # {‘__module__‘: ‘__main__‘, ‘__qualname__‘: ‘People‘, ‘__doc__‘: ‘ ‘, # ‘__init__‘: <function People.__init__ at 0x000001FCE6048AE8>} print(class_name) # People print(class_bases) # (<class ‘object‘>,) if class_dic.get(‘__doc__‘) is None and len(class_dic.get(‘__doc__‘))==0: raise TypeError(‘Document must exists and must not be None‘) if not class_name.istitle(): raise NameError(‘First letter must be capital‘) class People(object,metaclass=Mymeta): # if class_name‘initials is not capital,it # will report an error ‘‘‘ hey guys ‘‘‘ def __init__(self,name): self.name=name p=People(‘明日之星‘)
1 class Mymeta(type): 2 3 4 def __call__(self, *args, **kwargs): 5 6 # 先造出一個類的空對象 7 obj=self.__new__(self) 8 9 # 為該空對象初始化獨有屬性 10 self.__init__(obj,*args,**kwargs) 11 12 # 返回一個初始化好的對象 13 return obj 14 15 16 class People(object,metaclass=Mymeta): 17 def __init__(self,name): 18 print(self) 19 self.name=name 20 21 def eat(self): 22 print(‘%s is eating‘%self.name) 23 def __new__(cls, *args, **kwargs): #(涉及查找順序) 24 print(cls) # <class ‘__main__.People‘> 25 # cls.__new__(cls) # 錯誤 26 obj=super(People,cls).__new__(cls) 27 return obj 28 obj=People(‘大寶‘,)自定義元類來控制類的調用的過程,即類的實例化過程
反射、自定義內置方法來定制類的功能、元類