Chr*_*Gow 376 python reflection module inspect
我在我的系统上安装了一个python模块,我希望能够看到它中有哪些函数/类/方法.
我想在每一个上调用doc函数.在ruby中,我可以执行类似ClassName.methods的操作,以获取该类上可用的所有方法的列表.python中有类似的东西吗?
例如.就像是:
from somemodule import foo
print foo.methods # or whatever is the correct method to call
Run Code Online (Sandbox Code Playgroud)
cam*_*lan 468
您可以使用dir(module)
查看所有可用的方法/属性.还可以查看PyDocs.
Dan*_*ski 153
一旦你import
编写了模块,你就可以:
help(modulename)
Run Code Online (Sandbox Code Playgroud)
...以交互方式立即获取所有功能的文档.或者您可以使用:
dir(modulename)
Run Code Online (Sandbox Code Playgroud)
...简单地列出模块中定义的所有函数和变量的名称.
Tho*_*ers 126
检查模块.另请参阅inspect
模块,pydoc
交互式解释器中的函数以及help()
生成您所需文档的命令行工具.你可以给他们你希望看到文档的课程.例如,它们还可以生成HTML输出并将其写入磁盘.
小智 85
检查的一个例子:
from inspect import getmembers, isfunction
from my_project import my_module
functions_list = [o for o in getmembers(my_module) if isfunction(o[1])]
Run Code Online (Sandbox Code Playgroud)
getmembers返回(object_name,object_type)元组的列表.
您可以使用inspect模块中的任何其他isXXX函数替换isfunction.
Oli*_*Oli 70
import types
import yourmodule
print([getattr(yourmodule, a) for a in dir(yourmodule)
if isinstance(getattr(yourmodule, a), types.FunctionType)])
Run Code Online (Sandbox Code Playgroud)
csl*_*csl 40
为了完整起见,我想指出有时您可能想要解析代码而不是导入代码.一个import
将执行最高水平的表达,这可能是一个问题.
例如,我让用户为使用zipapp制作的包选择入口点函数.使用import
和inspect
冒险运行误入歧途的代码,导致崩溃,帮助打印出消息,弹出GUI对话框等等.
相反,我使用ast模块列出所有顶级函数:
import ast
import sys
def top_level_functions(body):
return (f for f in body if isinstance(f, ast.FunctionDef))
def parse_ast(filename):
with open(filename, "rt") as file:
return ast.parse(file.read(), filename=filename)
if __name__ == "__main__":
for filename in sys.argv[1:]:
print(filename)
tree = parse_ast(filename)
for func in top_level_functions(tree.body):
print(" %s" % func.name)
Run Code Online (Sandbox Code Playgroud)
将此代码放入list.py
并使用自身作为输入,我得到:
$ python list.py list.py
list.py
top_level_functions
parse_ast
Run Code Online (Sandbox Code Playgroud)
当然,导航AST有时会很棘手,即使是像Python这样相对简单的语言,因为AST非常低级.但是如果你有一个简单明了的用例,它既可行又安全.
但是,缺点是您无法检测在运行时生成的函数,例如foo = lambda x,y: x*y
.
Alg*_*ias 24
这样就可以了:
dir(module)
Run Code Online (Sandbox Code Playgroud)
但是,如果您发现读取返回的列表很烦人,只需使用以下循环来获取每行一个名称.
for i in dir(module): print i
Run Code Online (Sandbox Code Playgroud)
Cir*_*reo 23
对于您不想解析的代码,我建议使用上面基于AST的@csl方法.
对于其他一切,检查模块是正确的:
import inspect
import <module_to_inspect> as module
functions = inspect.getmembers(module, inspect.isfunction)
Run Code Online (Sandbox Code Playgroud)
这给出了表单中的2元组列表[(<name:str>, <value:function>), ...]
.
上面的简单答案在各种回复和评论中被暗示,但未明确提出.
bmu*_*bmu 20
dir(module)
是大多数答案中提到的使用脚本或标准解释器的标准方法.
但是,使用像IPython这样的交互式python shell,您可以使用tab-completion来概览模块中定义的所有对象.这比使用脚本和print
查看模块中定义的内容要方便得多.
module.<tab>
将显示模块中定义的所有对象(函数,类等)module.ClassX.<tab>
将向您展示一个类的方法和属性module.function_xy?
或者module.ClassX.method_xy?
将显示该函数/方法的文档字符串module.function_x??
或者module.SomeClass.method_xy??
将显示函数/方法的源代码.Sim*_*mon 18
对于全局函数dir()
是要使用的命令(如大多数答案中所述),但是它将公共函数和非公共函数一起列出.
例如运行:
>>> import re
>>> dir(re)
Run Code Online (Sandbox Code Playgroud)
返回函数/类,如:
'__all__', '_MAXCACHE', '_alphanum_bytes', '_alphanum_str', '_pattern_type', '_pickle', '_subx'
Run Code Online (Sandbox Code Playgroud)
其中一些通常不用于一般编程用途(但是由模块本身,除了DunderAliases之类的情况,例如__doc__
,__file__
ect).出于这个原因,将它们与公共列表一起列出可能没有用(这就是Python在使用时知道要获得什么的方式from module import *
).
__all__
可以用来解决这个问题,它返回一个模块中所有公共函数和类的列表(不以下划线开头的那些- _
).请参阅
Python中有人解释__all__吗?供使用__all__
.
这是一个例子:
>>> import re
>>> re.__all__
['match', 'fullmatch', 'search', 'sub', 'subn', 'split', 'findall', 'finditer', 'compile', 'purge', 'template', 'escape', 'error', 'A', 'I', 'L', 'M', 'S', 'X', 'U', 'ASCII', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL', 'VERBOSE', 'UNICODE']
>>>
Run Code Online (Sandbox Code Playgroud)
所有带下划线的函数和类都已被删除,只留下那些被定义为公共的函数和类,因此可以通过它们使用import *
.
请注意,__all__
并不总是定义.如果不包含则AttributeError
提出a.
这种情况与ast模块有关:
>>> import ast
>>> ast.__all__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'ast' has no attribute '__all__'
>>>
Run Code Online (Sandbox Code Playgroud)
如果您无法在没有导入错误的情况下导入所述 Python 文件,那么这些答案都不起作用。当我检查来自具有大量依赖项的大型代码库的文件时,就是这种情况。下面将文件作为文本处理并搜索所有以“def”开头的方法名称并打印它们及其行号。
import re
pattern = re.compile("def (.*)\(")
for i, line in enumerate(open('Example.py')):
for match in re.finditer(pattern, line):
print '%s: %s' % (i+1, match.groups()[0])
Run Code Online (Sandbox Code Playgroud)
__main__
我试图创建一个独立的 python 脚本,该脚本仅使用标准库来查找当前文件中带有前缀的函数,task_
以创建一个最小的自制版本npm run
。
如果您正在运行一个独立的脚本,您希望inspect.getmembers
在. 例如,module
sys.modules[\'__main__\']
inspect.getmembers(sys.modules[\'__main__\'], inspect.isfunction)\n
Run Code Online (Sandbox Code Playgroud)\n但我想按前缀过滤方法列表并删除前缀以创建查找字典。
\ndef _inspect_tasks():\n import inspect\n return { f[0].replace(\'task_\', \'\'): f[1] \n for f in inspect.getmembers(sys.modules[\'__main__\'], inspect.isfunction)\n if f[0].startswith(\'task_\')\n }\n
Run Code Online (Sandbox Code Playgroud)\n示例输出:
\n{\n \'install\': <function task_install at 0x105695940>,\n \'dev\': <function task_dev at 0x105695b80>,\n \'test\': <function task_test at 0x105695af0>\n}\n
Run Code Online (Sandbox Code Playgroud)\n我想要方法的名称来定义 CLI 任务名称,而不必重复自己。
\n./tasks.py
#!/usr/bin/env python3\nimport sys\nfrom subprocess import run\n\ndef _inspect_tasks():\n import inspect\n return { f[0].replace(\'task_\', \'\'): f[1] \n for f in inspect.getmembers(sys.modules[\'__main__\'], inspect.isfunction)\n if f[0].startswith(\'task_\')\n }\n\ndef _cmd(command, args):\n return run(command.split(" ") + args)\n\ndef task_install(args):\n return _cmd("python3 -m pip install -r requirements.txt -r requirements-dev.txt --upgrade", args)\n\ndef task_test(args):\n return _cmd("python3 -m pytest", args)\n\ndef task_dev(args):\n return _cmd("uvicorn api.v1:app", args)\n\nif __name__ == "__main__":\n tasks = _inspect_tasks()\n\n if len(sys.argv) >= 2 and sys.argv[1] in tasks.keys():\n tasks[sys.argv[1]](sys.argv[2:])\n else:\n print(f"Must provide a task from the following: {list(tasks.keys())}")\n
Run Code Online (Sandbox Code Playgroud)\n无参数示例:
\n\xce\xbb ./tasks.py\nMust provide a task from the following: [\'install\', \'dev\', \'test\']\n
Run Code Online (Sandbox Code Playgroud)\n使用额外参数运行测试的示例:
\n\xce\xbb ./tasks.py test -qq\ns.ssss.sF..Fs.sssFsss..ssssFssFs....s.s \n
Run Code Online (Sandbox Code Playgroud)\n你明白了。随着我的项目越来越多,保持脚本更新比保持自述文件更新更容易,我可以将其抽象为:
\n./tasks.py install\n./tasks.py dev\n./tasks.py test\n./tasks.py publish\n./tasks.py logs\n
Run Code Online (Sandbox Code Playgroud)\n
小智 5
然后使用vars(module)
以下方法过滤掉任何不是函数的内容inspect.isfunction
:
import inspect
import my_module
my_module_functions = [f for f in vars(my_module).values() if inspect.isfunction(f)]
Run Code Online (Sandbox Code Playgroud)
vars
over dir
or的优点inspect.getmembers
是它按照定义的顺序返回函数,而不是按字母顺序排序。
另外,这将包括由 导入的函数my_module
,如果您想过滤掉这些函数以仅获取在 中定义的函数my_module
,请参阅我的问题获取 Python 模块中的所有定义函数。