日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Python反射機制實例講解

瀏覽:20日期:2022-08-06 17:20:35
目錄1. 反射的四個函數2. 類的反射操作3. 當前模塊的反射操作4. 其他模塊反射操作5. 反射應用場景之一6. 反射應用場景之二7. 總結

通常,我們操作對象的屬性或者方法時,是通過點“.”操作符進行的。例如下面的代碼:

class Person: type = 'mammal' def __init__(self, name):self.name = name def say_hi(self):print(’Hello, my name is’, self.name) @staticmethod def feed():print('Three times per day.') @classmethod def sleep(cls):print('8 hours!')p = Person(’Chunming’)p.say_hi()print(p.name)

上面代碼的輸出是

Hello, my name is NikhilNikhil

反射是另外一種操作對象屬性和方法的手段,例如:

func = getattr(p, ’say_hi’) func()print(getattr(p, 'name'))

上面這段代碼的輸出是:

Hello, my name is NikhilNikhil

可見與通過點操作符的結果一致。

1. 反射的四個函數

getattr是獲取對象屬性或方法的函數,Python的官方文檔是這樣描述其用法的:

getattr(object, name, value)

返回對象命名屬性的值。name必須是字符串。如果該字符串是對象的屬性之一,則返回該屬性的值。例如, getattr(x, ‘foobar’)等同于 x.foobar。如果指定的屬性不存在,且提供了 default值,則返回它,否則觸發 AttributeError。

根據文檔理解上述代碼,getattr(p, ‘say_hi’) 獲取了p對象的say_hi屬性值并賦值給func變量,因為say_hi屬性在Person類中是一個方法,要想調用這個方法, 需要執行func(),getattr(p, “name”) 則是獲取p對象的name屬性。

除了獲取對象屬性和方法的getattr函數,python還內置了判斷、設置、刪除對象屬性和方法的函數,來看看Python官方文檔對這三個函數的說明:

setattr(object, name, value)

此函數與 getattr() 兩相對應。其參數為一個對象、一個字符串和一個任意值。字符串指定一個現有屬性或者新增屬性。函數會將值賦給該屬性,只要對象允許這種操作。例如,setattr(x, ‘foobar’, 123) 等價于 x.foobar = 123。

hasattr(object, name)

該實參是一個對象和一個字符串。如果字符串是對象的屬性之一的名稱,則返回 True,否則返回 False。(此功能是通過調用 getattr(object, name) 看是否有 AttributeError 異常來實現的。)

delattr(object, name)

setattr() 相關的函數。實參是一個對象和一個字符串。該字符串必須是對象的某個屬性。如果對象允許,該函數將刪除指定的屬性。例如 delattr(x, ‘foobar’) 等價于 del x.foobar 。

Python中通過getattr、setattr、hasattr和delattr四個函數操作屬性的機制就是反射。是通過字符串的形式操作對象屬性和方法的機制。下面對p屬性應用setattr、hasattr和delattr這三個函數看看效果:

判斷p對象是否有say_bye屬性和say_hi屬性:

print(hasattr(p, ’say_bye’)) # 輸出Falseprint(hasattr(p, ’say_hi’)) # 輸出True

給p對象增加say_bye的方法和age屬性:

setattr(p, ’say_bye’, say_bye)setattr(p, ’age’, 18)

現在可以訪問這兩個屬性了,通過反射訪問:

bye = getattr(p, ’say_bye’)bye()print(getattr(p, ’age’))

或者通過點操作符訪問:

p.say_bye()print(p.age)

刪除age屬性:

delattr(p, ’age’)print(hasattr(p, ’age’)) # 輸出False2. 類的反射操作

除了對象的反射操作,還有類的反射操作,當前模塊的反射操作,還有其他模塊的反射操作,其他包的反射操作。

類的反射操作,指的是對類屬性、類方法或者靜態方法執行反射操作。

獲取類屬性:

t = getattr(Person, ’type’)print(t) # 輸出mammalf = getattr(Person, ’feed’)f() # 輸出Three times per day.s = getattr(Person, ’sleep’)s() # 8 hours!

判斷類屬性是否存在:

print(hasattr(Person, ’type’)) # 輸出Trueprint(hasattr(Person, ’name’)) # 輸出Falseprint(hasattr(Person, ’say_hi’)) # 輸出Trueprint(hasattr(Person, ’sleep’)) # 輸出Trueprint(hasattr(Person, ’feed’)) # 輸出True

