Почему "импорт" плохой?

В Python рекомендуется использовать import *.

Может ли кто-нибудь объяснить причину этого, чтобы я мог избежать этого в следующий раз?

Ответ 1

  • Потому что он помещает много материала в ваше пространство имен (может тень другого объекта из предыдущего импорта, и вы не узнаете об этом).

  • Поскольку вы не знаете точно, что импортировано и не может легко найти, из какого модуля была импортирована определенная вещь (читаемость).

  • Поскольку вы не можете использовать классные инструменты, такие как pyflakes, чтобы статически обнаруживать ошибки в вашем коде.

Ответ 2

Согласно дзену питона:

Явное лучше, чем неявное.

... не могу с этим поспорить, конечно?

Ответ 3

Вы не проходите **locals() к функциям, не так ли?

Так как Python не имеет оператора include, а параметр self является явным, а правила определения области действия довольно просты, обычно очень легко указать палец на переменную и указать, откуда этот объект - без чтения другие модули и без какой-либо IDE (которые в любом случае ограничены методом интроспекции, поскольку язык очень динамичен).

import * ломает все это.

Кроме того, у него есть конкретная возможность скрывать ошибки.

import os, sys, foo, sqlalchemy, mystuff
from bar import *

Теперь, если в баровом модуле есть какие-либо атрибуты "os", "mystuff" и т.д., они переопределяют явно импортированные и, возможно, указывают на очень разные вещи. Определение __all__ в баре часто бывает мудрым - это указывает на то, что имплицитно будет импортировано, но все равно трудно отслеживать, откуда возникают объекты, без чтения и разбора модуля бара и после его импорта. Сеть import * - это первое, что я исправляю, когда я беру на себя ответственность за проект.

Не поймите меня неправильно: если бы import * отсутствовали, я бы заплакал, чтобы получить его. Но его нужно использовать осторожно. Хорошим вариантом является предоставление интерфейса фасада над другим модулем. Аналогично, использование условных операторов импорта или импорт внутри пространств имен функций/классов требует некоторой дисциплины.

Я думаю, что в средних и крупных проектах или небольших с несколькими вкладчиками минимальная гигиена необходима с точки зрения статического анализа - при использовании, по крайней мере, пеплета или даже лучше правильно настроенной пилинга, - чтобы поймать несколько видов ошибок до того, как они произойдут.

Конечно, поскольку это python - не стесняйтесь нарушать правила и исследовать - но будьте осторожны с проектами, которые могут расти в десять раз, если исходный код отсутствует в дисциплине, это будет проблемой.

Ответ 4

Это потому, что вы загрязняете пространство имен. Вы импортируете все функции и классы в свое собственное пространство имен, которое может столкнуться с функциями, которые вы сами определяете.

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

В модуле foo:

def myFunc():
    print 1

В вашем коде:

from foo import *

def doThis():
    myFunc() # Which myFunc is called?

def myFunc():
    print 2

Ответ 5

В интерактивном сеансе можно выполнить from ... import *.

Ответ 6

http://docs.python.org/tutorial/modules.html

Обратите внимание, что в целом практика импорта * из модуля или пакета неодобрилась, поскольку часто вызывает плохо читаемый код.

Ответ 7

Скажем, у вас есть следующий код в модуле foo:

import ElementTree as etree

а затем в вашем собственном модуле вы:

from lxml import etree
from foo import *

Теперь у вас есть сложный для отладки модуль, который выглядит так, как будто в нем есть lxml etree, но на самом деле имеет ElementTree.

Ответ 8

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

Я преподаю детям (около 8 лет) программировать на Python, чтобы манипулировать Minecraft. Мне нравится предоставлять им полезную среду кодирования для работы с (Atom Editor) и преподавать REPL-ориентированную разработку (через bpython). В Atom я обнаружил, что подсказки/завершение работают так же эффективно, как и bpython. К счастью, в отличие от некоторых других инструментов статистического анализа Atom не обманывается import *.

