python中面向物件元類的自定義用法
阿新 • • 發佈:2018-12-20
instance :判斷兩個物件是不是一類
issubclass :判斷某個類是不是另一個類的子類
#兩個常用方法的使用 class Person: pass class Student(Person): pass stu = Student() print(isinstance(stu, Student)) print(issubclass(Student,Person)) True True ##輸出的結果是布林值。
2.反射
反射,其實就是反省。簡單來講就是物件要具備一種修正錯誤的能力。
#四種方法: hasattr #判斷是否存在屬性 getattr #獲取某個屬性的值 setattr #設定某個屬性的值 delattr #刪除某個屬性 #這四種方法的共同點,都是通過字串來操作屬性,通過字串操作。 #示例:反射屬性 class Student: def __init__(self, name, sex, age): self.name = name self.age = age self.sex = sex def study(self): print('student is studying') deng = Student('deng', 'male', 25) #當我們獲取一個物件,但是不清楚物件內部細節,就需要用反射。 def test(obj): if hasattr(obj, 'name'): print(getattr(obj, 'name', "no 'name' attribute")) test(deng) #示例:反射方法 #通過反射方法的方式為物件增加一個方法,但是注意,這樣增加的方法就是一個普通函式,不會自動傳值。 res = getattr(deng, 'study', None)print(res) res() def run(obj): print('student is running') setattr(deng,'run',None) res1 = getattr(deng, 'run',None) run(deng) #deng #<bound method Student.study of <__main__.Student object at 0x00000272D8DB8C50>> #student is studying #student is running
3._ _str _ _內建方法
當我們需要自定義顯示內容時,就需要實現 _ _str _ _方法
#該方法必須返回一個字串,返回是什麼,打印出來就是什麼。 class Test: def __init__(self,name): self.name = name def __str__(self): print('str run...') return self.name t = Test('ming') print(t)
其實,在我們將一個物件轉換為字串時,本質就是在呼叫這個物件的_ str _ _方法。
4. _ _del _ _內建方法
該方法在物件(程式,檔案,等等)被從記憶體中刪除時會自動執行該方法。
class Student: def __del__(self): print('物件被刪除。。。') stu = Student() #建立stu物件 #當該stu物件建立完成後該程式就執行結束,就會執行del方法。 #觸發__del__有兩種: 1.程式自動執行結束 2.手動刪除,會立即執行__del__ #示例: class Student: def __del__(self): print('物件被刪除。。。') stu = Student() del stu #在這就會列印,但這是程式並未結束 import time time.sleep(5) 什麼時候使用它 在python中 有自動記憶體管理機制 所以 python自己建立的資料 不需要我們做任何操作 但是有一種情況 我們使用python打開了一個不屬於python管理的資料 比如打開了一個檔案 這個檔案一定是作業系統在開啟 會佔用系統記憶體 而python直譯器無法作業系統記憶體的 所以 當你的python直譯器執行結束後 檔案依然處於開啟狀態 這時候就需要使用__del__來關閉系統資源 簡單地說 當程式執行結束時 需要做一些清理操作 就使用__del__ __del__也稱之為 解構函式 分析構造 並拆除這個物件
5.exec方法
該方法是解析執行python程式碼(字串型別) 並且將得到的名稱 儲存到制定的名稱空間 直譯器內部也是呼叫它來執行程式碼。直譯器內部也是將程式碼看做字串。
該方法有三個引數:
引數一 需要一個字串物件, 表示需要被執行的python語句
引數二 是一個字典,表示全域性名稱空間
引數三 是一個字典,表示區域性名稱空間
#示例: globals_dic = {} locals_dic = {} exec(''' a = 1 if a >1: print('ming') else: print('deng')''', globals_dic, locals_dic)
#注意:
1.如果同時制定了全域性和區域性的,則會將字串中包含的名稱解析後存到區域性名稱空間。
2.如果只傳了一個傳引數 則 將字串中包含名稱 解析後存到全域性中。
6.元類
-
使用class可以發現,類其實是type型別的例項(物件)。
-
一切皆物件
-
元類是指 用於產生類的類 type就是元類
class Student: def study(self): print('studying') print(type(Student))
總結:
1.類由type例項化產生
2.我們可以使用type產生一個類
3.一個類由類名,類的父類,類的名稱空間組成。
type類例項化可以得到類,類例項化可以得到物件。
7._ _ call _ _ 內建方法
_ _ call _ _呼叫的意思,在物件被呼叫的時候執行該方法(執行該物件所屬的類)
#示例: class Person: def __call__(self, *args, **kwargs): print('call running') p = Person() #建立物件不會執行call內建方法 p() # call running 物件被呼叫時會自動執行該方法。
自定義元類 的目的
1.可以通過call 來控制物件的建立過程
2.可用控制類的建立過程
自定義一個元類(元類也是一個類),但該類需繼承元類type。
#1.通過__call__來控制物件的建立過程 #1.建立一個元類(需要繼承type) #2.覆蓋__call__方法,會將正在例項化物件的類轉化為傳入的引數 #3.在新的__call__方法中,需要按下面編寫,然後再加你需要的控制邏輯即可。 class MyMeta(type): #self表示建立物件的那個類,*args, **kwargs引數 def __call__(self, *args, **kwargs): print('MyMeta中的call') #下面三步是固定的 #1.建立物件 obj = object.__new__(self) #2.呼叫初始化方法 self.__init__(obj,*args,**kwargs) #3.得到一個完整的物件 return obj #先修改Person的元類為MyMeta class Person(metaclass=MyMeta): def __init__(self,name ,age): self.name = name self.age = age def __call__(self, *args, **kwargs): print('call is running...') deng = Person('deng', 26) print(deng) deng() #### MyMeta中的call <__main__.Person object at 0x00000251588D89B0> call is running... #2.通過元類控制類的建立過程: #1.建立一個元類(需要繼承type) #2.覆蓋__init__方法,該方法會新建類的物件,類名,父類名,名稱空間,可以利用這些資訊做處理 #3.對於需要控制的類,需要指定metaclass為上面元類 class MyMeta(type): def __init__(self, class_name, bases, namespace): print('=======') #控制類名必須大寫 if not class_name.istitle(): print('類名必須大寫開頭。。。') #該程式碼主動丟擲異常 raise TypeError('類名,開頭必須大寫開頭。。。') if not self.__doc__: raise TypeError pass class Student(metaclass=MyMeta): ''' 這是文件註釋,可以通過__doc__獲取 ''' #在類的__init__中可以控制該類物件的建立過程 def __init__(self, name): print('+++++++++++++') print(self.__doc__) self.name = name print(Student.__doc__)
8.單例模式
單例 一種設計模式
單個物件,一個類如果只有一個例項,那麼該類稱之為單例
為什麼需要單例?
class MyMeta(type): obj = None def __call__(self, *args, **kwargs): if not MyMeta.obj: obj = object.__new__(self) self.__init__(obj, *args, **kwargs) MyMeta.obj = obj return MyMeta.obj class Printer(metaclass=MyMeta): ''' 這是一個單例類,請不要直接例項化,使用get方法獲取例項 ''' obj = None def __init__(self, name, type): self.name = name self.type = type def printing(self, text): print('正在列印%s' % text) @classmethod def get_printer(cls): if not cls.obj: obj = cls('ec001', 'sharp') cls.obj = obj print('建立新物件') return cls.obj p = Printer.get_printer() print(p.name) print(p) p1 = Printer('ming','002') print(p1.name) print(p1)
總結: