【问题标题】:How to report a bug with Python's 'help()' function?如何使用 Python 的 'help()' 函数报告错误?
【发布时间】:2010-01-23 01:39:20
【问题描述】:

作为一个爱好/学习项目,我正在用 Python 编写一个解析器生成器。我的一个代码文件名为“token.py”——其中包含几个用于将纯字符串转换为 Token 对象的类。我刚刚发现在 Python 中使用控制台中的“help()”函数会为包含“token.py”的目录中定义的任何模块引发错误。

这是一种重现错误的方法。使用以下文件创建一个新目录:

/New Folder
  main.py
  token.py

将“token.py”留空。在 main.py 中,编写一个简单的函数——例如:

def test():
    pass

然后,在您的 Python 控制台中,导入 'main' 并调用 'help(main.test)' - 您将得到以下结果:

C:\New Folder>python
Python 3.1.1 (r311:74483, Aug 17 2009, 17:02:12) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import main
>>> help(main.test)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python31\lib\site.py", line 428, in __call__
    import pydoc
  File "C:\Python31\lib\pydoc.py", line 55, in <module>
    import sys, imp, os, re, inspect, builtins, pkgutil
  File "C:\Python31\lib\inspect.py", line 40, in <module>
    import tokenize
  File "C:\Python31\lib\tokenize.py", line 37, in <module>
    COMMENT = N_TOKENS
NameError: name 'N_TOKENS' is not defined
>>>

如果您删除 'token.py' 文件,help() 将正常运行。 Python 3.1 和 Python 2.5 都表现出这种行为。

这是一个已知问题吗?如果没有,我该如何举报?

编辑:

几个 cmets 声明此行为不是错误。定义“帮助”的模块从 Python 的标准库中导入一个名为“令牌”的模块。但是,Python 会先在应用程序文件夹中查找,然后再在其库中查找模块。在上面的示例中,“帮助”尝试使用我的“token.py”而不是 Python 的,这会导致错误。

由于 Python 被定义为表现出这种行为,我想这不是一个错误。但是为什么人们认为这种行为是可以接受的呢?这意味着向 Python 库添加新模块——即使不更改现有模块——也可能会破坏现有应用程序。这也意味着程序员应该记住 Python 库中所有模块的名称——这比期望程序员记住 .NET 或 Java 中的每个命名空间更荒谬吗?为什么 Python 应用程序没有自己的命名空间?为什么 Python 标准库模块不在自己的命名空间中?

【问题讨论】:

    标签: python namespaces


    【解决方案1】:

    问题是您的本地token.py 是由help() 导入的,而不是Python 的实际token.py。对于名称与内置模块冲突的任意数量的 .py 文件,都会发生这种情况。例如,尝试在 CWD 中创建 pydoc.py 文件,然后在 Python 中尝试 help()help() 函数只是一个内置的 Python 函数,因此它遵循与任何其他 Python 代码相同的导入路径。

    【讨论】:

    • 为什么内置函数的导入路径是相对于我的应用程序而不是 Python 的标准库?这是否意味着如果将新模块添加到标准库中——即使现有模块保持不变——它仍然会破坏应用程序?这听起来像是运行时的一个缺陷。
    • 进程中每一位 Python 的导入路径都是相同的,由 sys.path 定义。您的代码、Python 标准库或两者都可能被重组以利用(相对较新的)“绝对导入”方法——但 that(如果在标准库中完成)会破坏现有的确实依赖于能够将其代码替换为某些标准库模块(通常是为了丰富它们)的应用程序,因此这不会是一个明显的胜利(重构您的代码,OTOH,是完全可行的,并且没有缺点)。
    【解决方案2】:

    无论何时您选择以模仿 Python 标准库中定义的模块名称的方式命名您的模块,您都要对结果发生的任何事情负全部责任 - 其他 Python 标准库模块可能依赖于您所使用的模块隐藏/覆盖,如果您自己的模块没有仔细模仿您隐藏的模块的功能,那 不是 Python 的错误:这是 your 的错误代码。当然,这同样适用于模块token

    如果这种情况意外发生在您身上,并且您正在寻找一种方法来检查您的代码中是否存在可能的错误或不确定的结构(而不​​是像您所说的那样,使用 Python 标准库报告不存在的错误的方法),我认为像 pylint 这样的工具可能会有所帮助。

    【讨论】:

    • 我的代码有什么错误?你是说内置函数的导入路径是相对于我的应用程序而不是 Python 的标准库是正确的吗?请参阅我对 ezod 答案的评论。
    • sys.path 控制检查目录以查找要导入的模块的顺序——所以是的,当然,如果您的目录优先于 Python 的目录,这是完全正确的(并且绝对是强制性的)之前在sys.path 中重新列出(您可以很好地控制sys.path,例如,通过在site-packages 目录中编写您自己的sitecustomize.py 模块,例如,如果您希望您的目录按导入顺序排在Python 之后)。 Python 的模块(和内置)名称不是“保留字”:您可以重新定义它们如果您知道自己在做什么
    • ...如果您知道自己在做什么,那么,是的,很明显代码中的错误(错误的意外名称选择)。
    【解决方案3】:

    您可以在此处搜索问题并报告新问题:http://bugs.python.org/

    【讨论】:

      【解决方案4】:

      这不是 help() 方法的错误。标准库中有一个名为 token.py 的模块,它由 tokenize.py 导入(您看到的错误来自该模块)。

      来自 tokenize.py:

      from token import *
      

      所以 tokenize.py 期望有一堆来自标准库 token.py 的变量,但是由于工作目录中的 token.py 实际上是导入的,所以它们不存在,这导致了 NameError(其中一个原因 import * 不应使用)。

      【讨论】:

      • 使用import token 而不是from 语句,错误消息会稍微清晰一些,但观察到的行为的所有其他方面都绝对相同;所以我不同意这是“许多原因”之一(还有许多其他原因比错误消息更重要,可能会使初学者感到困惑......;-)。
      猜你喜欢
      • 2011-07-02
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多