文章目錄
一、什麼是反射
反射是一個很重要的概念,它可以把字符串映射到實例的變量或者實例的方法然後可以去執行調用、修改等操作。
這一點在項目開發中尤爲重要,在不清楚方法或變量在對象中是否存在時,可以通過反射這個特殊的方法或機制來對對象中"未知的"變量或者方法進行操作。
核心是:通過字符串去操作對象的屬性和方法,是字符串形式!
二、反射的方法
1、內建函數
方法 | 意義 |
---|---|
getattr(object,name[,default]) | 通過name返回object的屬性值,當屬性不存在,返回default默認值,如果沒有default,則拋出異常,name必須是字符串 |
setattr(object,name,value) | 操作object的屬性,如有則覆蓋,不存在則新增 |
hasaattr(object,name) | 判斷對象是否有這個名字的屬性,name必須爲字符串,有返回True,不存在返回Felse |
delattr(object,name) | 當通過實例來刪除屬性時調用此方法 |
2、反射方法的查找路徑
查找路徑和繼承一致:參考 Python面對對象:繼承(詳解)
對象本身__dict__---->class的__.dict__---->繼承的祖先類(直到object)的__dict__
三、什麼對象可以用反射?
在python中只有:實例化對象、類、其他模塊(.py結尾的文件)、本模塊(.py結尾的文件
只有以上四個才能使用,因爲他們都能通過== .== 的方式獲取或調用,這也算是一種前提
attr是屬性英文的前幾個字母,屬性指的是類中類變量、實例變量和方法。但是要注意不能是私有的,如果你的變量是以“_”開頭,那將無法獲取。
四、代碼實例
1、實例化對象的反射實例
class People:
def __init__(self,name):
self.name = name
def info(self):
print("我的名字叫:%s" % self.name)
obj = People("金鞍少年")
# hasattr 判斷對象中是否存在 屬性
# =====================================================
print(hasattr(obj, "info")) # True。因爲存在info方法
print(hasattr(obj, "name")) # True。因爲存在name變量
print(hasattr(obj, "age")) # False。因爲不存在age方法或變量
# getattr 獲取對象中的屬性
# =====================================================
f1 = getattr(obj, 'info') # f1 = obj.info
f1() # 我的名字叫:金鞍少年
# 如果obj中不存在屬性,則會報錯,可以設置default,返回None、False、True
f2 = getattr(obj, 'xxx', None)
print(f2) # None
# setattr 爲對象設置屬性
# =====================================================
setattr(obj, 'age', 18) # 等同於 obj.age = 18
print(obj.__dict__) # {'name': '金鞍少年', 'age': 18}
# delattr 刪除對象屬性
# =====================================================
delattr(obj, 'age') # 等同於 del obj.age
print(obj.__dict__) # {'name': '金鞍少年'}
2、類的反射實例
'''
類的反射實例
'''
class Country:
city = '武漢'
Attractions = '黃鶴樓'
def func(self):
print('武漢有名景點---》黃鶴樓')
# 獲取類 Country 的靜態屬性
print(getattr(Country, 'city')) # 存在city方法 ,返回 :武漢
# 獲取類 Country 的方法
getattr(Country, "func")('Country') # 武漢有名景點---> 黃鶴樓 ,因爲類中方法需要穿一個參數,隨便傳了一個
# 其他操作和實例化對象操作一致
3、文件(模塊)間的反射實例
'''
我是 test.py 文件
'''
name = '我是test.py文件'
class Country:
city = '武漢'
def func(self):
print('武漢有名景點---》黃鶴樓')
#===========================================================================================
'''
我是執行文件
'''
import test
print(test.name) # 我是test.py文件
print(getattr(test.Country,'city')) # 存在city屬性 返回: 武漢
setattr(test.Country,'city','杭州') # 修改city的屬性
print(test.Country.__dict__)
# {'__module__': 'test', 'city': '杭州', 'func': <function Country.func at 0x000002B34EAAC160>, '__dict__': <attribute '__dict__' of 'Country' objects>, '__weakref__': <attribute '__weakref__' of 'Country' objects>, '__doc__': None}
五、練習
1、通過字符串導入模塊
temp = "re" # 要引入的模塊
func = "compile" # 要使用的方法
model = __import__(temp) # 導入模塊
function = getattr(model, func) # 找到模塊中的屬性
def main():
txt = "python 2020"
pattern = function(r"[0-9]+") # 這裏執行funcation()就等於執行re.compile()函數
print(model.search(pattern, txt).group())
if __name__ == '__main__':
main()
# 結果:2020
2、模擬FTP動態請求過程
class Ftp:
def get(self):
print('下載文件')
def put(self):
print('上傳文件')
def login(self):
print('登錄')
def run(self):
while True:
choice = input('>>>請輸入命令: ').strip()
if hasattr(self, choice):
method = getattr(self, choice)
method()
else:
print('命令不存在')
obj = Ftp()
obj.run()