最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Python的自省Introspection和反射機制Reflection

 更新時間:2023年08月21日 09:25:12   作者:天元浪子  
這篇文章主要介紹了淺談Python的自省Introspection和反射機制Reflection,反射就是通過字符串的形式去對象(模塊)中操作(查找/獲取/刪除/添加)成員,一種基于字符串的事件驅(qū)動,需要的朋友可以參考下

1. 從dir()函數(shù)說起

對于dir()這個Python的內(nèi)置函數(shù),Python進階群里的小伙伴們一定不陌生。

我不止一次地介紹過這個函數(shù)。

每當想要了解一個類或類實例包含了什么屬性和方法時,我都會求助于這個函數(shù)。

 a = [3,4,5]
 type(a) # 返回a的類型,結(jié)果是list類
<class 'list'>
 dir(a) # 返回list類實例對象a包含的屬性和方法
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
 dir(list) # 返回list類a包含的屬性和方法
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

對于模塊、內(nèi)置函數(shù),以及自定義的類,dir()一視同仁,照樣可用。

 import math
 dir(math) # 返回math模塊包含的子項(子模塊、類、函數(shù)、常量等)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
 dir(max) # 返回內(nèi)置函數(shù)的內(nèi)建子項
['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__text_signature__']

讀到這里,一定會有很多小伙伴會說,我的PyCharm(也可能是VSCode或者其他什么)也會告訴我,當前的對象有什么屬性和方法,還是自動顯示的,不需要我動手。

沒錯,IDE的確為我們提供了很多便利,但是,你有沒有想過IDE是如何實現(xiàn)這些功能的呢?

假如你的任務就是設計一款類似的IDE,你真的不要深入理解Python內(nèi)在的機制嗎?

2. 內(nèi)建屬性和方法

下面的代碼中,類Player定義了兩個屬性和一個方法,p是Player的一個實例。

調(diào)用dir()顯示實例p的屬性和方法,就會發(fā)現(xiàn),除了代碼中定義name,rating和say_hello()外,其他都是以雙下劃線開頭、以雙下劃線結(jié)尾,這些就是傳說中的Python對象的內(nèi)建屬性和方法。

 class Player:
		"""玩家類"""
		def __init__(self, name, rating=1800):
			self.name = name
			self.rating = rating
		def say_hello(self):
			"""自報姓名和等級分"""
			print('大家好!我是棋手%s,目前等級分%d分。'%(self.name, self.rating))
 p = Player('天元浪子')
> p.say_hello()
大家好!我是棋手天元浪子,目前等級分1800分。
 for item in dir(p):
		print(item)
__class__
__delattr__
__dict__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__gt__
__hash__
__init__
__init_subclass__
__le__
__lt__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
name
rating
say_hello

這些內(nèi)建屬性和方法中,似乎只有__init__和__new__看起來有點面熟,其他那些都有什么用途呢?

下面,我選其中的幾個演示一下。

2.1 _ doc _

__doc__是最常用的內(nèi)建屬性,有很多小伙伴并沒有意識到這一點。

一個規(guī)范的代碼文件,除了代碼本身,還會提供很多必要信息,比如類、函數(shù)的說明,這些說明,我們稱其為文檔字符串(DocString)。

__doc__就是對象的文檔字符串。

 Player.__doc__
'玩家類'
 p.__doc__
'玩家類'
 p.say_hello.__doc__
'自報姓名和等級分'

這里顯示的文檔字符串,就是我在定義Player時寫在特定位置的注釋(沒有注意到這一點的小伙伴,請返回查看前面的Player類定義代碼)。

2.2 _ module _

很容易猜到,內(nèi)建屬性__mudule__表示對象所屬的模塊。

這里,Player類及其實例,都是當前__main__模塊。

如我們引入一個模塊,更容易說明__module__的含義。

 Player.__module__
'__main__'
 p.__module__
'__main__'
 p.say_hello.__module__
'__main__'
 import math
 math.sin.__module__
'math'

2.3 _ dict _

內(nèi)建屬性__dict__,是一個由對象的屬性鍵值對構(gòu)成的字典。

類的__dict__和類實例的__dict__有不同的表現(xiàn)。

 p.__dict__
{'name': '天元浪子', 'rating': 1800}
 Player.__dict__
mappingproxy({'__module__': '__main__', '__doc__': '玩家類', '__init__': <function Player.__init__ at 0x000002578CF399D8>, 'say_hello': <function Player.say_hello at 0x000002578CF39A68>, '__dict__': <attribute '__dict__' of 'Player' objects>, '__weakref__': <attribute '__weakref__' of 'Player' objects>})

2.4 _ class _

通過類的實例化,可以得到一個類實例。那么如何從一個類實例,逆向得到類呢?實際上,類實例的內(nèi)建屬性__class__就是類。我們完全可以用一個實例的__class__去初始化另一個實例。

 pp = p.__class__('零下八段', 2100)
 pp.say_hello()
