Используйте "импорт модуля" или "из импорта модуля"?


Я попытался найти полное руководство о том, лучше ли использовать import module или from module import? Я просто начал с Python и я пытаюсь начать с лучших практик в виду.

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

13 264

13 ответов:

разницу между import module и from module import foo в основном субъективные. Выберите тот, который вам больше всего нравится, и будьте последовательны в его использовании. Вот некоторые моменты, которые помогут вам решить.

import module

  • плюсы:
    • меньше обслуживания вашего import заявления. Не нужно добавлять никаких дополнительных импорта, чтобы начать использовать другой элемент из модуль
  • плюсы:
    • введя module.foo в вашем коде может быть утомительным и избыточным (скука может быть сведена к минимуму с помощью import module as mo введя mo.foo)

from module import foo

  • плюсы:
    • меньше ввода для использования foo
    • больше контроля над тем, какие элементы модуля могут быть доступ
  • плюсы:
    • использовать новый элемент из модуля вы должны обновить свой import сообщении
    • вы теряете контекст о foo. Например, менее понятно, что ceil() не по сравнению с math.ceil()

любой метод приемлем, но не использовать from module import *.

для любого разумного большого набора кода, если вы import * вы вероятно, будет цементировать его в модуль, не может быть удален. Это связано с тем, что трудно определить, какие элементы, используемые в коде, поступают из "модуля", что позволяет легко добраться до точки, где вы думаете, что не используете import больше, но это очень трудно быть уверенным.

здесь есть еще одна деталь, не упомянутая, связанная с записью в модуль. Конечно, это может быть не очень распространено, но мне это нужно время от времени.

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

модуль foo:

bar = "apples"

модуль а:

import foo
foo.bar = "oranges"   # update bar inside foo module object

модуль b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

однако, если вы импортируете имена символов вместо имен модулей, это не будет работать.

например, если я делаю это в модуле:

from foo import bar
bar = "oranges"

никакой код за пределами a не будет видеть бар как "апельсины", потому что моя настройка бара просто повлияла на имя" бар "внутри модуля a, он не" достиг "объекта модуля foo и не обновил его"бар".

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

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

  • from module import ...: приятно, что импортированные элементы можно использовать непосредственно без префикса имени модуля. Недостатком является то, что вы должны перечислить каждую вещь, которую вы используете, и что это не ясно в коде, где что-то пришло оттуда.

что использовать зависит от того, что делает код понятным и читаемым, и имеет более чем мало общего с личными предпочтениями. Я наклоняюсь к import module Как правило, потому что в коде очень ясно, откуда появился объект или функция. Я использую from module import ... когда я использую какой-то объект/функцию a много в коде.

хотя многие люди уже объяснили про import vs import from, я хочу попытаться объяснить немного больше о том, что происходит под капотом, и где все места, которые он меняет.


import foo:

импорт foo, и создается ссылка на этот модуль в текущем пространстве имен. Затем вам нужно определить завершенный путь модуля для доступа к определенному атрибуту или методу изнутри модуля.

например.foo.bar но не bar

from foo import bar:

импорт foo, и создает ссылки на всех участников (bar). Не устанавливает переменную foo.

например.bar а не baz или foo.baz

from foo import *:

импорт foo, и создает ссылки на все общедоступные объекты, определенные этим модулем в текущем пространстве имен (все перечисленное в __all__ если __all__ существует, иначе все, что не запускается с _). Не устанавливает переменную foo.

например.bar и baz а не _qux или foo._qux.


теперь посмотрим, когда мы это сделаем import X.Y:

>>> import sys
>>> import os.path

Регистрация sys.modules С именем os и os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Регистрация globals() и locals() пространство имен словарь с os и os.path:

 >>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

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

 >>> os
 <module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
 >>> os.path
 <module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
 >>>

а не path.

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

после удаления os из пространства имен locals() вы не сможете получить доступ к os а также os.path даже если они существуют в sys.модули:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

теперь давайте поговорим о import from:

from:

>>> import sys
>>> from os import path

Регистрация sys.modules С os и os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

мы обнаружили, что в sys.modules мы нашли так же, как и раньше, используя import name

