Python: Почему запрещен «из import *»?

Если в вашей программе (или модуле) окажется

from <module> import *

, вы получите предупреждение:

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

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

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

28
задан shuttle87 5 October 2019 в 17:06
поделиться

6 ответов

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

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

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

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

def f():
    ...

from module import *

def g():
    ...

РЕДАКТИРОВАТЬ, апрель 2013 г.: Изучая что-то еще, я обнаружил, что это ограничение было введено в Python 2.1 как следствие функции «Вложенные области» (PEP 227). Цитата из ссылки:

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

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

SON OF EDIT: ... и, по-видимому, flashk указал на это много лет назад в другом ответе, цитируя тот же абзац «Что нового в Python 2.1». Вы все идите, проголосуйте за это сейчас.

26
ответ дан 28 November 2019 в 02:59
поделиться

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

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

12
ответ дан 28 November 2019 в 02:59
поделиться

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

... это удобно для быстрых скриптов и исследования оболочки.

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

  1. это может привести к импорту имен, о которых вы не знаете, и стиранию локальных имен
  2. вы не можете знать, что используется в вашем коде, трудно понять зависимости скрипта
  3. дополнения кода больше не будут работать правильно
  4. удобные проверки IDE, такие как «эта переменная не была объявлена», больше не могут работать
  5. упрощается создание циклического импорта
]
4
ответ дан 28 November 2019 в 02:59
поделиться

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

1
ответ дан 28 November 2019 в 02:59
поделиться

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

0
ответ дан 28 November 2019 в 02:59
поделиться

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

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

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

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

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

Пространства имен — отличная идея. - давайте больше таких!

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

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

16
ответ дан 28 November 2019 в 02:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: