Меня немного смущает множество способов импорта модулей в Python.
import X
import X as Y
from A import B
Я читал об области видимости и пространствах имен, но мне хотелось бы получить несколько практических советов о том, какая стратегия является лучшей, при каких обстоятельствах и почему. Должен ли импорт происходить на уровне модуля или на уровне метода / функции? В __init__.py или в самом коде модуля?
На мой вопрос "Пакеты Python - импорт по классам, а не по файлам" не ответил, хотя, очевидно, он связан.
См. stackoverflow.com/questions/186472/…






Обычно я бы использовал import X на уровне модуля. Если вам нужен только один объект из модуля, используйте from X import Y.
Используйте import X as Y только в том случае, если вы иначе столкнетесь с конфликтом имен.
Я использую импорт только на уровне функций для импорта того, что мне нужно, когда модуль используется в качестве основного модуля, например:
def main():
import sys
if len(sys.argv) > 1:
pass
HTH
В производственном кодексе нашей компании мы стараемся придерживаться следующих правил.
Мы помещаем импорт в начало файла сразу после строки документации основного файла, например:
"""
Registry related functionality.
"""
import wx
# ...
Теперь, если мы импортируем класс, который является одним из немногих в импортированном модуле, мы импортируем имя напрямую, так что в коде нам нужно использовать только последнюю часть, например:
from RegistryController import RegistryController
from ui.windows.lists import ListCtrl, DynamicListCtrl
Однако есть модули, которые содержат десятки классов, например список всех возможных исключений. Затем мы импортируем сам модуль и ссылаемся на него в коде:
from main.core import Exceptions
# ...
raise Exceptions.FileNotFound()
Мы используем import X as Y как можно реже, потому что это затрудняет поиск использования того или иного модуля или класса. Однако иногда вам нужно использовать его, если вы хотите импортировать два класса с одинаковым именем, но существующие в разных модулях, например:
from Queue import Queue
from main.core.MessageQueue import Queue as MessageQueue
Как правило, мы не импортируем внутри методов - они просто делают код медленнее и менее читабельным. Некоторым это может показаться хорошим способом решения проблемы циклического импорта, но лучшим решением является реорганизация кода.
«они просто делают код медленнее» - это не так. Это было протестировано здесь: stackoverflow.com/a/4789963/617185
import X as Y полезен, если у вас есть разные реализации одного и того же модуля / класса.
С некоторыми вложенными try..import..except ImportError..import вы можете скрыть реализацию от своего кода. См. Пример импорта lxml etree:
try:
from lxml import etree
print("running with lxml.etree")
except ImportError:
try:
# Python 2.5
import xml.etree.cElementTree as etree
print("running with cElementTree on Python 2.5+")
except ImportError:
try:
# Python 2.5
import xml.etree.ElementTree as etree
print("running with ElementTree on Python 2.5+")
except ImportError:
try:
# normal cElementTree install
import cElementTree as etree
print("running with cElementTree")
except ImportError:
try:
# normal ElementTree install
import elementtree.ElementTree as etree
print("running with ElementTree")
except ImportError:
print("Failed to import ElementTree from any known place")
Обычно я стараюсь использовать обычный import modulename, если имя модуля не длинное или не используется часто.
Например, я бы сделал ..
from BeautifulSoup import BeautifulStoneSoup as BSS
.. так что я могу сделать soup = BSS(html) вместо BeautifulSoup.BeautifulStoneSoup(html)
Или же..
from xmpp import XmppClientBase
.. вместо импорта всего xmpp, когда я использую только XmppClientBase
Использование import x as y удобно, если вы хотите импортировать либо очень длинные имена методов, либо предотвратить затирание существующего импорта / переменной / класса / метода (чего вам следует избегать полностью, но это не всегда возможно)
Скажем, я хочу запустить функцию main () из другого скрипта, но у меня уже есть функция main () ..
from my_other_module import main as other_module_main
..не удалось заменить мою функцию main на main my_other_module
О, одно - не делайте from x import * - это затрудняет понимание вашего кода, так как вы не можете легко увидеть, откуда появился метод (from x import *; from y import *; my_func() - где определен my_func?)
Во всех случаях вы мог просто выполняете import modulename, а затем modulename.subthing1.subthing2.method("test") ...
Материал from x import y as z создан исключительно для удобства - используйте его всякий раз, когда он упростит чтение или запись кода!
IMHO, здесь есть некоторые заблуждения ... 1) "импорт всего xmpp, когда я использую только ...": это ложно подразумевает, что этот подход «легче», но Python все равно загрузит и инициализирует весь модуль, независимо от того, сколько объектов вы импортировали. Что касается «загрязнения пространства имен», оба добавят запись не замужем в локальное пространство имен: xmpp или XmppClientBase. Так что это обоснование недействительно
2) "поскольку вы не можете легко увидеть, откуда появился метод": верно для * импорта, но также верно для вашего подхода к использованию as только для сокращения имени модуля / объекта. Откуда взялся BSS()? Использование from также страдает (немного) от этого: from mymod import MyClass. Теперь на 300 строк впереди вы видите class MyOtherClass(MyClass): ... откуда снова взялся MyClass? Читатель вынужден всегда возвращаться к заголовку, чтобы проверить, откуда какой объект был импортирован.
Другие рассмотрели здесь большую часть вопросов, но я просто хотел добавить один случай, когда я буду использовать import X as Y (временно), когда я пробую новую версию класса или модуля.
Итак, если мы переходили на новую реализацию модуля, но не хотели сокращать базу кода сразу, мы могли бы написать модуль xyz_new и сделать это в исходных файлах, которые мы перенесли:
import xyz_new as xyz
Затем, как только мы сократим всю кодовую базу, мы просто заменим модуль xyz на xyz_new и вернем весь импорт обратно на
import xyz
НЕ делайте этого:
from X import *
за исключением случаев, когда вы абсолютно уверены, что будете использовать все элементы этого модуля. И даже тогда вам, вероятно, следует пересмотреть вариант использования другого подхода.
В остальном это просто вопрос стиля.
from X import Y
это хорошо и избавляет вас от лишнего набора текста. Я обычно использую это, когда что-то в нем использую довольно часто. Но если вы много импортируете из этого модуля, вы можете получить оператор импорта, который выглядит так:
from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P
Вы уловили идею. Вот когда импорт вроде
import X
стать полезным. Либо так, либо если я на самом деле ничего не использую в X очень часто.
'from X import *' имеет свое применение - например, с pyparsing.
Я согласен. Но в целом это плохая привычка. Ничто не раздражает меня больше, чем необходимость отслеживать, какая функция от какого модуля пришла, потому что есть много операторов from x import * type.
Позвольте мне просто вставить часть разговора в список рассылки django-dev, начатый Гвидо ван Россумом:
[...] For example, it's part of the Google Python style guides[1] that all imports must import a module, not a class or function from that module. There are way more classes and functions than there are modules, so recalling where a particular thing comes from is much easier if it is prefixed with a module name. Often multiple modules happen to define things with the same name -- so a reader of the code doesn't have to go back to the top of the file to see from which module a given name is imported.
Источник:http://groups.google.com/group/django-developers/browse_thread/thread/78975372cdfb7d1a
1: http://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports
ИМО, это должен быть предпочтительный способ импорта вещей, особенно в крупных проектах.
Если у вас есть хорошо написанная библиотека, что иногда бывает в Python, вам следует просто импортировать ее и использовать как нее. Хорошо написанная библиотека имеет тенденцию отнимать жизнь и собственный язык, что приводит к приятному для чтения коду, когда вы редко ссылаетесь на библиотеку. Когда библиотека хорошо написана, вам не нужно слишком часто переименовывать или что-то еще.
import gat
node = gat.Node()
child = node.children()
Иногда это невозможно написать таким образом, или вам нужно извлечь что-то из импортированной вами библиотеки.
from gat import Node, SubNode
node = Node()
child = SubNode(node)
Иногда вы делаете это для многих вещей, если ваша строка импорта превышает 80 столбцов, это хорошая идея:
from gat import (
Node, SubNode, TopNode, SuperNode, CoolNode,
PowerNode, UpNode
)
Лучшая стратегия - держать весь этот импорт в верхней части файла. Предпочтительно упорядочивать в алфавитном порядке, сначала - операторы импорта, затем - операторы импорта.
Теперь я скажу вам, почему это лучший съезд.
Python вполне мог иметь автоматический импорт, который искал бы значение из основного импорта, если его нельзя найти в глобальном пространстве имен. Но это плохая идея. Я кратко объясняю почему. Помимо того, что его сложнее реализовать, чем простой импорт, программисты не будут так много думать о зависимостях и выяснять, откуда вы импортировали что-то, нужно делать другим способом, чем просто смотреть на импорт.
Необходимость выяснить зависимости - одна из причин, по которой люди ненавидят "from ... import *". Однако существуют некоторые плохие примеры, когда вам нужно это сделать, например opengl -wrappings.
Таким образом, определения импорта действительно ценны как определение зависимостей программы. Это то, как вы должны их использовать. Из них вы можете быстро просто проверить, откуда импортирована какая-то странная функция.
Я с Джейсоном в том, что не использую
from X import *
Но в моем случае (я не опытный программист, поэтому мой код не слишком хорошо соответствует стилю кодирования) я обычно делаю в своих программах файл со всеми константами, такими как версия программы, авторы, сообщения об ошибках и все такое, поэтому файл - это просто определения, затем я делаю импорт
from const import *
Это экономит мне много времени. Но это единственный файл, который имеет такой импорт, и это потому, что все внутри этого файла - просто объявления переменных.
Такой импорт в файл с классами и определениями может быть полезен, но когда вам нужно прочитать этот код, вы тратите много времени на поиск функций и классов.
Кто-то выше сказал, что
from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P
эквивалентно
import X
import X позволяет напрямую изменять A-P, а from X import ... создает копии A-P. Для from X import A..P вы не получаете обновления переменных, если они изменяются. Если вы их изменяете, вы изменяете только свою копию, но X знает о ваших изменениях.
Если A-P - это функции, вы не заметите разницы.
В частности, если вы хотите использовать mock в модульных тестах, чтобы имитировать, скажем, X.A, то это работает, только если вы использовали import X.
См. stackoverflow.com/questions/187453/…