大家好!我是棋手零下八段,目前等級分2100分。

2.5 _ dir _

dir()函數(shù)是Python的內(nèi)置函數(shù),內(nèi)建方法__dir__類似于dir()函數(shù)。。

 p.__dir__()
['name', 'rating', '__module__', '__doc__', '__init__', 'say_hello', '__dict__', '__weakref__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']

2.6 _ getattribute _

顧名思義,__getattribute__返回對象的屬性——實際上是屬性或方法。

這是一個內(nèi)建方法,使用的時候其后必須有圓括號,參數(shù)是指定的屬性或方法的名字。

 p.__getattribute__('name')
'天元浪子'
 p.__getattribute__('rating')
1800
 p.__getattribute__('say_hello')
<bound method Player.say_hello of <__main__.Player object at 0x000002578CF2CA88>>
 p.__getattribute__('say_hello')()
大家好!我是棋手天元浪子,目前等級分1800分。

3. 動態(tài)加載及調(diào)用

學習任何一門編程語言的初級階段,我們幾乎都會遇到一個共同的問題:動態(tài)創(chuàng)建一個變量或?qū)ο蟆?/p>

在這里,“動態(tài)”只是強調(diào)變量或?qū)ο竺Q不是由程序員決定,而是由另外的參與方(比如交互程序中的操作者,C/S或B/S程序中的客戶端)決定。

也許不是一個準確的說法,但我想不出一個更好的詞匯來表述此種應用需求。

以Python為例:從鍵盤上讀入一個字符串,以該字符串為名創(chuàng)建一個整型對象,令其值等于3。

通常,這樣的問題我們使用exec()函數(shù)就可以解決。

為什么不是eval()函數(shù)呢?

eval()函數(shù)僅是計算一個字符串形式的表達式,無法完成賦值操作。

 var_name = input('請輸入整型對象名:')
請輸入整型對象名:x
 exec('%s=3'%var_name)
 x
3

理解了“動態(tài)”的概念,我們來看看如何動態(tài)加載模塊、如何動態(tài)調(diào)用對象等

3.1 動態(tài)加載模塊

按照Python編碼規(guī)范,腳本文件一般會在編碼格式聲明和文檔說明之后統(tǒng)一導入模塊。

有些情況下,代碼需要根據(jù)程序運行時的具體情況,臨時導入相應的模塊——通常,這種情況下,導入的模塊命是由一個字符串指定的。

下面的代碼給出了動態(tài)加載模塊的實例。

 os.getcwd() # 此時沒有導入os模塊,所以拋出異常
Traceback (most recent call last):
  File "<pyshell#158>", line 1, in <module>
    os.getcwd()
NameError: name 'os' is not defined
 os = __import__('os') # 動態(tài)導入'os'模塊
 os.getcwd()
'C:\\Users\\xufive\\AppData\\Local\\Programs\\Python\\Python37'

3.2 通過對象名取得對象

這個需求聽起來有點奇怪,但也有很多人會遇到。Player類實例p為例,如果我們只有字符串’p’,怎樣才能得到p實例呢?我們知道內(nèi)置函數(shù)globals()返回全局的對象字典,locals()返回所處層次的對象字典,這兩個字典的鍵就是對象名的字符串。有了這個思路,就很容易通過對象名取得對象了。

 obj = globals().get('p', None)
 obj
<__main__.Player object at 0x000002578CF2CA88>
 obj.say_hello()
大家好!我是棋手天元浪子,目前等級分1800分。

3.3 動態(tài)調(diào)用對象

動態(tài)調(diào)用對象最典型的應用是服務接口的實現(xiàn)。假如客戶端通過發(fā)送服務的名字字符串來調(diào)用服務端的一個服務,名字字符串和服務有者一一對應的關系。如果沒有動態(tài)調(diào)用,代碼恐怕就得寫成下面這個樣子。

if cmd == 'service_1':
	serv.service_1()
elif cmd == 'service_2':
	serv.service_2()
elif cmd == 'service_3':
	serv.service_3()
... ...

下面的代碼,演示了服務端如何根據(jù)接收到的命令動態(tài)調(diào)用對應的服務。

 class ServiceDemo:
	def service_1(self):
		print('Run service_1...')
	def service_2(self):
		print('Run service_2...')
	def onconnect(self, cmd):
		if hasattr(self, cmd):
			getattr(self, cmd)()
		else:
			print('命令錯誤')
 serv = ServiceDemo()
 serv.onconnect('service_1')
Run service_1...
 serv.onconnect('service_2')
Run service_2...
 serv.onconnect('hello')
命令錯誤

4. 自省和反射機制

