什麼是反射
反射主要是指程序可以訪問、檢測和修改它本身狀態或行爲的一種能力(自省)。
python面向對象中的反射就是通過字符串獲取對象或者類的屬性,進行操作~,主要是對這4個方法的應用:hasattr,getattr,setattr,delattr。
反射對象的屬性和方法
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def __fun(self):
print(self.__class__)
def say(self):
print(self.__name + ' ' + str(self.__age))
# 判斷屬性是否存在
p = Person('baby', 18)
print(hasattr(p, 'name')) # False
print(hasattr(p, '_Person__name')) # True
print(hasattr(p, 'say')) # True
# 獲取屬性
fun = getattr(p, 'say')
fun() # baby 18,執行反射獲取的方法
name = getattr(p, '_Person__name')
print(name) # baby
# 若是屬性不存在則報錯
# age = getattr(p, 'age') # 'Person' object has no attribute 'age'
# 設置屬性
setattr(p, 'sex', 'male') # 設置的是對象的屬性,存放在對象的名稱空間中
# 這裏設置的方法是普通方法,存放在對象的名稱空間中,self.__name不會變形爲 self._Person__name
# setattr(p, 'show_name', lambda self: self.__name)
setattr(p, 'say_hello', lambda self: 'Hello ' + self._Person__name)
print(p.__dict__)
# {'_Person__name': 'baby', '_Person__age': 18, 'sex': 'male', 'say_hello': <function <lambda> at 0x10f7bf2f0>}
print(p.say_hello(p)) # 不是綁定方法,需要手動傳值
# 刪除屬性
delattr(p, 'sex')
print(p.__dict__)
# {'_Person__name': 'baby', '_Person__age': 18, 'say_hello': <function <lambda> at 0x10f7bf2f0>}
# 若不存在該屬性則報錯
# delattr(p, 'name') # AttributeError: name
Tip:
- 通過對象設置的屬性,不管是變量還是方法,都存放在對象的名稱空間中;
- 通過對象設置的方法僅僅是普通方法,調用的時候也不會自動傳值(需要手動傳值),且方法中不能使用對象的私有屬性
反射類的屬性和方法
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
self.city = 'NB'
def __fun(self):
print(self.__class__)
def say(self):
print(self.__name + ' ' + str(self.__age))
@classmethod
def play(cls):
print(cls.__name__)
@staticmethod
def sleep():
print('sleep...')
# 判斷屬性是否存在
print(hasattr(Person, 'name')) # False
print(hasattr(Person, '_Person__name')) # False,私有屬性 __name,__age 屬於對象
print(hasattr(Person, 'say')) # True
# 獲取屬性
fun = getattr(Person, 'say')
p = Person('baby', 18)
fun(p) # baby 18,等同於Person.say(p),需要手動傳遞self
# 若是屬性不存在
# age = getattr(Person, 'age') # 報錯,'Person' object has no attribute 'age'
# 設置屬性
setattr(Person, 'sex', 'male') # 設置的是類的靜態屬性
setattr(Person, 'show_city', lambda self: self.city) # 這裏通過類設置的方法爲綁定到對象的方法,通過對象調用的時候能夠自動傳值(self)
print(p.show_city()) # NB
# setattr(Person, 'show_name', lambda self: self.__name) # self.__name 不會自動轉換爲 self._Person__name
# print(p.show_name()) # AttributeError: 'Person' object has no attribute '__name'
# 刪除屬性
delattr(Person, 'sex') # 刪除的是類的靜態屬性
# 獲取類方法
getattr(Person, 'play')() # 會完成自動傳值,默認將Person作爲第一個參數傳遞給play方法
# 獲取靜態方法
getattr(Person, 'sleep')()
Tip:
- 通過類設置的屬性,存放在類的名稱空間中;
- 通過類設置的方法爲綁定到對象的方法,通過對象調用的時候,能夠完成自動傳值;同樣方法內無法訪問到私有變量(self.__屬性 不會自動轉換爲self._類名__屬性)
反射當前模塊成員
import sys
def s1():
print('s1')
def s2():
print('s2')
this_module = sys.modules[__name__]
# 判斷模塊中是否存在 s1 方法
print(hasattr(this_module, 's1')) # True
# 獲取模塊中的方法並執行
getattr(this_module, 's2')() # s2
sys.modules[__name__] 也可以寫成 sys.modules['__main__'],但是不建議這麼寫,因爲當前的模塊被導入到另外一個模塊的時候,這個被導入的模塊使用 sys.modules['__main__'] 就獲取不到它的內存地址了~
操作的對象也可以是導入的模塊
# module_test
def test():
print('from test')
# test.py
import module_test
print(hasattr(module_test,'test')) # True
getattr(module_test, 'test')() # from test
isinstance 和 issubclass
isinstance 方法用來判斷 一個對象 和 一個類之間的關係,即這個對象是不是由這個類實例化而來
class Person:
pass
p = Person()
print(isinstance(p, Person)) # True
issubclass 用來判斷兩個類之間是否存在繼承關係
class Father:
pass
class Son(Father):
pass
print(issubclass(Son, Father)) # True
.................^_^