【问题标题】:How to access a docstring from a separate script?如何从单独的脚本访问文档字符串?
【发布时间】:2021-03-01 22:37:05
【问题描述】:

为用户构建一个 GUI 以选择他们想要运行的 Python 脚本。每个脚本都有自己的文档字符串来解释脚本的输入和输出。我想在他们突出显示脚本后在 UI 中显示该信息,但未选择运行它,而且我似乎无法从基本程序访问文档字符串。

例如

test.py

"""this is a docstring"""
print('hello world')

program.py

index 在此示例中为 test.py,但通常不知道,因为它是用户在 GUI 中选择的任何内容。

# index is test.py
def on_selected(self, index):
    script_path = self.tree_view_model.filePath(index)
    fparse = ast.parse(''.join(open(script_path)))
    self.textBrowser_description.setPlainText(ast.get_docstring(fparse))

【问题讨论】:

  • 您已经在此处使用ast.get_docstring 的代码似乎是解决此问题的正确方法。有什么问题?
  • 这个here已经有答案了
  • @Comsavvy 您引用的问题与此问题无关。
  • 确实如此! @e4862 正在寻找一种方法来获取 test.py 的文档字符串。
  • 不清楚你为什么用ast.parse(''.join(open(script_path)))而不是ast.parse(open(script_path).read())

标签: python python-3.8 docstring python-ast


【解决方案1】:

让我们要访问的文档字符串属于文件file.py

您可以通过执行以下操作来获取文档字符串:

import file
print(file.__doc__)

如果您想在导入之前获取文档字符串,那么您可以读取文件并提取文档字符串。这是一个例子:

import re


def get_docstring(file)
    with open(file, "r") as f:
        content = f.read()  # read file
        quote = content[0]  # get type of quote
        pattern = re.compile(rf"^{quote}{quote}{quote}[^{quote}]*{quote}{quote}{quote}")  # create docstring pattern
    return re.findall(pattern, content)[0][3:-3]  # return docstring without quotes


print(get_docstring("file.py"))

注意:要使此正则表达式起作用,文档字符串需要位于最顶部。

【讨论】:

  • 我认为他希望在导入之前显示它,因为它在用户用来选择要加载的文件的菜单中。
  • @Barmar 除非以某种方式评估文件,否则您无法获得file.__doc__。唯一的区别是语义,比如使用importlib.import_module,甚至是eval
  • importlib,
  • @Aaron:因为他们不想导入它:“我想在他们突出显示脚本后在 UI 中显示该信息,但没有选择运行它”。
  • @e4862:所有 Python 脚本都是模块。
【解决方案2】:

以下是通过importlib 获取它的方法。大部分逻辑都放在了一个函数中。请注意,使用importlib 确实会导入脚本(这会导致执行其所有顶级语句),但是当函数返回时,模块本身会被丢弃。

如果这是我想从中获取文档字符串的当前目录中的脚本docstring_test.py

""" this is a multiline
    docstring.
"""
print('hello world')

这是怎么做的:

import importlib.util

def get_docstring(script_name, script_path):
    spec = importlib.util.spec_from_file_location(script_name, script_path)
    foo = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(foo)
    return foo.__doc__

if __name__ == '__main__':

    print(get_docstring('docstring_test', "./docstring_test.py"))

输出:

hello world
 this is a multiline
    docstring.

更新:

下面是如何做到这一点,让标准库中的ast 模块进行解析,避免导入/执行脚本以及尝试使用正则表达式自己解析它。

这看起来或多或少等同于你的问题,所以不清楚为什么你所拥有的对你不起作用。

import ast

def get_docstring(script_path):
    with open(script_path, 'r') as file:
        tree = ast.parse(file.read())
        return ast.get_docstring(tree, clean=False)

if __name__ == '__main__':

    print(repr(get_docstring('./docstring_test.py')))

输出:

' this is a multiline\n    docstring.\n'

【讨论】:

  • 我将不得不看看是否有办法在不执行代码的情况下做到这一点。或者重新构想 GUI 以在用户选择运行脚本后打开另一个仅显示文档字符串的窗口。
  • @SaladHead 的 answer 通过尝试解析文件的内容来做到这一点,这可能会在大多数情况下都有效——我个人对解析脚本有点怀疑一个正则表达式。就执行代码而言,大多数模块在导入时都不会打印出来(原因很明显)。
  • 问题是软件开发人员无法控制脚本的编写,因此保持一致性是我们无法控制的。让人很难喜欢解析文件。
  • 原来的问题已经在使用 ast.parse/ast.get_docstring... 而 O.P. 从来没有解释过这种方法有什么问题。
猜你喜欢
  • 2012-01-27
  • 1970-01-01
  • 1970-01-01
  • 2013-05-18
  • 1970-01-01
  • 1970-01-01
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多