python - 获取当前模块中所有函数的列表。检查当前模块不起作用?

时间:2013-09-20 01:51:55

标签: python

我有以下代码

fset = [ obj for name,obj in inspect.getmembers(sys.modules[__name__]) if inspect.isfunction(obj) ]

def func(num):
    pass

if __name__ == "__main__":
    print(fset)

打印

[]

然而这

def func(num):
    pass

fset = [ obj for name,obj in inspect.getmembers(sys.modules[__name__]) if inspect.isfunction(obj) ]

if __name__ == "__main__":
    print(fset)

打印

[<function func at 0x7f35c29383b0>]

那么如何将fset列为当前模块中所有函数的列表,其中fset定义在所有函数的顶部?

编辑1:我想做的是

def testall(arg):
    return any(f(arg) for f in testfunctions)

def test1(arg):
    #code here
    # may call testall but wont call anyother test*

def test2(arg):
    #code here
    # may call testall but wont call anyother test*

将来可能会添加更多测试功能。这就是fset / testfunctions的原因

3 个答案:

答案 0 :(得分:11)

不可能。函数定义在Python中执行 。在执行定义之前,函数不存在。在定义函数之前,无法定义fset变量。

答案 1 :(得分:10)

  

编辑1:我想做的是

def testall(arg):
    return any(f(arg) for f in testfunctions)

def test1(arg):
    #code here
    # may call testall but wont call anyother test*    

这很好用:

def testall(arg):
    testfunctions = [obj for name,obj in inspect.getmembers(sys.modules[__name__]) 
                     if (inspect.isfunction(obj) and 
                         name.startwith('test') and name != 'testall')]
    return any(f(arg) for f in testfunctions)

def test1(arg):
    #code here
    # may call testall but wont call anyother test*

在这种情况下,testfunctions在调用testall之前不会被评估,所以此时没有问题 - 所有顶级模块代码(包括test1定义)将被评估,因此testfunctions将获得所有顶级函数。 (我假设从模块底部的testall块调用test1if __name__ == '__main__',或者另一个脚本正在执行import tests; tests.test1(10)或类似的事情。)

事实上,即使你明确地命名为test1test2,也没有问题:

def testall(arg):
    testfunctions = ('test1',)
    return any(f(arg) for f in testfunctions)

def test1(arg):
    #code here
    # may call testall but wont call anyother test*

同样,test1已经在您拨打testall时定义,所以一切都很好。


如果您想了解其工作原理,您必须了解这里的各个阶段。

导入模块或运行顶级脚本时,第一个阶段是编译(除非已有缓存的.pyc文件)。编译器不需要知道名称具有什么值,只需知道它是本地的还是全局的(或闭包单元格),并且它已经可以告诉sysinspect以及test1是全局变量(因为你没有在testall或封闭范围内分配它们。)

接下来,解释器按顺序执行顶级模块的编译字节码。这包括执行函数定义。因此,testall成为一个函数,然后test1成为一个函数,然后test2成为一个函数。 (函数实际上只是适当的编译代码,附加了一些额外的东西,比如它定义的全局命名空间。)

稍后,当您调用testall函数时,解释器将执行该函数。这是在列表理解(在第一个版本中)或全局名称查找(在第二个版本中)发生时。由于test1test2的函数定义已经过评估并绑定到模块中的全局名称,因此一切正常。

如果您稍后拨打test1来拨打testall,该怎么办?没问题。解释器执行test1,它有一个testall的调用,显然已经定义了,所以解释器调用它,其余的与前一段相同。

那么,如果您在testalltest1定义之间拨打test1test2,该怎么办?在这种情况下,test2尚未定义,因此它不会出现在列表中(第一个版本),或者会引发NameError(第二个版本)。但只要你不这样做,就没有问题。并且没有充分的理由这样做。


如果你担心每次打电话testfunctions时计算testall的可怕性能成本......嗯,首先,这是一个愚蠢的担忧;你要打多少次电话?你的功能真的如此之快,以至于调用和过滤getmembers的时间甚至会出现在雷达上吗?但是,如果它真的是一个担心,只需将值缓存在您最喜欢的常用方法 - 可变默认值,privat全局,函数属性,......:

def testall(arg, _functions_cache=[]):
    if not _functions_cache:
        _functions_cache.extend([…])

答案 2 :(得分:2)

要排除任何导入的功能,这将起作用:

import sys
import inspect 
   [obj for name,obj in inspect.getmembers(sys.modules[__name__]) 
                         if (inspect.isfunction(obj) and 
                             name.startswith('test') and
                             obj.__module__ == __name__)]