此外,還可以對類添加和刪除屬性和方法。

print(delattr(Person, ’feed’))print(hasattr(Person, ’feed’))setattr(Person, ’feed’, lambda x: print('Three times per day.'))print(hasattr(Person, ’feed’))3. 當前模塊的反射操作

當前模塊也就是當前代碼所在的py文件,反射也可以對當前模塊中的變量和函數進行操作。例如某個模塊包含一個al函數,用來判斷迭代對象中每個元素是否都是True,內容如下:

import sysdef al(iterable): for element in iterable:if not element: return False return Truethis_module = sys.modules[__name__]if hasattr(this_module, ’al’): all_true = getattr(this_module, ’al’) result = all_true([1, 2, 3, 4, True, 0]) print(result)

通過sys.modules[name]方法獲取當前模塊的名稱。getattr第一個參數是模塊名稱,第二個參數是想要從模塊中獲取的屬性。

4. 其他模塊反射操作

對import進來的其他模塊中的函數、屬性、變量進行反射操作。例如,我們導入Python的heapq模塊,這塊模塊提供了堆隊列算法的實現,也稱為優先隊列算法。下面的代碼是一個實現堆排序的函數。

import heapqh = [(5, ’write code’), (7, ’release product’), (1, ’write spec’), (3, ’create tests’)]if hasattr(heapq, ’heapify’): heapi = getattr(heapq, ’heapify’) # 獲取heapify屬性 heapi(h) # 建堆 if hasattr(heapq, ’heappop’): heapp = getattr(heapq, ’heappop’) # 獲取heappop屬性 print([heapp(h) for _ in range(len(h))]) # 彈出并從返回堆中最小的項

這里,我們并沒有通過heapq.heapify和heapq.heappop方式調用heapq模塊中的函數。而是通過反射達到的同樣的效果。

5. 反射應用場景之一

了解了反射中四個函數的基本用法。那么反射到底有什么用呢?它的應用場景是什么呢?答案是,當不確定所需要的屬性和函數是否存在時,可以使用反射。另外一個重要作用是,可以提高代碼的擴展性和可維護性。

假如我們把所有的加密算法都放到一個叫做encryption的模塊中維護 ,并且允許使用這個模塊的用戶添加更多的加密算法到這個模塊中。encryption的模塊內容如下:

import hashlibimport osimport sysdef md5(content=None): '''生成字符串的SHA256值''' if content is None:return ’’ md5_gen = hashlib.md5() md5_gen.update(content.encode(’utf-8’)) md5code = md5_gen.hexdigest() return md5codedef sha256(content=None): '''生成字符串的SHA256值''' if content is None:return ’’ sha256_gen = hashlib.sha256() sha256_gen.update(content.encode(’utf-8’)) sha256code = sha256_gen.hexdigest() return sha256codedef sha256_file(filename): '''生成文件的SHA256值''' if not os.path.isfile(filename):return '' sha256gen = hashlib.sha256() size = os.path.getsize(filename) # 獲取文件大小,單位是Byte with open(filename, ’rb’) as fd: # 以二進制方式讀取文件while size >= 1024 * 1024: # 當文件大于1MB時分塊讀取文件內容 sha256gen.update(fd.read(1024 * 1024)) size -= 1024 * 1024sha256gen.update(fd.read()) sha256code = sha256gen.hexdigest() return sha256codedef md5_file(filename): '''生成文件的MD5值''' if not os.path.isfile(filename):return '' md5gen = hashlib.md5() size = os.path.getsize(filename) # 獲取文件大小,單位是Byte with open(filename, ’rb’) as fd:while size >= 1024 * 1024: # 當文件大于1MB時分塊讀取文件內容 md5gen.update(fd.read(1024 * 1024)) size -= 1024 * 1024md5gen.update(fd.read()) md5code = md5gen.hexdigest() return md5codedef encrypt_something(something, algorithm): ''' 通用加密算法 :param something: 待加密的內容,字符串或者文件 :param algorithm: 加密算法 :return: 加密后的內容 ''' result = '' if algorithm == 'md5':result = md5(something) elif algorithm == 'sh256':result = sha256(something) elif algorithm == 'sh256_file':result = sha256_file(something) elif algorithm == 'md5_file':result = md5_file(something) return result

