我有以下代码
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的原因
答案 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
块调用test1
或if __name__ == '__main__'
,或者另一个脚本正在执行import tests; tests.test1(10)
或类似的事情。)
事实上,即使你明确地命名为test1
和test2
,也没有问题:
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文件)。编译器不需要知道名称具有什么值,只需知道它是本地的还是全局的(或闭包单元格),并且它已经可以告诉sys
和inspect
以及test1
是全局变量(因为你没有在testall
或封闭范围内分配它们。)
接下来,解释器按顺序执行顶级模块的编译字节码。这包括执行函数定义。因此,testall
成为一个函数,然后test1
成为一个函数,然后test2
成为一个函数。 (函数实际上只是适当的编译代码,附加了一些额外的东西,比如它定义的全局命名空间。)
稍后,当您调用testall
函数时,解释器将执行该函数。这是在列表理解(在第一个版本中)或全局名称查找(在第二个版本中)发生时。由于test1
和test2
的函数定义已经过评估并绑定到模块中的全局名称,因此一切正常。
如果您稍后拨打test1
来拨打testall
,该怎么办?没问题。解释器执行test1
,它有一个testall
的调用,显然已经定义了,所以解释器调用它,其余的与前一段相同。
那么,如果您在testall
和test1
定义之间拨打test1
或test2
,该怎么办?在这种情况下,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__)]