21 反射
21.1 反射概念
? ? 反射主要是指程式可以訪問、檢測和修改其本身狀態或行為的一種能力,在Python中最重要的4個方法如下所示:
- getattr:獲取指定字串名稱的物件屬性
- setattr:給物件添加類屬性
- hasattr:判斷物件是否存在某個對應的物件
- delattr:洗掉指定的屬性
? ? 我們先來定義一個類,如下所示:
class Fruit:
def __init__(self,name,color):
self.name=name
self.color=color
def __str__(self):
return f"Fruit is {self.name} color is {self.color}"
def buy(self,price,totalWeight):
return f"Fruit is {self.name},total price is {price*totalWeight}"
21.2 反射常用方法
21.2.1 getattr
? ? getattr主要用來獲取指定字串名稱的物件屬性,其使用方法如下所示:
getattr(object, name:string[, default]) -> value
- name引數需要為string型別,不管是判斷類屬性還是類方法,其名稱均以字串形式傳參
- 如果屬性存在,則回傳其屬性值,不存在則分為兩種情況,一種是沒有default引數時,則直接報錯,如給定了default引數,物件沒有其屬性,則回傳給定的default值
- 如果獲取的是類方法,則回傳函式物件
? ? 以前面定義的Fruit類為例
# 實體化一個類
apple=Fruit("apple","red")
# 利用反射獲取類屬性
print(getattr(apple,"name"))
print(getattr(apple,"color"))
# 利用反射獲取類方法
print(getattr(apple,"buy"))
# 利用反射獲取不存在的屬性且有默認值
print(getattr(apple,"test","123"))
# 利用反射獲取不存在的屬性且沒有默認值 - 報錯
print(getattr(apple,"test"))
輸出結果如下所示:
apple
red
<bound method Fruit.buy of <__main__.Fruit object at 0x000001E70B356288>>
123
Traceback (most recent call last):
File "C:/Users/Surpass/Documents/PycharmProjects/SADCI/TempCode/reflectorSample.py", line 24, in <module>
print(getattr(apple,"test"))
AttributeError: 'Fruit' object has no attribute 'test'
21.2.2 setattr
? ? setattr主要用于給物件添加一個類屬性,如果添加的屬性已經存在,則對其進行更新,否則則進行創建,其使用方法如下所示:
setattr(object, name:string, value)
name引數需要為string型別,不管是判斷類屬性還是類方法,其名稱均以字串形式傳參
? ? 示例如下所示:
# 實體化一個類
apple=Fruit("apple","red")
# 為實體添加一個類屬性,并設定其值
setattr(apple,"destination","china")
print(f'第一次添加類屬性,其值為(添加操作):{getattr(apple,"destination")}')
setattr(apple,"destination","USA")
print(f'第二次添加類屬性,其值為(更新操作):{getattr(apple,"destination")}')
輸出結果如下所示:
第一次添加類屬性,其值為(添加操作):china
第二次添加類屬性,其值為(更新操作):USA
21.2.3 hasattr
? ? hasattr常用于判斷物件中是否存在其屬性或方法,常用用法如下所示:
hasattr(object, name:string) -> bool
name引數需要為string型別,不管是判斷類屬性還是類方法,其名稱均以字串形式傳參
? ? 示例如下所示:
# 實體化一個類
apple=Fruit("apple","red")
# 判斷屬性或方法是否存在
print(f'物件是否存在其屬性 name - {True if hasattr(apple,"name") else False }')
print(f'物件是否存在其屬性 country - {True if hasattr(apple,"country") else False }')
print(f'物件是否存在其方法 buy - {True if hasattr(apple,"buy") else False }')
輸出結果如下所示:
物件是否存在其屬性 name - True
物件是否存在其屬性 country - False
物件是否存在其方法 buy - True
21.2.4 delattr
? ? delattr常用于洗掉指定的屬性,但不能用于方法,常用用法如下所示:
delattr(object, name:string)
name引數需要為string型別,不管是判斷類屬性還是類方法,其名稱均以字串形式傳參
? ? 示例如下所示:
# 實體化一個類
apple=Fruit("apple","red")
delattr(apple,"name")
# 判斷屬性或方法是否存在
print(f'物件是否存在其屬性 name - {True if hasattr(apple,"name") else False }')
print(f'物件是否存在其屬性 country - {True if hasattr(apple,"country") else False }')
print(f'物件是否存在其方法 buy - {True if hasattr(apple,"buy") else False }')
輸出結果如下所示:
物件是否存在其屬性 name - False
物件是否存在其屬性 country - False
物件是否存在其方法 buy - True
在日常使用,一般會進行判斷屬性是否存在,然后再呼叫獲取、添加和洗掉方法
21.3 示例
? ? 以下用一個簡單的示例來解釋,反射在實際的應用案例,現在有一個場景,就是根據傳入的不同的模塊名稱,呼叫不同的模塊所對應方法,代碼如下所示:
class ReflectSample:
def moduleA(self):
print("我是moduleA")
def moduleB(self):
print("我是moduleB")
def moduleC(self):
print("我是moduleC")
def moduleD(self):
print("我是moduleD")
- 方法一:
while True:
reflectSample=ReflectSample()
choice=input("請輸入模塊名稱")
if choice == "moduleA":
reflectSample.moduleA()
elif choice == "moduleB":
reflectSample.moduleB()
elif choice == "moduleC":
reflectSample.moduleC()
elif choice == "moduleD":
reflectSample.moduleD()
else:
print("輸入的模塊不存在")
測驗結果如下所示:
請輸入模塊名稱moduleA
我是moduleA
請輸入模塊名稱moduleD
我是moduleD
請輸入模塊名稱moduleF
輸入的模塊不存在
- 方法二:
while True:
reflectSample = ReflectSample()
choice = input("請輸入模塊名稱")
if hasattr(reflectSample,choice):
func=getattr(reflectSample,choice)
func()
else:
print("輸入的模塊不存在")
測驗結果如下所示:
請輸入模塊名稱moduleA
我是moduleA
請輸入模塊名稱moduleD
我是moduleD
請輸入模塊名稱moduleF
輸入的模塊不存在
兩種方法一對比,自然就覺得方法二更簡潔,也更容易維護,更不用擔心類中有很多個方法,
本文地址:https://www.cnblogs.com/surpassme/p/12902742.html
本文同步在微信訂閱號上發布,如各位小伙伴們喜歡我的文章,也可以關注我的微信訂閱號:woaitest,或掃描下面的二維碼添加關注:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/138095.html
標籤:Python
