Как сообщить об ошибке с помощью функции Python 'help ()'?

1

Как хобби/учебный проект, я пишу генератор парсера в Python. Один из моих файлов кода называется "token.py" - который содержит пару классов для превращения простых строк в объекты Token. Я только что обнаружил, что использование функции "help()" из консоли в Python вызывает ошибку для любого модуля, определенного в каталоге, который содержит "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 демонстрируют это поведение.

Это известная проблема? Если нет, как мне сообщить об этом?

EDIT:

Несколько комментариев указывают, что это поведение не является ошибкой. Модуль, который определяет "help", импортирует модуль, называемый "токеном" из стандартной библиотеки Python. Тем не менее, Python смотрит в папку приложения, прежде чем он ищет в своей библиотеке, чтобы найти модули. В приведенном выше примере "help" пытается использовать мой "token.py" вместо Python, что вызывает ошибку.

Поскольку Python определен для проявления этого поведения, я полагаю, что это не ошибка. Но почему люди думают, что это поведение приемлемо? Это означает, что добавление новых модулей в библиотеку Python - даже без изменения существующих модулей - может сломать существующие приложения. Это также подразумевает, что программисты, как ожидается, запомнили имена всех модулей в библиотеке Python - как это все менее смешно, чем ожидать, что программисты запоминают каждое пространство имен в .NET или Java? Почему приложения Python не получают собственные пространства имен? Почему в их собственном пространстве имен не входят стандартные библиотечные модули Python?

Теги:
namespaces

4 ответа

5
Лучший ответ

Проблема заключается в том, что ваш локальный token.py импортируется help() вместо фактического token.py Python. Это произойдет для любого количества файлов .py, имена которых сталкиваются со встроенными модулями. Например, попробуйте создать файл pydoc.py в CWD, а затем попробуйте help() в Python. Функция help() - это просто встроенная функция Python, поэтому она следует тому же пути импорта, что и любой другой код Python.

  • 0
    Почему пути импорта встроенных функций относятся к моему приложению, а не к стандартной библиотеке Python? Не означает ли это, что если новые модули будут добавлены в стандартную библиотеку - даже если существующие модули останутся нетронутыми - это все равно может нарушить работу приложений? Это звучит как недостаток во время выполнения.
  • 1
    Пути импорта одинаковы для каждого бита Python в процессе, как определено sys.path . Ваш код, стандартная библиотека Python, или оба, может быть перестроена , чтобы воспользоваться (сравнительно недавно) «абсолютным импортом» подхода - но это (если сделано в стандартной библиотеке) нарушило бы существующие приложения , которые полагаются на возможность заменить их код на некоторые стандартные библиотечные модули (как правило, для их обогащения), так что это не будет явным выигрышем (рефакторинг вашего кода, OTOH, вполне выполним и без недостатков).
3

Всякий раз, когда вы выбираете названия своих модулей таким образом, чтобы имитировать имена модулей, определенные в стандартной библиотеке Python, вы несете полную ответственность за все, что происходит в результате - другие стандартные библиотечные модули Python, скорее всего, будут полагаться на те, которые вы скрытие/переопределение, и если ваши собственные модули не тщательно имитируют функциональность скрываемых модулей, не ошибка с Python: это ошибка с вашей код. Конечно, это относится к модулю token столько же, сколько к любому другому.

Если это случается с вами случайно, и вы ищете способ проверить свой код на наличие вероятных ошибок или конструкций iffy (а не, как вы говорите, способ сообщить о несуществующей ошибке с стандартной библиотекой Python), Я думаю, что такие инструменты, как pylint, могут помочь.

  • 0
    Как это ошибка с моим кодом? Вы говорите правильно, что пути импорта встроенных функций относятся к моему приложению, а не к стандартной библиотеке Python? Смотрите мой комментарий к ответу ezod.
  • 0
    sys.path контролирует порядок, в котором каталоги проверяются на предмет импортируемых модулей - так что да, конечно, совершенно правильно (и абсолютно обязательно), чтобы ваши каталоги имели приоритет над каталогами Python, если они перечислены ранее в sys.path ( вы можете прекрасно управлять sys.path , например, написав свой собственный модуль sitecustomize.py в каталоге site-packages , например, если вы хотите, чтобы ваши каталоги sitecustomize.py после Python в порядке импорта). Имена модулей (и встроенных) Python не являются «зарезервированными словами»: вы можете переопределить их, если знаете, что делаете .
Показать ещё 1 комментарий
1

Вы можете искать проблемы и сообщать о новых: http://bugs.python.org/.

0

Это не ошибка с методом help(). В стандартной библиотеке есть модуль с именем token.py, который импортируется tokenize.py(откуда возникает ошибка, с которой вы видите).

from tokenize.py:

from token import *

Итак, tokenize.py рассчитывает иметь кучу переменных из стандартной библиотеки token.py, но так как token.py в вашем рабочем каталоге фактически импортирован, они отсутствуют, что вызывает NameError (один из многих причин импорта * не следует использовать).

  • 0
    При использовании import token вместо оператора from сообщение об ошибке будет немного более четким, но все остальные аспекты наблюдаемого поведения будут абсолютно идентичны; поэтому я не согласен с тем, что это одна из «многих причин» (есть много других, которые гораздо важнее сообщений об ошибках, которые могут сбить с толку новичка ... ;-).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню