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

2024-04-29 02:34:10 发布

您现在位置: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是在所有函数的顶部定义的?

编辑一:我想做的是

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的原因


Tags: nameinmodulesobjforifdefsys
2条回答

EDIT 1: What I am trying to do is

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将获得所有顶级函数。(我假设testalltest1是从模块底部的if __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文件)。编译器不需要知道一个名称有什么值,只需要知道它是本地的还是全局的(或者是一个闭包单元格),它已经可以知道sysinspecttest1是全局的(因为您没有在testall或封闭的作用域中分配给它们)。

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

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

如果您稍后调用test1,它调用testall,会怎么样?没问题。解释器执行test1,它有一个对testall的调用,这个调用显然已经定义好了,所以解释器调用它,剩下的与前面的段落相同。

那么,如果在test1test2定义之间调用testalltest1呢?在这种情况下,test2还没有定义,因此它不会出现在列表中(第一个版本),或者引发一个NameError(第二个版本)。但只要你不这么做,就没问题。也没有理由这么做。


如果你担心每次你打电话给testall时计算的可怕性能成本……那么,首先,这是一个愚蠢的担心;你要打多少次电话?你的函数真的如此之快以至于调用和过滤的时间甚至出现在雷达上了吗?但如果真的很担心,只需将值缓存到您最喜欢的可变默认值、privat global、function attribute、…:

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

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

相关问题 更多 >