Однако, давайте возьмем этот пример... В этой обертке они from local_module import * объединяют модули, включая этот список блоков. Пусть игнорируют риск конфликтов пространства имен. Делая from mcpi.block import *, они делают весь этот список неясных типов блоков тем, что вам нужно посмотреть, чтобы узнать, что доступно. Если бы они использовали from mcpi import block, то вы могли бы ввести walls = block., а затем появится список автозаполнения. Снимок экрана Atom.io

Ответ 9

Понял действительные точки, которые люди здесь поставили. Тем не менее, у меня есть один аргумент, что иногда "звездный импорт" не всегда может быть плохой практикой:

  • Когда я хочу структурировать свой код таким образом, чтобы все константы переходили в модуль с именем const.py:
    • Если я import const, то для каждой константы я должен ссылаться на нее как const.SOMETHING, что, вероятно, не самый удобный способ.
    • Если я делаю from const import SOMETHING_A, SOMETHING_B..., то, очевидно, это слишком многословно и побеждает цель структурирования.
    • Таким образом, я чувствую, что в этом случае выполнение from const import * может быть лучшим выбором.

Ответ 10

Практика очень низкая по двум причинам:

  • Чтение кода
  • Риск переопределения переменных/функций и т.д.

Для точки 1: Рассмотрим пример:

from module1 import *
from module2 import *
from module3 import *

a = b + c - d

Здесь, увидев код, никто не получит представление о том, из какого модуля b, c и d действительно принадлежит.

С другой стороны, если вы это сделаете:

#                   v  v  will know that these are from module1
from module1 import b, c   # way 1
import module2             # way 2

a = b + c - module2.d
#            ^ will know it is from module2

Это намного более чистое для вас, а также новый человек, присоединившийся к вашей команде, будет иметь лучшую идею.

Для точки 2: пусть говорят, что как module1, так и module2 имеют переменную как b. Когда я это сделаю:

from module1 import *
from module2 import *

print b  # will print the value from module2

Здесь значение из module1 теряется. Будет сложно отлаживать, почему код не работает, даже если b объявлен в module1, и я написал код, ожидающий, что мой код будет использовать module1.b

Если у вас одинаковые переменные в разных модулях, и вы не хотите импортировать весь модуль, вы можете даже сделать:

from module1 import b as mod1b
from module2 import b as mod2b

Ответ 11

В качестве теста я создал модуль test.py с двумя функциями A и B, которые соответственно печатают "A 1" и "B 1". После импорта test.py с помощью:

import test

., Я могу запустить 2 функции, поскольку test.A() и test.B() и "test" отображаются в модуле в пространстве имен, поэтому, если я редактирую test.py, я могу перезагрузить его с:

import importlib
importlib.reload(test)

Но если я сделаю следующее:

from test import *

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

import test
import test as tt

добавит "test" или "tt" (соответственно) в качестве имен модулей в пространстве имен, что позволит перезагрузить.

Если я это сделаю:

from test import *

имена "A" и "B" отображаются в пространстве имен как функции. Если я отредактирую test.py и повторю вышеприведенную команду, измененные версии функций не будут перезагружены.

И следующая команда вызывает сообщение об ошибке.

importlib.reload(test)    # Error - name 'test' is not defined

Если кто-то знает, как перезагрузить модуль, загруженный с "из импорта модуля", отправьте сообщение. В противном случае это было бы еще одной причиной, чтобы избежать формы:

from module import *

Ответ 12

Как предлагается в документации, вы никогда не должны использовать import * в производственном коде.

В то время как импорт * из модуля плох, импорт * из пакета еще хуже. По сути, from package import * импортируется любое имя, определенное пакетом __init__.py, но оно также включает любые подмодули пакета, которые были загружены предыдущими операторами import.

Рассмотрим этот пример:

# anywhere in the code before import *
import sound.effects.echo
import sound.effects.surround

# in your module
from sound.effects import *

Последний оператор импортирует модули echo и surround в текущее пространство имен (возможно, переопределяя предыдущие определения), потому что они определены в пакете sound.effects при выполнении оператора import.