Python面向对象中反射和双下的正确用法
一.反射
反射:程序可以訪問,檢測和修改它本身狀態或行為的一種能力(自省)
python面向對象中的反射:通過字符串的形式操作對象相關的屬性
python中的一切事物都是對象(都可以使用反射)
四個可以實現自省的函數,下列方法適用于類和對象(一切對象,類本身也是對象)
# 對實例化對象的示例 class Foo:f = '類的靜態變量'def __init__(self, name, age):self.name = nameself.age = agedef say_hi(self):print(f'Hi,{self.name}') obj = Foo('小馬', 18)# 檢測是否含有某屬性 print(hasattr(obj, 'name')) # True print(hasattr(obj, 'say_hi'))# 獲取屬性 n = getattr(obj, 'name') print(n) func = getattr(obj, 'say_hi') func() print(getattr(obj, 'aaa', '不存在啊')) # 沒有會返回設定好的信息,不設定則報錯# 設置屬性 setattr(obj, 'hello', True) # 設置字段 hello = True setattr(obj, 'show_name', lambda self: self.name + '美女') # 設置方法 print(obj.__dict__) print(obj.show_name(obj)) # 設置的函數也在對象空間中# 刪除屬性 delattr(obj, 'age') delattr(obj, 'show_name') delattr(obj, 'show_name111') # 不存在就會報錯print(obj.__dict__) ----------------------------------------------------- # 對類的反射 class Foo:Class_name = '天上人間'def __init__(self, name):self.name = namedef func(self):return 'func'@staticmethoddef bar():return 'bar'print(getattr(Foo, 'Class_name')) print(getattr(Foo, 'func')) print(getattr(Foo, 'bar')) -----------------------------------------------------# 當前模塊的反射 import sys def s1():print('s1') def s2():print('s2')this_module = sys.modules[__name__] # 獲取當前腳本這個對象 print(hasattr(this_module, 's1')) a = getattr(this_module, 's2') a() ----------------------------------------------------- # 其他模塊的發射 # 一個模塊中代碼(module_test.py) def test():print('from the test')# 本模塊中的代碼 import module_test as obj obj.test() print(hasattr(obj, 'test')) a = getattr(obj, 'test') a() ----------------------------------------------------- # 反射的應用 # 模擬訪問網站 class User:def login(self):print('歡迎來到登錄頁面')def register(self):print('歡迎來到注冊頁面')def save(self):print('歡迎來到存儲頁面')user = User() while 1:choose = input('>>>:').strip()if hasattr(user, choose):func = getattr(user, choose)func()else:print('輸入錯誤!')二.函數VS方法
1.判斷函數與方法的途徑
通過打印函數(方法)名確定
''' 學習中遇到問題沒人解答?小編創建了一個Python學習交流QQ群:725638078 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' def func():passprint(func) # <function func at 0x01CCF7C8>class A:def func(self):passprint(A.func) # <function A.func at 0x03AAA588> obj = A() print(obj.func) # <bound method A.func of <__main__.A object at 0x01D05450>>通過types模塊驗證
from types import FunctionType from types import MethodTypedef func():passclass A:def func(self):passobj = A() print(isinstance(func, FunctionType)) # True print(isinstance(A.func, FunctionType)) # True print(isinstance(obj.func, FunctionType)) # False print(isinstance(obj.func, MethodType)) # True --------------------------------------------------- # 靜態方法是函數 from types import FunctionType class A:def func(self):pass@classmethoddef func1(self):pass@staticmethoddef func2(self):pass obj = A() # 靜態方法其實是函數 print(isinstance(A.func2, FunctionType)) # True print(isinstance(obj.func2, FunctionType)) # True2.函數與方法的區別
- 函數是顯性傳參,如我們要指明為len()函數傳遞一些要處理的參數 !
- 函數跟對象無關 !
- 方法中存在隱式傳參 !
- 方法可以操作類內部的數據
- 方法跟對象是關聯的.如我們在用strip()方法是,是不是都是要通過str對象調用,比如我們有字符串s,然后s.strip()這樣調用.是的,strip()方法屬于str對象
三.雙下方法
1.定義:
雙下方法是特殊方法,他是解釋器提供的,由雙下劃線加方法名加雙下劃線(方法名)組成具有特殊意義的方法,雙下方法主要是python源碼程序員使用的
2.調用:
不同的雙下方法有不同的觸發方式,就好比盜墓時觸發的機關一樣,不知不覺就觸發了雙下方法,例如:__init__
3.__init__
class A:def __init__(self, name):print('in __init__')self.name = name obj = A('小馬') # 實例化對象時自動運行,在__new__之后4.__len__
''' 學習中遇到問題沒人解答?小編創建了一個Python學習交流QQ群:725638078 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' # 一個對象可以使用len()函數,根本原因是這個對象從屬于的類中有__len__方法 class B:def __len__(self):print(666)return 10 # 必須要有一個int型的返回值b = B() len(b) # len()一個對象就會觸發__len__方法 # 666class A:def __init__(self):self.a = 1self.b = 2def __len__(self):return len(self.__dict__)a = A() print(len(a)) # 25.__hash__
class A:def __init__(self):self.a = 1self.b = 2def __hash__(self):return hash(str(self.a) + str(self.b)) a = A() print(hash(a)) # hash()一個對象就會觸發__hash__方法6.__str__
# 如果一個類中定義了__str__方法,那么在打印對象時,默認輸出該方法的返回值 class A:def __init__(self, name):self.name = namedef __str__(self):return self.name a = A('小馬') str(a) # str()一個對象就會觸發__str__方法 print(str(a)) print(a) # 打印對象時,默認輸出__str__方法的返回值 print(f'{a}') # 格式化輸出也會觸發__str__方法7.__repr__ 和__str__相似,但是優先級比__str__低
''' 學習中遇到問題沒人解答?小編創建了一個Python學習交流QQ群:725638078 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class A:def __init__(self):passdef __repr__(self):return '小馬' a = A() print(repr(a)) print(a) # 打印對象時,也可以調用__repr__方法 print(f'{a}') # 格式化輸出,也可以調用__repr__方法 print('%r' % a) # 指定調用__repr__方法8.__call__
# 對象后面加括號,觸發執行 # 注:構造方法__new__的執行是由創建對象觸發的,即:對象 = 類名(),而對于__call__方法的執行是由對象后加括號觸發的,即:對象(),或者類()() class Foo:def __init__(self):passdef __call__(self, *args, **kwargs):print('__call__') obj = Foo() # 執行 __init__ obj() # 執行 __call__9.__eq__
class A:def __init__(self):self.a = 1self.b = 2def __eq__(self,obj):if self.a == obj.a and self.b == obj.b:return True a = A() b = A() print(a == b) # 對一個類的兩個對象進行比較操作就會觸發__eq__方法10.__del__
析構方法,當對象在內存中被釋放時,自動觸發執行.
注:此方法一般無須定義,因為Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的.
11.__new__構造方法,創造并返回一個新對象
class A:def __init__(self):self.x = 1print('in init function')def __new__(cls, *args, **kwargs):print('in new function')return object.__new__(cls)# 調用object或者父類(最終調用object)的__new__來開辟對象空間a = A() # 類名加()先觸發__new__,并且將類名自動傳給cls print(a.x) ------------------------------------------------------- # 單例模式 # 一個類只能實例化一個對象,無論實例化多少次,內存中只有一個對象;這個類的對象不是個性化的,主要是實例化對象之后去執行類中的方法 class A:__instance = Nonedef __new__(cls, *args, **kwargs):if cls.__instance is None:obj = object.__new__(cls)cls.__instance = objreturn cls.__instancedef func(self):print(self.__instance) a = A() a.func() # <__main__.A object at 0x002F5F30>b = A() # b還是a對象 print(b is a) # True單例模式是一種常用的軟件設計模式.在它的核心結構中只包含一個被稱為單例類的特殊類.通過單例模式可以保證系統中一個類只有一個實例而且該實例易于外界訪問,從而方便對實例個數的控制并節約系統資源.如果希望在系統中某個類的對象只能存在一個,單例模式是最好的解決方案.
采用單例模式動機,原因: 對于系統中的某些類來說,只有一個實例很重要.例如,一個系統中可以存在多個打印任務,但是只能有一個正在工作的任務;一個系統只能有一個窗口管理器或文件系統;一個系統只能有一個計時工具或ID(序號)生成器.如在Windows中就只能打開一個任務管理器.如果不使用機制對窗口對象進行唯一化,將彈出多個窗口,如果這些窗口顯示的內容完全一致,則是重復對象.浪費內存資源;如果這些窗口顯示的內容不一致,則意味著在某一瞬間系統有多個狀態,與實際不符,也會給用戶帶來誤解,不知道哪一個才是真實的狀態.因此有時確保系統中某個對象的唯一性即一個類只能有一個實例非常重要.
如何保證一個類只有一個實例并且這個實例易于被訪問呢? 定義一個全局變量可以確保對象隨時都可以被訪問,但不能防止我們實例化多個對象.一個更好的解決辦法是讓類自身負責保存它的唯一實例.這個類可以保證沒有其他實例被創建,并且它可以提供一個訪問該實例的方法.這就是單例模式的模式動機.
單例模式優缺點
# 單例模式優缺點 # 優點 # 一,實例控制 # 單例模式會阻止其他對象實例化其自己的單例對象的副本,從而確保所有對象都訪問唯一實例. # 二,靈活性 # 因為類控制了實例化過程,所以類可以靈活更改實例化過程.# 缺點 # 一,開銷 # 雖然數量很少,但如果每次對象請求引用時都要檢查是否存在類的實例,將仍然需要一些開銷.可以通過使用靜態初始化解決此問題. # 二,可能的開發混淆 # 使用單例對象(尤其在類庫中定義的對象)時,開發人員必須記住自己不能使用new關鍵字實例化對象.因為可能無法訪問庫源代碼,因此應用程序開發人員可能會意外發現自己無法直接實例化此類. # 三,對象生存期 # 不能解決刪除單個對象的問題.12.__item__系列 對對象進行類似字典的操作
''' 學習中遇到問題沒人解答?小編創建了一個Python學習交流QQ群:725638078 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Foo:def __init__(self, name):self.name = namedef __getitem__(self, item):print(self.__dict__[item])print(666)def __setitem__(self, key, value):self.__dict__[key] = valuedef __delitem__(self, key):self.__dict__.pop(key)print('del obj[key]時,我執行')def __delattr__(self, item):print('del obj.key時,我執行')self.__dict__.pop(item) f1 = Foo('小馬') f1['age'] = 18 # 執行__setitem__方法 f1['sex'] = '男' print(f1['age']) # 執行__getitem__方法 del f1['age'] # 執行__delitem__方法 del f1.sex # 執行__delattr__方法 f1['name'] = '大馬' print(f1.__dict__)13.__enter__ ``__exit__ 上下文管理器相關
# 如果想要對一個類的對象進行with as 的操作 不行。 class A:def __init__(self, text):self.text = textwith A('大爺') as f1:print(f1.text) ------------------------------------------------------ # 解決上述問題 class A:def __init__(self, text):self.text = textdef __enter__(self): # 開啟上下文管理器(with語句)對象時觸發此方法self.text = self.text + '來啦'return self # 將實例化的對象返回f1def __exit__(self, exc_type, exc_val, exc_tb): # 執行完上下文管理器對象f1時觸發此方法self.text = self.text + '這就走啦' with A('小馬') as f1:print(f1.text) print(f1.text)------------------------------------------------------ # 用于文件管理 class Diycontextor:def __init__(self, name, mode):self.name = nameself.mode = modedef __enter__(self):print('in enter')self.filehander = open(self.name, self.mode)return self.filehanderdef __exit__(self, *para):print('in exit')self.filehander.close()with Diycontextor('module_test.py', 'r') as f:for i in f:print(i)結尾給大家推薦一個非常好的學習教程,希望對你學習Python有幫助!
Python基礎入門教程推薦
Python爬蟲案例教程推薦
總結
以上是生活随笔為你收集整理的Python面向对象中反射和双下的正确用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python字典的作用与基本操作
- 下一篇: Python中异常处理不要乱用哦