天天看點

Python 反射

反射說簡單點 --> 就是利用字元串的形式去對象(子產品)中操作(尋找/檢查/删除/設定)成員。

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      

 利用反射導入子產品、查找類、建立對象、查找對象中的字段

内容如下:

Python 反射
Python 反射
#!/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/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接。