ок, давайте проверим, как это выглядит в locals() и globals() пространство имен предсказывает:

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

вы можете получить доступ, используя имя path а не os.path:

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

давайте удалим 'path' из locals():

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

последний пример использования псевдонима:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

и путь не определен:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>

Я лично всегда использую

from package.subpackage.subsubpackage import module

а затем получить доступ ко всему, как

module.function
module.modulevar

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

Излишне говорить, что не используйте импорт *, потому что он загрязняет ваше пространство имен и не говорит вам, откуда берется данная функция (из какого модуля)

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

from package1.subpackage import module
from package2.subpackage import module

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

import module

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

from module import function

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

вот еще одно отличие не упоминается. Это скопировано дословно из http://docs.python.org/2/tutorial/modules.html

обратите внимание, что при использовании

from package import item

элемент может быть либо подмодулем (или подпакетом) пакета, либо каким-либо другим именем, определенным в пакете, например функцией, классом или переменной. Оператор import сначала проверяет, определен ли элемент в пакете; если нет, он предполагает, что это модуль и пытается загрузить его. Если это не удается найти его, возникает исключение ImportError.

наоборот, при использовании синтаксиса типа

import item.subitem.subsubitem

каждый элемент, кроме последнего, должен быть пакетом; последний элемент может быть модулем или пакетом, но не может быть классом, функцией или переменной, определенной в предыдущем элементе.

я только что обнаружил еще одно тонкое различие между этими двумя методами.

если модуль foo использует следующий импорт:

from itertools import count

модуль bar может по ошибке использовать count как будто это было определено в foo, не itertools:

import foo
foo.count()

если foo применение:

import itertools

ошибка все еще возможна, но с меньшей вероятностью будет сделана. bar нужно:

import foo
foo.itertools.count()

это вызвало некоторые проблемы для меня. У меня был модуль, который по ошибке импортировал исключение из модуля, который не определял его, только импортировал его из другого модуля (используя from module import SomeException). Когда импорт больше не был нужен и удален, оскорбительный модуль был сломан.

добавить к тому, что люди говорят о from x import *: кроме того, что делает его более трудным, чтобы сказать, откуда пришли имена, это отбрасывает кодовые шашки, такие как Pylint. Они будут сообщать эти имена как неопределенные переменные.

import package
import module

С import, токен должен быть модулем (файл, содержащий команды Python) или пакетом (папка в sys.path, содержащий файл __init__.py.)

когда есть подпакеты:

import package1.package2.package
import package1.package2.module

требования к папке (пакету) или файлу (модулю) одинаковы, но папка или файл должны быть внутри package2, который должен быть внутри package1, а как package1 и package2 должен содержать __init__.py файлы. https://docs.python.org/2/tutorial/modules.html

С from стиль импорт:

from package1.package2 import package
from package1.package2 import module

пакет или модуль входит в пространство имен файла, содержащего import заявление module (или package) вместо package1.package2.module. Вы всегда можете привязать к более удобному имени:

a = big_package_name.subpackage.even_longer_subpackage_name.function

только from стиль импорта позволяет вам назвать определенную функцию или переменную:

from package3.module import some_function

разрешено, но

import package3.module.some_function 

не допускается.

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

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

так как я тоже новичок, я буду пытаться объяснить это в простой форме: В Python, у нас есть три типа import инструкции:

1. Общий импорт:

import math

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

math.sqrt(4)

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

усилие ввода может быть дополнительно уменьшено с помощью этого оператора импорта:

import math as m

теперь, вместо того, чтобы использовать math.sqrt() можно использовать m.sqrt().

2. Функция импорт:

from math import sqrt

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

3. Универсальный импорт:

from math import 

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

если у вас есть функция с вашим собственным именем sqrt и вы импортируете математику, ваша функция безопасна: есть ваш sqrt и есть математика.функция sqrt. Если вы делаете из math import *, однако, у вас есть проблема: а именно, две разные функции с одинаковым именем. Источник:Codecademy

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

импорт модуля из-Меньше ввода и больше контроля над тем, какие элементы модуля могут быть accessed.To используйте новый элемент из модуля, который необходимо обновить оператор импорта.