[python]python動態調用模塊內的類或方法


需求

寫py程序時候總是碰到下面這種場景,動態生成對象或者函數:

>>> def foo():
        print "foo"
 
>>> def bar():
        print "bar"
 
>>> func_list = ["foo","bar"]
>>> for func in func_list:
        func()
TypeError: 'str' object is not callable

這種需要根據字符串生成對象或者方法的需求,再java里大概是反射的一個功能,因為老是用到,所以在這里總結一下.

一共有以下幾種方式:

eval

>>> for func in func_list:
        eval(func)()
foo
bar

eval是最簡單粗暴的方式,會將字符串重新解釋為可運行對象,也即是所有的可執行的字符串都會被編譯為python對象然后執行結果.這種方式雖然能夠得到正確的結果,但是一旦在某些程序中使用,便可能會給黑客入侵帶來便利,因為可以動態執行所有的字符串,那么關於系統相關信息的函數也並不例外.eval is evil,除非十分必要,否則應該極力避免.

locals()和globals()


>>> for func in func_list:
        locals()[func]()
foo
bar
 
>>> for func in func_list:
        globals()[func]()
foo
bar

locals()和globals()分別是存儲python程序變量的兩個dict,每個dict中都存放着不同數目的name[str]和value[object]的條目,其中lacals中存儲的是局部變量,globas中存儲的是全局變量.
使用這兩個dict有一定限制,在單文件中尚可,但如果在多個包,尤其是每個包中有相同名字的對象或方法時,就有點力不從心了.

熟悉程序運行過程的朋友知道,程序在內存中分為不同的區,有着不同的空間和生命周期.其空間意義及周期如下:

Local:局部命名空間,每個函數所擁有的命名空間,記錄了函數中定義的所有變量,包括函數的入參、內部定義的局部變量。
Global:全局命名空間,每個模塊加載執行時創建的,記錄了模塊中定義的變量,包括模塊中定義的函數、類、其他導入的模塊、模塊級的變量與常量。
Built-in:python自帶的內建命名空間,任何模塊均可以訪問,放着內置的函數和異常。

Local(局部命名空間)在函數被調用時才被創建,但函數返回結果或拋出異常時被刪除。(每一個遞歸函數都擁有自己的命名空間)。

Global(全局命名空間)在模塊被加載時創建,通常一直保留直到python解釋器退出。

Built-in(內建命名空間)在python解釋器啟動時創建,一直保留直到解釋器退出。

各命名空間創建順序:python解釋器啟動 ->創建內建命名空間 -> 加載模塊 -> 創建全局命名空間 ->函數被調用 ->創建局部命名空間

各命名空間銷毀順序:函數調用結束 -> 銷毀函數對應的局部命名空間 -> python虛擬機(解釋器)退出 ->銷毀全局命名空間 ->銷毀內建命名空間

python解釋器加載階段會創建出內建命名空間、模塊的全局命名空間,局部命名空間是在運行階段函數被調用時動態創建出來的,函數調用結束動態的銷毀的。

getattr()


>>> class Foo:
    def do_foo(self):
        ...
 
    def do_bar(self):
        ...
 
>>> f = getattr(foo_instance, 'do_' + opname)
>>> f()

多用於類屬性方法的獲取,當然包似乎也行.

methodcaller

>>> class Foo:
    def do_foo(self):
        print 1
 
    def do_bar(self):
        print 2
 
>>> f = Foo()
>>> from operator import methodcaller
>>> methodcaller('do_foo')(f)

有點類似於getattr,不過getattr可以獲取屬性,methodcaller側重於執行method.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM