Python物件導向之反射

來源:互聯網
上載者:User

標籤:python 反射 內建函數 getattr 授權 動態載入 模組

    首先,我們來看兩個內建函數,isinstance和issubclass,前者是判斷一個對象是不是相應的類型,比如:

obj = ‘python‘print(isinstance(obj,str))

判斷obj是否為字串類型,結果返回True

後者issubclass則判斷一個類是否為另一個的子類,比如:

class A:    passclass B(A):    passprint(issubclass(B,A))

判斷B是否為A的子類,結果返回True

 

反射:其實它的核心本質其實就是利用字串的形式去對象(模組)中操作(尋找/擷取/刪除/添加)成員,一種基於字串的事件驅動!

python的四個重要內建函數:getattrhasattrdelattrsetattr較為全面的實現了基於字串的反射機制。他們都是對記憶體內的模組進行操作,並不會對源檔案進行修改。

import sysclass Commons:    @staticmethod    def login():        print("登入頁面")    @staticmethod    def logout():        print("退出頁面")    @staticmethod    def home():        print("這是網站首頁")this_moudle = sys.modules[__name__]def run():    inp = input("請輸入想訪問頁面的URl:").strip()    if hasattr(Commons,inp):        func = getattr(Commons,inp,‘沒有這個頁面‘)        func()    else:        print("404!")run()

從上面的例子可以看到hasattr及getattr的用法,另外還有delattr和setattr方法類似

 

那麼我們為什麼要用反射機制呢?

其好處有:

        1、實現可插拔機制(對於代碼來說),可以事先定義好介面,介面只有在被完成後才會真正執行,這實現了隨插即用,這其實是一種‘後期綁定’,什麼意思?即你可以事先把主要的邏輯寫好(只定義介面),然後後期再去實現介面的功能

        2、動態匯入模組(基於反射當前模組成員)

def run():  inp = input("請輸入您想訪問頁面的url: ").strip()  modules, func = inp.split("/")  obj = __import__(modules)  if hasattr(obj, func):    func = getattr(obj, func)    func()  else:    print("404")    run()

輸入形如:請輸入您想訪問頁面的url: commons/home

執行結果為:這是網站首頁

 

在這,順便說一下,官方建議用下述的方式進行模組的匯入

import importlibimportlib.import_module(‘需要匯入的庫‘)

 

接下來我們看看其他幾個python內建的函數__getattr__、__setattr__、__delattr__

class Foo:    def __init__(self,name):        self.name = name    def __setattr__(self, key, value):#添加/修改屬性會觸發它的執行         if isinstance(value,str):            self.__dict__[key] = value            print("__setattr__")        else:            raise TypeError("必須為字串")    def __getattr__(self, item):#只有在使用點調用屬性且屬性不存在的時候才會觸發         print("getattr--->%s %s"%(item,type(item)))    def __delattr__(self, item):#刪除屬性的時候會觸發         self.__dict__.pop(item)        print("__delattr__")f = Foo(‘zds‘)print(f.name)f.age = ‘18‘print(f.age)del f.ageprint(f.__dict__)print(f.xxxxx)

 

封裝與授權

封裝:python為大家提供了標準資料類型,以及豐富的內建方法,其實在很多情境下我們都需要基於標準資料類型來定製我們自己的資料類型,新增/改寫方法,這就用到了我們剛學的繼承/派生知識(其他的標準類型均可以通過下面的方式進行二次加工)

 

授權:授權是封裝的一個特性, 封裝一個類型通常是對已存在的類型的一些定製,這種做法可以建立,修改或刪除原有產品的功能。其它的則保持原樣。授權的過程,即是所有更新的功能都是由新類的某部分來處理,但已存在的功能就授權給對象的預設屬性。

實現授權的關鍵點就是覆蓋__getattr__方法

 

以下樣本作為練習:

 基於授權定製自己的清單類型,要求定製的自己的__init__方法,
 定製自己的append:只能向列表加入字串類型的值
 定製顯示列表中間那個值的屬性
 其餘方法都使用list預設的

class List(list):    def __init__(self,obj):        super().__init__(obj)    def append(self, p_object):        if not isinstance(p_object,str):             raise TypeError("must be str type")        super().append(p_object)    @property    def mid_value(self):        return self[(self.__len__())//2]    def __getattr__(self, item):        if hasattr(List,item):            func = getattr(List,item)            return self.func()        else:            print("沒有這個方法")l = List([1,2,3,4,5,6])l.append(‘7‘)print(l)print(l.mid_value)l.insert(0,9)print(l)

運行結果為:

[1, 2, 3, 4, 5, 6, ‘7‘]
4
[9, 1, 2, 3, 4, 5, 6, ‘7‘]

Python物件導向之反射

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.