[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.

posted @ 2022-04-05 19:26  wildkid1024  阅读(954)  评论(0编辑  收藏  举报