Python物件導向之九:反射

晴朗_不積跬步無以至千里發表於2020-12-06

Python物件導向之九:反射

反射的概念是由Smith在1982年首次提出的,主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了電腦科學領域關於應用反射性的研究。它首先被程式語言的設計領域所採用,並在Lisp和麵向物件方面取得了成績。

一、什麼是反射

python物件導向中的反射:通過字串的形式操作物件相關的屬性。

python中的一切事物都是物件(都可以使用反射)。

二、物件的反射

1、getattr 獲取指定字串名稱的物件屬性

class Foo:
    f = '類的靜態變數'
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_hi(self):
        print(f'hi,{self.name}')

obj = Foo('晴朗', 73)
n = getattr(obj, 'name')
print(n)  #晴朗
func = getattr(obj, 'say_hi')
func()  #hi,晴朗
print(getattr(obj, 'aaaaaaaa', '不存在啊')) #報錯

2、hasattr 判斷物件是否有對應的物件屬性(字串)

class Foo:
    f = '類的靜態變數'
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_hi(self):
        print(f'hi,{self.name}')

obj = Foo('晴朗', 73)

#檢測是否含有某屬性
print(hasattr(obj, 'name'))     #True
print(hasattr(obj, 'say_hi'))   #True
print(hasattr(obj, 'aaabbb'))   #False

3、setattr 為物件設定一個物件屬性

class Foo:
    f = '類的靜態變數'
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_hi(self):
        print(f'hi,{self.name}')

obj = Foo('晴朗', 73)
setattr(obj, "ty", '帥哥')
setattr(obj, 'show_name', lambda self:self.name+'是帥哥')
print(obj.__dict__)  #{'name': '晴朗', 'age': 73, 'ty': '帥哥', 'show_name': <function <lambda> at 0x00000207559E7C10>}
print(obj.show_name(obj))  #晴朗是帥哥

4、delattr 刪除指定屬性

class Foo:
    f = '類的靜態變數'
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_hi(self):
        print(f'hi,{self.name}')

obj = Foo('晴朗', 73)
delattr(obj, 'age')
# delattr(obj, 'say_hi')  #報錯,不能刪除方法
# delattr(obj, 'show_name111')#不存在,則報錯
print(obj.__dict__)   #{'name': '晴朗'}

三、類的反射

class Foo(object):
    staticField = "old boy"

    def __init__(self):
        self.name = 'wupeiqi'

    def func(self):
        return 'func'

    @staticmethod
    def bar():
        return 'bar'

print(getattr(Foo, 'staticField'))
m = getattr(Foo, 'func')
print(m(object))
print(getattr(Foo, 'bar'))
setattr(Foo, 'ty', '帥哥')
print(Foo.ty)

# 執行結果:
# old boy
# func
# <function Foo.bar at 0x0000018D4DD77DC0>
# <class '__main__.Foo'> ty
# 帥哥

四、模組的反射

1 、當前模組的反射

import sys

def s1():
    print('s1')

def s2():
    print('s2')

this_module = sys.modules[__name__]

m = hasattr(this_module, 's1')
print(m)  #True
n = getattr(this_module, 's2')
print(n)  #<function s2 at 0x0000022C4F847CA0>
n()  #s2

2、其他模組的反射

#一個模組中的程式碼
def test():
    print('from the test')
"""
程式目錄:
    module_test.py
    index.py
 
當前檔案:
    index.py
"""
# 另一個模組中的程式碼
import module_test as obj

obj.test()  #from the test

print(hasattr(obj,'test')) #True

getattr(obj,'test')()  #from the test

四、反射的應用

例子:模擬網頁登入

1、未用反射:

class User:
    def login(self):
        print('歡迎來到登入頁面')

    def register(self):
        print('歡迎來到註冊頁面')

    def save(self):
        print('歡迎來到儲存頁面')


while 1:
    choose = input('>>>').strip()
    if choose == 'login':
        obj = User()
        obj.login()
        break

    elif choose == 'register':
        obj = User()
        obj.register()
        break

    elif choose == 'save':
        obj = User()
        obj.save()
        break
    else:
        print('輸入錯誤,請重新輸入!')

2、使用反射:

class User:
    def login(self):
        print('歡迎來到登入頁面')
    
    def register(self):
        print('歡迎來到註冊頁面')
    
    def save(self):
        print('歡迎來到儲存頁面')

user = User()
while 1:
    choose = input('>>>').strip()
    if hasattr(user,choose):
        func = getattr(user,choose)
        func()
        break
    else:
        print('輸入錯誤,請重新輸入!')

相關文章