其中,encrypt_something函數提供了通用加密算法,需要調用者傳入待加密的內容和加密算法,這樣當調用者使用encryption.py模塊時,只需導入encrypt_something函數即可。就像這樣:

import encryptionprint(encryption.encrypt_something('learn_python_by_coding', 'sh256'))print(encryption.encrypt_something('learn_python_by_coding', 'md5'))

通過分析encrypt_something函數發現,當我們在encryption.py模塊添加更多的加密算法后,就要修改encrypt_something函數,在其中增加新的if分支,隨著加密算法的增加,encrypt_something函數的分支會越來越多。

學了反射之后,encrypt_something代碼部分就可以這樣寫:

def encrypt_something(something, algorithm): ''' 通用加密算法 :param something: 待加密的內容,字符串或者文件 :param algorithm: 加密算法 :return: 加密后的內容 ''' this_module = sys.modules[__name__] if hasattr(this_module, algorithm):algorithm = getattr(this_module, algorithm)result = algorithm(something) else:raise ValueError('Not support {} algorithm'.format(algorithm)) return result

相比前面的采用if分支語句方式,反射更加簡潔明了,可維護性更強,要想增加新的加密方法,只需要在encryption.py模塊添加更多的加密算法即可,encrypt_something代碼不需要任何變更。

6. 反射應用場景之二

再看一個基于Pytest測試框架的測試腳本中應用反射的例子,比如conftest文件內容如下:

# content of conftest.pyimport pytestimport smtplib@pytest.fixture(scope='module')def smtp_connection(request): server = getattr(request.module, 'smtpserver', 'smtp.gmail.com') smtp_connection = smtplib.SMTP(server, 587, timeout=5) yield smtp_connection print('finalizing {} ({})'.format(smtp_connection, server)) smtp_connection.close()

request.module 是所有測試腳本,就是那些以_test結尾或者test_開頭的py文件。

server = getattr(request.module, 'smtpserver', 'smtp.gmail.com')

含義就是從測試腳本文件中找smtpserver屬性,如果找不到,默認使用smtp.gmail.com作為smtpserver的值。如果測試腳本文件有這個屬性,則使用測試腳本中的值,例如下面這個測試腳本,smtpserver則會使用mail.python.org這個值:

# content of test_anothersmtp.pysmtpserver = 'mail.python.org' # will be read by smtp fixturedef test_showhelo(smtp_connection): assert 0, smtp_connection.helo()7. 總結

在很多開源框架中普遍采用,是提高可維護性和擴展性的利器。如果工作中也涉及到框架開發,反射一定會助一臂之力,,希望大家以后多多支持好吧啦網!

標簽: Python 編程
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
97精品国产99久久久久久免费| 亚州av日韩av| 国产精品啊v在线| 国产黄色一区| 高清av一区| 国精品一区二区| 999精品一区| 欧美日韩在线观看视频小说| 亚洲深夜av| 日韩欧美在线精品| 久久99精品久久久久久园产越南| 精品美女在线视频| 欧美日韩国产高清电影| 一本综合精品| 久久99精品久久久久久园产越南 | 日韩伦理一区| 国产一区日韩欧美| 蜜桃久久av一区| 国产精品白浆| 欧美日韩一二三四| 亚洲精品一区二区在线播放∴| 国产精品香蕉| 亚洲国产综合在线看不卡| 免费精品视频在线| 精品精品国产三级a∨在线| 激情五月综合网| 久久精品av麻豆的观看方式| 成人精品视频| 免费人成黄页网站在线一区二区| 国产精品一区二区三区美女| 亚洲高清不卡| 国产日韩视频在线| 香蕉精品久久| 久久字幕精品一区| 亚洲自拍另类| 欧美www视频在线观看| 性一交一乱一区二区洋洋av| 国产福利一区二区三区在线播放| 国产在线欧美| 久久这里只有| 免费观看在线综合色| 久久久久伊人| 亚洲一区网站| 福利在线一区| 日韩精品一区二区三区中文在线| 国产精品专区免费| 日韩高清一级| 日韩精品一区二区三区免费观影| 日韩美女精品| 亚洲激情精品| av高清不卡| 欧美国产日本| 五月国产精品| 日韩一级不卡| 欧美sss在线视频| 欧美日韩亚洲一区| 欧美在线综合| 日韩另类视频| 成人午夜毛片| 国产精品成人一区二区网站软件| 性一交一乱一区二区洋洋av| 日韩一区亚洲二区| 久久国内精品| 日韩精品一级二级 | 精品欧美视频| 欧美日本三区| 伊人www22综合色| 亚洲夜间福利| 国产综合色区在线观看| 久久精品色播| 久久国产欧美日韩精品| 亚洲精品在线a| 蜜臀久久99精品久久久久宅男| 欧美日韩水蜜桃| 日韩久久一区二区三区| 久久精品一区二区三区中文字幕| 亚洲欧洲美洲国产香蕉| 狠狠爱成人网| 午夜视频精品| 午夜欧美理论片| 亚洲国产不卡| 亚洲黄色在线| 美女国产一区| 蜜桃久久久久久| 男人天堂欧美日韩| 久久高清国产| 视频一区国产视频| 亚洲欧美日本日韩| 美女黄网久久| 日韩精品一区二区三区中文| 免费看精品久久片| 免费看黄色91| 亚洲v天堂v手机在线| 亚洲人www| 日韩有吗在线观看| 午夜亚洲福利| 国产欧美一区二区三区国产幕精品 | 激情欧美丁香| 亚洲女同中文字幕| 日韩视频不卡| 免费美女久久99| 天堂va在线高清一区| 亚洲tv在线| 日韩精品福利一区二区三区| 欧美日韩一区二区三区在线电影| 欧美亚洲一级| 麻豆精品在线| 亚洲国产福利| 欧美1级日本1级| 免费在线成人网| 欧美片网站免费| 国产一区调教| 99视频精品视频高清免费| 蜜桃视频欧美| 欧美在线综合| 久久精品xxxxx| 国产一区二区视频在线看| 日韩欧美午夜| 黄色成人在线网址| 亚洲毛片在线| 欧美黑人做爰爽爽爽| 精品美女在线视频| 伊人久久大香线蕉av不卡| 日韩中文字幕不卡| 国产精品一级| 香蕉成人av| 蜜桃一区二区三区在线| 清纯唯美亚洲综合一区| 国产一区二区色噜噜| 91精品二区| 欧美日本久久| 久久久国产精品一区二区中文| 国产午夜精品一区二区三区欧美| 综合日韩在线| 国产一区二区三区成人欧美日韩在线观看| 成人啊v在线| 天海翼亚洲一区二区三区| 国产精品99视频| 蜜桃视频一区二区| 精品国产精品国产偷麻豆| 国产二区精品| 国产色99精品9i| 激情综合亚洲| 国产精品99久久久久久董美香| 韩国精品主播一区二区在线观看| 蜜臀av性久久久久蜜臀aⅴ流畅 | 国产一区调教| 天堂av在线一区| 麻豆一区二区99久久久久| 国产精品7m凸凹视频分类| 欧美一区二区三区免费看| 99视频精品全国免费| 国产日韩免费| 国产亚洲亚洲| 四虎成人av| 91成人在线网站| 狠狠爱www人成狠狠爱综合网| 国产精品自拍区| 亚洲欧洲一区| 中国字幕a在线看韩国电影| 六月婷婷一区| 伊伊综合在线| 国产麻豆一区| 在线观看一区| 国产99精品一区| 久久一区亚洲| 日韩三级视频| 亚洲中字黄色| 久久久国产亚洲精品| 91福利精品在线观看| 在线亚洲观看| 久久久久蜜桃| 色乱码一区二区三区网站| 国产亚洲一区| 亚洲美女久久| 亚洲视频综合| av资源中文在线| 国产精品免费精品自在线观看| 伊人精品在线| 久久影院一区| 麻豆成人综合网| 日本a级不卡| 亚洲精品无吗| 在线日韩成人| 亚洲一区二区三区免费在线观看| 日韩在线观看一区| 久久这里只有| 国产欧美一区| 日本aⅴ精品一区二区三区| 免费看精品久久片| 蜜桃国内精品久久久久软件9| 日韩不卡一区| 国产伊人久久| 精品国产精品国产偷麻豆| 欧美亚洲国产日韩| 日韩毛片网站| 日本在线一区二区三区| 亚洲精品护士| 一区二区日韩免费看| 亚洲午夜久久|