Подтвердить что ты не робот

Python: Почему "из <module> import *" запрещается?

Если у вас

from <module> import *

в середине вашей программы (или модуля) вы получите предупреждение:

/tmp/foo:100: SyntaxWarning: import * only allowed at module level

Я понимаю, почему import * вообще обескураживает (невидимость пространства имен), но есть много ситуаций, когда это окажется удобным, особенно там, где код не используется никому.

Итак, кто-нибудь может точно объяснить, почему from <module> import * должен быть запрещенным во всех возможных случаях?

4b9b3361

Ответ 1

Я полагаю, что "в середине вашей программы" вы говорите об импорте внутри определения функции:

def f():
    from module import *    # not allowed

Это не допускается, потому что это слишком сильно оптимизирует тело функции. Реализация Python хочет знать все имена функционально-локальных переменных, когда он байт-компилирует функцию, чтобы она могла оптимизировать ссылки переменных в операциях в стеке операнда виртуальной машины (CPython) или, по меньшей мере, в локальный переменный слот а не поисками в внешних пространствах имен. Если вы могли бы сбросить все содержимое модуля в локальное пространство имен функций, тогда компилятор должен был предположить, что любое имя в функции может ссылаться на модуль глобальный, потому что список имен, внесенных from module import *, является только известных во время выполнения.

Помещение from module import * между объявлениями верхнего уровня - это плохой стиль, но это разрешено:

def f():
    ...

from module import *

def g():
    ...

EDIT Апрель 2013:. Изучая что-то еще, я обнаружил, что это ограничение было введено в Python 2.1, как следствие "Вложенные области" (PEP 227). Цитата из ссылки:

Один побочный эффект изменения заключается в том, что утверждения from module import * и exec были сделаны незаконными внутри области функций при определенных условиях. В справочном руководстве Python сказано, что from module import * является только законным на верхнем уровне модуля, но интерпретатор CPython никогда не применял это раньше. В рамках реализации вложенных областей компилятор, который превращает исходный код Python в байт-коды, должен генерировать другой код для доступа к переменным в области содержимого. from module import * и exec не позволяют компилятору понять это, потому что они добавляют имена в локальное пространство имен, которые непознаваемы во время компиляции. Поэтому, если функция содержит определения функций или выражения lambda со свободными переменными, компилятор будет отмечать это, создавая исключение SyntaxError.

Это разъясняет поведение Python 3.x vs 2.x, обсуждаемое в комментариях. Это всегда противоречит спецификации языка, но CPython с 2.1 по 2.7 только выдает ошибку для from module import * внутри функции, если это может повлиять на способность компилятора узнать, связывается ли переменная локально или в области содержимого. В 3.x он был доведен до безусловной ошибки.

SON OF EDIT:... и, по-видимому, flashk указал на это несколько лет назад в другом ответе, цитируя тот же абзац "What New in Python 2.1". Теперь вы можете продвинуться вперёд.

Ответ 2

На любом лексическом уровне from amodule import * - это "казалось бы хорошей идеей в то время" дизайнерское решение, которое доказало реальную катастрофу в реальной жизни, за исключением удобного исследования в интерактивном интерпретаторе (даже тогда, Я не слишком горяч на нем - import module as m заставляет только два дополнительных символа использовать вместо них квалифицированные имена [[только префикс m.]], а квалифицированные имена всегда более четкие и более гибкие, чем имена банеров, не говоря уже о большая полезность в поисковых интерактивных ситуациях, когда m доступен для help(m), reload(m) и тому подобного!).

Эта разрушенная конструкция делает ее очень трудной, поскольку бедный человек, читающий код (часто в обреченной попытке помочь отладить его), чтобы понять, откуда приходят загадочно-появляющиеся имена, невозможно, если конструкция используется больше, чем один раз на лексическом уровне; но даже когда он используется только один раз, он заставляет кропотливо перечитывать весь модуль каждый раз, прежде чем можно убедить себя, что, да, это забитое барное имя должно появиться из модуля.

Плюс, авторы модулей обычно не идут на крайние проблемы, необходимые для "поддержки" ужасной конструкции, о которой идет речь. Если где-то в вашем коде есть, скажем, использование sys.argvimport sys на самом верху вашего модуля, конечно), как вы знаете, что sys модуль должен быть... или какой-то совершенно другой (или немодульный), исходящий из ... import *?! Умножьте, что по всем квалифицированным именам вы используете, а несчастье - единственный конечный результат - это и загадочные ошибки, требующие долгой, кропотливой отладки (обычно с неохотой помощью кого-то, кто "получает" Python...! -).

Внутри функции, способ добавления и переопределения произвольных локальных имен будет еще хуже. В качестве элементарной, но решающей оптимизации компилятор Python просматривает тело функции для любого присваивания или других операторов привязки для каждого имени бана и считает "локальными" имена, которые он видит таким образом (другие должны быть глобальными или встроенными). С import * (точно так же, как с exec somestring без явных dicts для использования в качестве пространств имен), внезапно становится полной тайной, имена которой локальны, имена которых глобальны, поэтому бедному компилятору приходилось прибегать к самым медленным возможную стратегию для каждого поиска имени, используя dict для локальных переменных (вместо компактного "вектора", который он обычно использует) и выполнения до трех исканий для каждого упоминаемого барана, снова и снова.

Перейдите в любую интерактивную подсказку Python. Введите import this. Что ты видишь? Дзен Питона. Какая последняя и, вероятно, самая большая часть мудрости в этом тексте...?

Пространства имен - одна хорошая идея - позвольте сделать больше из них!

Заставляя использовать барные имена, где квалифицированные имена настолько предпочтительнее, вы по существу делаете очень противоположную эту мудрую рекомендацию: вместо того, чтобы восхищаться величием и хонингованием пространств имен и делать больше из них вы разбиваете два совершенно хороших и готовых к использованию пространства имен (импортируемого модуля и лексического объема, в который вы его импортируете), чтобы создать единую, нечестивую, багги, медленный, жесткий, непригодный беспорядок.

Если бы я мог вернуться и изменить одно раннее дизайнерское решение в Python (это трудный выбор, потому что использование def и особенно lambda для того, что Javascript гораздо более читаемо вызывает function, является второй секундой; -), я бы задним числом уничтожил идею import * из соображений Гвидо. Никакое количество предполагаемого удобства для исследования в интерактивном приглашении не может сбалансировать количество зла, которое оно совершило...! -)

Ответ 3

Заметки о выпуске для Python 2.1 объясняют, почему это ограничение существует:

Один из побочных эффектов изменения заключается в том, что из импорта модуля * и exec заявления были сделаны незаконными внутри области функций при определенных условия. Ссылка на Python руководство все время говорило об этом модуль импорта * является законным только на верхний уровень модуля, но CPython переводчик никогда не применял этот до. В рамках реализации вложенных областей, компилятор, который превращает источник Python в байт-коды для генерации другого кода для доступа переменные в области сдерживания. из модуль import * и exec делают это невозможно, чтобы компилятор это, потому что они добавляют имена к локальное пространство имен, которые непознаваемым во время компиляции. Следовательно, если функция содержит функцию определения или лямбда-выражения с свободные переменные, компилятор будет отмечать это, подняв SyntaxError исключение.

Ответ 4

Это не запрещено, потому что...

... он удобен для быстрого сценария и изучения оболочки.

... но вы не должны держать его в каком-либо серьезном коде

  • это может привести к импортированию имен, о которых вы не знаете, и удалении локальных имен
  • Вы не можете знать, что используется в вашем коде, трудно знать зависимости script
  • завершение кода больше не будет работать.
  • Удобные проверки IDE, такие как "этот var не был объявлен", больше не могут работать
  • упростить создание циклического импорта.

Ответ 5

Это не запрещено. Он отлично работает, но вы получаете предупреждение, потому что это вообще плохая идея (по причинам, по которым другие пошли). Вы можете, если хотите, подавить предупреждение; модуль предупреждений - это то, что вы хотите для этого.

Ответ 6

другие дали подробные ответы, я дам краткий обзорный ответ моего понимания. При использовании от вас вы делаете это так, чтобы вы могли напрямую вызывать любую функцию в том модуле, который вы импортировали, не выполняя modulename.functioname(вы может просто вызвать "имя функции" ), это создает проблемы, если у вас есть 2 функции с одним и тем же именем в разных модулях, а также может создавать путаницу при работе с множеством функций, так как вы не знаете, к какому объекту/модулю он принадлежит (из точки из-за того, что кто-то просматривает уже написанный код, который не знаком с ним)