Python: Почему «из <module>import *» должно быть запрещено? - PullRequest
26 голосов
/ 26 августа 2010

Если у вас есть

from <module> import *

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

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

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

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

Ответы [ 6 ]

24 голосов
/ 26 августа 2010

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

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

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

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

def f():
    ...

from module import *

def g():
    ...

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

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

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

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

16 голосов
/ 26 августа 2010

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

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

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

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

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

Пространства имен - это одна из замечательных идей - давайте сделаем еще больше!

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

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

12 голосов
/ 26 августа 2010

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

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

4 голосов
/ 26 августа 2010

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

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

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

  1. может привести к импорту имен, о которых вы не знаете, и к удалению локальных имен
  2. вы не можете знать, что используется в вашем коде, трудно понять зависимости скрипта
  3. завершение кода больше не будет работать правильно
  4. Удобные проверки IDE типа "эта переменная не была объявлена" больше не могут работать
  5. облегчает создание кругового импорта
1 голос
/ 26 августа 2010

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

0 голосов
/ 26 августа 2010

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

...