Каковы хорошие эмпирические правила для импорта Python?

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

import X
import X as Y
from A import B

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

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

Ответ 1

В производственном кодексе в нашей компании мы стараемся соблюдать следующие правила.

Мы помещаем импорт в начале файла сразу после основного файла docstring, например:

"""
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

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

Ответ 2

Позвольте мне вставить часть разговора в список рассылки django-dev, который начал Guido van Rossum:

[...] Например, это часть руководства по стилю Google Python [1], что все импорт должен импортировать модуль, а не класс или функцию из этого модуль. Есть больше классов и функций, чем есть модулей, поэтому, вспоминая, откуда происходит определенная вещь, много проще, если он имеет префикс имени модуля. Часто несколько модулей случаются, чтобы определить вещи с тем же именем - так читатель кода не нужно возвращаться к началу файла, чтобы увидеть, из которого модуль импортирует заданное имя.

Источник: http://groups.google.com/group/django-developers/browse_thread/thread/78975372cdfb7d1a

1: http://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports

Ответ 3

Я обычно использовал бы import X на уровне модуля. Если вам нужен только один объект из модуля, используйте from X import Y.

Используйте import X as Y только в том случае, если вы столкнулись с конфликтом имени.

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

def main():
  import sys
  if len(sys.argv) > 1:
     pass

НТН

Ответ 4

Кто-то сказал выше, что

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 - это функции, вы не будете знать разницу.

Ответ 5

Другие рассмотрели большую часть работы здесь, но я просто хотел добавить один случай, когда я буду использовать import X as Y (временно), когда я попробую новую версию класса или модуля.

Итак, если мы переходим к новой реализации модуля, но не хотим каждый раз обрезать базу кода, мы можем написать модуль xyz_new и сделать это в исходных файлах, которые у нас были мигрировали:

import xyz_new as xyz

Затем, как только мы перерезаем всю базу кода, мы просто заменим модуль xyz на xyz_new и изменим все импорт обратно на

import xyz

Ответ 6

НЕ ДЕЛАЙТЕ:

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 очень часто.

Ответ 7

Обычно я пытаюсь использовать обычный import modulename, если имя модуля не длинное или часто используется.

Например, я бы сделал.

from BeautifulSoup import BeautifulStoneSoup as BSS

.. поэтому я могу сделать soup = BSS(html) вместо BeautifulSoup.BeautifulStoneSoup(html)

или..

from xmpp import XmppClientBase

.. вместо импорта всего xmpp, когда я использую только XmppClientBase

Использование import x as y удобно, если вы хотите импортировать либо очень длинные имена методов, либо предотвратить слияние существующего метода import/variable/class/(то, что вы должны пытаться полностью избежать, но это не всегда возможно)

Скажем, я хочу запустить функцию main() из другого script, но у меня уже есть функция main().

from my_other_module import main as other_module_main

.. не заменит мою функцию main на my_other_module main

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

Ответ 8

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

Лучшая стратегия заключается в том, чтобы сохранить весь этот импорт в верхней части файла. Предпочтительно упорядочивается в алфавитном порядке, сначала импортировать -значения, затем из import -statements.

Теперь я говорю вам, почему это лучшее соглашение.

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

Необходимость выяснения зависимостей является одной из причин, почему люди ненавидят "из... импорта". Некоторые плохие примеры, где вам нужно это делать, существуют, например, opengl -wrappings.

Таким образом, определения импорта действительно ценны для определения зависимостей программы. Это то, как вы должны их использовать. Из них вы можете быстро проверить, откуда импортирована какая-то странная функция.

Ответ 9

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")

Ответ 10

Я с Джейсоном в том, что не использовал

from X import *

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

from const import *

Это экономит мне много времени. Но это единственный файл, который имеет этот импорт, и потому, что все внутри этого файла являются просто объявлениями переменных.

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