Каковы практические правила импорта Python?

Меня немного смущает множество способов импорта модулей в Python.

import X
import X as Y
from A import B

Я читал об области видимости и пространствах имен, но мне хотелось бы получить несколько практических советов о том, какая стратегия является лучшей, при каких обстоятельствах и почему. Должен ли импорт происходить на уровне модуля или на уровне метода / функции? В __init__.py или в самом коде модуля?

На мой вопрос "Пакеты Python - импорт по классам, а не по файлам" не ответил, хотя, очевидно, он связан.

См. stackoverflow.com/questions/187453/…

S.Lott 11.10.2008 14:33

См. stackoverflow.com/questions/186472/…

S.Lott 11.10.2008 14:35
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
72
2
50 353
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Обычно я бы использовал 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

kmonsoor 08.06.2015 10:17

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. Так что это обоснование недействительно

MestreLion 13.04.2012 23:46

2) "поскольку вы не можете легко увидеть, откуда появился метод": верно для * импорта, но также верно для вашего подхода к использованию as только для сокращения имени модуля / объекта. Откуда взялся BSS()? Использование from также страдает (немного) от этого: from mymod import MyClass. Теперь на 300 строк впереди вы видите class MyOtherClass(MyClass): ... откуда снова взялся MyClass? Читатель вынужден всегда возвращаться к заголовку, чтобы проверить, откуда какой объект был импортирован.

MestreLion 13.04.2012 23:57

Другие рассмотрели здесь большую часть вопросов, но я просто хотел добавить один случай, когда я буду использовать 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.

John Fouhy 13.10.2008 01:44

Я согласен. Но в целом это плохая привычка. Ничто не раздражает меня больше, чем необходимость отслеживать, какая функция от какого модуля пришла, потому что есть много операторов from x import * type.

Jason Baker 13.10.2008 02:44

Позвольте мне просто вставить часть разговора в список рассылки 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

ИМО, это должен быть предпочтительный способ импорта вещей, особенно в крупных проектах.

Priidu Neemre 07.10.2014 20:23

Если у вас есть хорошо написанная библиотека, что иногда бывает в 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.

RemcoGerlich 17.12.2013 16:26

Другие вопросы по теме