反射与二次加工标准类型
| 反射與二次加工標準類型 |
一、反射
反射主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力。
有四個可以實現自省(反射)的函數,如下表所示:
| 函數名 | 含義 |
| hasattr(object,name) | 判斷object中有沒有一個name字符串對應的方法或屬性 |
| getattr(object,name, default=None) | 檢查obj.__dict__中有沒有name這個鍵值,有則不做任何處理,沒有則報錯 |
| setattr(object,name,value) | 等價于object.name=value |
| delattr(object,name) | 等價于del object.name |
各個函數具體代碼實現:
class BlackMedium:feture = 'Ugly'def __init__(self,name,addr):self.name = nameself.addr = addrdef sell_hourse(self):print('%s正在賣房子' %self.name)def rent_hourse(self):print('%s正在租房子' %self.name)print(hasattr(BlackMedium,'feture')) #結果為:True b1 = BlackMedium('alex','廈門') print(hasattr(b1,'name')) #結果為:True print(hasattr(b1,'sell_hourse')) #結果為:Trueprint(getattr(b1,'name')) #結果為:alex g = getattr(b1,'sell_hourse') g() #結果為:alex正在賣房子 print(getattr(b1,'sell_hoursesafgsgr','沒有這個屬性')) #結果為:沒有這個屬性 setattr(b1,'phone',18264894546) print(b1.__dict__) #結果為:{'name': 'alex', 'addr': '廈門', 'phone': 18264894546} setattr(b1,'func',lambda x:x+1) print(b1.__dict__) #結果為:{'name': 'alex', 'addr': '廈門', 'phone': 18264894546, 'func': <function <lambda> at 0x000000000041C1E0>} delattr(b1,'func') print(b1.__dict__) #結果為:{'name': 'alex', 'addr': '廈門', 'phone': 18264894546}上述代碼介紹了實現自省(反射)的函數。
反射的兩個好處:
第一的好處:實現可插拔機制
假設程序員a與程序員b負責同一個項目,程序員a負責實現功能,而程序員b負責執行功能,那么程序員b在執行功能時發現程序員a的實現功能還未寫入,這樣就會出錯,該如何解決這一問題?我們可以使用上面所學的反射來解決,具體代碼如下:
#程序員a寫的實現功能,寫在ftp_client.py文件 class FtpClient:def __init__(self,addr):print('正在連接服務器%s' %addr)self.addr = addr# def put(self): #假設這方法還沒寫,被程序員b調用# print('正在上傳文件') #程序員b寫的執行功能,寫在ftp_bin.py文件 from ftp_client import FtpClientf1 = FtpClient('1.1.1.1') #f1.put() ftp_client文件還沒有寫這功能會報錯,可以利用反射方式判斷,如下所示if hasattr(f1,'put'):func_get = getattr(f1,'put')func_get() else:print('不存在此方法,處理其它的邏輯')上述代碼利用反射方式判斷,相當于事先定義接口,接口只有在被完成后才會真正執行,這實現了即插即用。
第二個好處:動態導入模塊(基于反射當前模塊成員)
假如你需要導入m1.py模塊,即:
import m1 __import__('m1.tttt') #這是解釋器自己內部用的,它導入的就是m1模塊 importlib.import_module('m1.tttt') #與上面這句效果一樣我們來了解類內置attr函數,分別是__setattr__、__getattr__、__delattr__。
__getattr__只有在使用點調用屬性且屬性不存在時候才會執行,具體如何實現請看下面代碼:
class Foo:x = 1def __init__(self,y):self.y = ydef __getattr__(self, item):print('執行__getattr__') #調用一個對象不存在時候才會執行 f1 = Foo(10) print(f1.y) #結果為:10 print(getattr(f1,'y')) #結果為:10 f1.svdgsg #結果為:執行__getattr____delattr__刪除屬性的時候才會執行,該屬性不存在也會執行,具體實現如下代碼所示:
class Foo:x = 1def __init__(self,y):self.y = ydef __delattr__(self, item):print('刪除操作__delattr__')self.__dict__.pop(item) #內置的 f1 = Foo(10) del f1.y #結果為:刪除操作__delattr__ del f1.x #結果為:刪除操作__delattr__,報錯__setattr__在類被實例化、以及添加或修改屬性的才會執行,代碼如下:
class Foo:x = 1def __init__(self,y):self.y = ydef __setattr__(self,key,value):print('執行__setattr__')self.__dict__[key] = value #內置的 f1 = Foo(10) #結果為:執行__setattr__ print(f1.__dict__) #結果為:{'y': 10} f1.z = 2 #結果為:執行__setattr__ print(f1.__dict__) #結果為:{'y': 10, 'z': 2}二、二次加工標準類型
1.包裝
Python為大家提供了標準數據類型,以及豐富的內置方法,其實在很多場景下我們都需要基于標準數據類型來定制我們自己的數據類型,新增/改寫方法,這就用到了我們剛學的繼承/派生知識。
假設利用list方法只能添加到字符串類型,具體代碼如下:
class List(list):def append(self, item):if type(item) is str:super().append(item) else:print('只能添加字符串類型')l1 = List('hello') l1.append('alex') print(l1) #結果為:['h', 'e', 'l', 'l', 'o', 'alex'] l1.append(1646) #結果為:只能添加字符串類型 print(l1) #結果為:['h', 'e', 'l', 'l', 'o', 'alex']上述代碼在講述包裝一個類型通常是對已存在的類型的一些定制,這種做法可以新建、修改或刪除原有產品的功能,其它的則保持原樣。
2.授權
授權是包裝的一個特性,授權的過程即是所有更新的功能都是由新類的某部分來處理,但已存在的功能就授權給對象的默認屬性。
假設我們想要修改文件的寫操作,具體代碼如下:
import datetime class Open:def __init__(self,filename,mode='r',encoding='utf-8'):#self.filename = filenameself.file = open(filename,mode,encoding=encoding)self.mode = modeself.encoding = encodingdef write(self,line): #將寫操作加上當前時間t = datetime.datetime.now()self.file.write('%s %s' %(t,line))def __getattr__(self,item):return getattr(self.file,item)f1 = Open('a.txt','w+') f1.write('1111111\n') #執行類的write方法 f1.write('ssssss\n') f1.write('hhhhh\n') f1.seek(0) print(f1.read()) #先在初始函數找,然后在類找,最后找到__getattr__方法,觸發__getattr__實現授權的關鍵點就是類中的__getattr__函數。
轉載于:https://www.cnblogs.com/lzc69/p/11264038.html
總結
以上是生活随笔為你收集整理的反射与二次加工标准类型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS 定位 四种定位
- 下一篇: 一个切图仔的 CSS 笔记