是時候說說自省和反射了。但是,截止到這里,我已經(jīng)把自省和反射全部講完了,只是沒有使用自省和反射這兩個詞罷了。僅從這一點,就可以說明,自省和反射是完全多余的概念。如果有小伙伴搞不清楚這兩個概念,那也完全沒有關系,一點兒都不會影響你對編程的理解。

所謂的自省,就是對象自身提供可以查看自身屬性、方法、類型的手段。內(nèi)建方法__dir__不正是對象的自省嗎?另外,內(nèi)置函數(shù)dir()、type()、isinstance()都可以提供類似自省的部分或全部功能。

反射機制是Java和PHP等語言提供的一個特性,準確描述起來有些費勁,簡而言之,就是在運行態(tài)可以獲取對象的屬性和方法,并隨時調(diào)用他們,最典型的應用就是通過字符串形式的對象名獲取對象。這不就是我說的“動態(tài)加載和調(diào)用”嗎?

寫道這里,不由地再次致敬龜叔當年的遠見卓識:早在Java誕生前好多年,龜叔就已經(jīng)全面地規(guī)劃了Python對象的內(nèi)建機制,其前瞻性遠遠超過了自省和反射機制。

到此這篇關于淺談Python的自省Introspection和反射機制Reflection的文章就介紹到這了,更多相關Python的自省和反射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Python threading模塊condition原理及運行流程詳解

    Python threading模塊condition原理及運行流程詳解

    這篇文章主要介紹了Python threading模塊condition原理及運行流程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-10-10
  • python之Flask實現(xiàn)簡單登錄功能的示例代碼

    python之Flask實現(xiàn)簡單登錄功能的示例代碼

    這篇文章主要介紹了python之Flask實現(xiàn)簡單登錄功能的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-12-12
  • python中decimal模塊的具體使用

    python中decimal模塊的具體使用

    本文主要介紹了python中decimal模塊的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • Python基于plotly模塊實現(xiàn)的畫圖操作示例

    Python基于plotly模塊實現(xiàn)的畫圖操作示例

    這篇文章主要介紹了Python基于plotly模塊實現(xiàn)的畫圖操作,涉及Python基于plotly模塊的數(shù)值運算與圖形操作相關實現(xiàn)技巧,需要的朋友可以參考下
    2019-01-01
  • python實現(xiàn)套接字創(chuàng)建

    python實現(xiàn)套接字創(chuàng)建

    這篇文章主要為大家介紹了python套接字創(chuàng)建實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • django配置使用asgi的實現(xiàn)步驟

    django配置使用asgi的實現(xiàn)步驟

    本文主要介紹了django配置使用asgi的實現(xiàn)步驟,支持 ASGI 協(xié)議能處理傳統(tǒng)HTTP請求,也能支持實時WebSocket通信,具有一定的參考價值,感興趣的可以了解一下
    2025-03-03
  • PyQt5打開文件對話框QFileDialog實例代碼

    PyQt5打開文件對話框QFileDialog實例代碼

    這篇文章主要介紹了PyQt5打開文件對話框QFileDialog實例代碼,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • Python使用multiprocessing模塊實現(xiàn)多進程并發(fā)處理大數(shù)據(jù)量的示例代碼

    Python使用multiprocessing模塊實現(xiàn)多進程并發(fā)處理大數(shù)據(jù)量的示例代碼

    這篇文章主要介紹了Python使用multiprocessing模塊實現(xiàn)多進程并發(fā)處理大數(shù)據(jù)量的示例代碼,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-01-01
  • 教你用Python實現(xiàn)一個輪盤抽獎小游戲

    教你用Python實現(xiàn)一個輪盤抽獎小游戲

    Python提供了許多個圖像開發(fā)界面的庫,比如現(xiàn)在主流的Tkinter,wxPython,pyqt5等,三種各有優(yōu)點,也各有缺點,下面對其分別進行介紹和對比,并編寫代碼實現(xiàn)一個輪盤轉(zhuǎn)盤抽獎小游戲.需要的朋友可以參考下
    2021-05-05
  • Python中常用文本數(shù)據(jù)格式轉(zhuǎn)換

    Python中常用文本數(shù)據(jù)格式轉(zhuǎn)換

    這篇文章主要為大家整理了一下Python中一些常用文本數(shù)據(jù)格式轉(zhuǎn)換,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的小伙伴可以參考一下
    2025-02-02

最新評論

南宁市| 志丹县| 中牟县| 崇信县| 永德县| 陇南市| 清涧县| 富川| 额尔古纳市| 灵川县| 济阳县| 丰台区| 鄂伦春自治旗| 社会| 尚志市| 游戏| 宁南县| 集安市| 遵化市| 东阿县| 五大连池市| 伊川县| 崇左市| 云林县| 龙胜| 海阳市| 同德县| 正镶白旗| 揭阳市| 德令哈市| 抚顺县| 沙洋县| 林西县| 阳曲县| 高阳县| 时尚| 八宿县| 乌什县| 马龙县| 怀集县| 黎川县|