反射說簡單點 --> 就是利用字元串的形式去對象(子產品)中操作(尋找/檢查/删除/設定)成員。
1.根據字元串的形式導入子產品。
2.根據字元串的形式去對象(某個子產品)中操作其成員
說反射之前先介紹一下__import__方法,這個和import導入子產品的另一種方式
1. import commons
2. __import__('commons')
如果是多層導入:
1. from list.text import commons
2. __import__(' list.text.commons',fromlist=True) #如果不加上fromlist=True,隻會導入list目錄
反射即想到4個内置函數分别為:getattr、hasattr、setattr、delattr 擷取成員、檢查成員、設定成員、删除成員下面逐一介紹先看例子:
class Foo():
def __init__(self):
self.name = 'abc'
def func(self):
return "OK"
obj = Foo()
# 擷取成員
ret = getattr(obj, 'func') # 擷取的是個對象
r = ret()
print(r)
# 檢查成員
ret = hasattr(obj, 'func') # 因為有func方法是以傳回True
print(ret)
# 設定成員
print(obj.name) # 設定之前為:abc
ret = setattr(obj, 'name', 19)
print(obj.name) # 設定之後為:19
# 删除成員
print(obj.name) # abc
delattr(obj, 'name')
#print(obj.name) # 報錯
OK
True
abc
19
web執行個體
考慮有這麼一個場景,根據使用者輸入的url的不同,調用不同的函數,實作不同的操作,也就是一個url路由器的功能,這在web架構裡是核心部件之一。下面有一個精簡版的示例:
首先,有一個test子產品,它裡面有幾個函數,分别用于展示不同的頁面,代碼如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Jack.Ming
def login():
print("這是一個登陸界面")
def logout():
print("這是一個退出界面")
def look():
print("這是一個浏覽界面")
其次,有一個web子產品,作為程式入口,接受使用者輸入,展示相應的頁面,代碼如下:(這段代碼是比較初級的寫法)
import test
def run():
inp = input("請輸入您想通路頁面的url: ").strip()
if inp == "login":
test.login()
elif inp == "logout":
test.logout()
elif inp == "home":
test.look()
else:
print("404")
if __name__ == '__main__':
run()
運作該程式:
請輸入您想通路頁面的url: login
這是一個登陸界面
這就實作了一個簡單的WEB路由功能,根據不同的url,執行不同的函數,獲得不同的頁面。
如果在text子產品有成千上萬了函數,那麼在web子產品中也需要有成千上萬個判斷語句,那這樣豈不是很麻煩,我們可以用反射的方式解決這種問題:
反射機制(動态導入)
仔細觀察web中的代碼,我們會發現使用者輸入的url字元串和相應調用的函數名好像!如果能用這個字元串直接調用函數就好了!但是,前面我們已經說了字元串是不能用來調用函數的。為了解決這個問題,我們可以使用getattr和hasattr這兩個内置函數,代碼如下:
# !/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Jack.Ming
def run():
url = input("請輸入URL位址:").strip()
modules, index = url.split("/")
obj = __import__(modules, fromlist=True)
if hasattr(obj, index):
func = getattr(obj, index)
func()
else:
print("404 頁面不存在")
if __name__ == '__main__':
run()
運作:
請輸入URL位址:test/login
這是一個登陸界面
分析一下以上代碼:
首先,我們并沒有定義任何一行import語句;
其次,使用者的輸入URL被要求為類似“commons/home”這種格式,其實也就是模拟web架構裡的url位址,斜杠左邊指向子產品名,右邊指向子產品中的成員名。
然後,modules,index = url.split("/")處理了使用者輸入,使我們獲得的2個字元串,并分别儲存在modules和index變量裡。
接下來,最關鍵的是obj = __import__(modules)這一行,它讓程式去導入了modules這個變量儲存的字元串同名的子產品,并将它指派給obj變量。
使用hasattr方法判斷在該子產品中是否有該方法。
最後的調用中,getattr去modules子產品中調用index成員的含義和以前是一樣的。
總結:通過__import__函數,我們實作了基于字元串的動态的子產品導入。
利用反射檢視面向對象成員歸屬
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/12/26 0026 15:18
# @Author : ming
# 以字元串的形式去對象中查找成員
class Foo:
def __init__(self, name):
self.Name = name
def show(self):
print("show")
# 反射:類,隻能查找類中的成員
r = hasattr(Foo, "Name")
print(r)
r = hasattr(Foo, "show")
print(r)
# 反射:對象,即可查找對象,也可以查找類的成員
obj = Foo("yang")
r = hasattr(obj, "Name")
print(r)
r = hasattr(obj, "show")
print(r)
運作結果:
False
True
True
True
利用反射導入子產品、查找類、建立對象、查找對象中的字段
内容如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2018/1/2 0002 14:34
# @Author : ming
# 導入子產品
m = __import__("s1", fromlist=True)
# 去子產品中找類
lei = getattr(m, "Foo")
# 擷取類對象
obj1 = lei("yang")
# 去類中找屬性值Name
obj2 = getattr(obj1,"Name")
# print
print(obj2)
yang
作者:楊永明
出處:https://www.cnblogs.com/ming5218/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接。