Использовать «модуль импорта» или «из модуля импорта»?


411

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

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


5
Я просто хотел сообщить вам, что выбранный ответ неверен. Это заявляет, что различие субъективно, тогда как есть различие. Это может привести к трудностям при обнаружении ошибок. Смотрите ответ Майкла Рэя Ловетца.
Mayou36


2
Существует огромная разница между импортом определенных именованных идентификаторов 'from module import X,Y,Zпротив'from module import * . Последнее загрязняет ваше пространство имен и может дать непредсказуемые результаты в зависимости от того, что происходит в модуле. Что еще хуже, from module import *с несколькими модулями.
SMCI

Ответы:


474

Разница между 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но в этом чрезвычайно трудно быть уверенным.


66
+1 за противодействие использованию «from module import *», оно просто загромождает пространство имен.
Кристиан Виттс

22
загромождение пространства имен - не самая проблемная часть «импорта *», это снижение читабельности: любые конфликты имен проявятся в (модульном) тестировании. Но все имена, которые вы используете в импортированном модуле, будут пустыми, без намека на то, откуда они пришли. Я абсолютно ненавижу "импорт *".
Юрген А. Эрхард

21
Разве дзен Python не говорит, что явное лучше, чем неявное?
Энтони Кох

8
from module import *может быть особенно полезно, если использовать его в качестве: if(windows):\n\t from module_win import * \n else: \n\t from module_lin import *. Тогда ваш родительский модуль может потенциально содержать независимые от ОС имена функций, если имена функций в module_lin & module_win имеют одинаковые имена. Это как условно наследовать любой класс.
Anishsane

19
@anishsane. Есть еще один способ сделать это. импортировать module_win как нибудь. Тогда всегда используйте что-
то.method_name

163

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

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

модуль foo:

bar = "apples"

модуль а:

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

модуль б:

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

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

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

from foo import bar
bar = "oranges"

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


В этом последнем примере вы все еще можете вызвать 'foo.bar = "orange" для обновления' bar 'внутри' foo '?
велосирабит

4
Нет, в последнем примере имя «foo» неизвестно
Гислен Левек

31
Этот ответ дает «верный» ответ на вопрос: в чем разница между двумя вариантами импорта
Mayou36

3
Написал какой-то фрагмент кода, чтобы доказать, что этот ответ абсолютно прав, но в чем причина этого?
Хуангбейду

Я думаю, что вы говорите, импортировать имена символов, чтобы иметь локальные переменные, но импортировать имена модулей, чтобы иметь глобальные переменные ???
WinEunuuchs2Unix

79

Несмотря на то, что многие уже рассказывали о importпротивостоянии 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из местных имен (), вы не сможете получить доступ os, а также os.pathнесмотря на то, что они существуют в sys.modules:

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

Давайте удалим «путь» из 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'
>>>

8
Хотя это многословно, это действительно лучший ответ в списке на довольно сложный вопрос. Он предоставляет реальный код, чтобы помочь объяснить тонкости «под капотом», которые более важны, чем стиль, для этой конкретной проблемы. Хотелось бы, чтобы я проголосовал за это не раз!
Майк Уильямсон

Меняет ли использование, as SYMBOLкак этот ответ работает вообще?
Максимилиан Бурзли

40

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

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

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

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


1
Есть ли способ использовать from M import Xи все же получить выгоду от использования определителей каким-то образом? Кажется, вы могли бы получить лучшее из обоих миров, если бы вы все еще могли сделать M.Xпосле этого импорта.
членистоногие

@artgropod: Kinda. Вы можете сделать class m: from something.too.long import x, y, z. Не очень рекомендую, хотя.
Ли Райан

35

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

from package.subpackage.subsubpackage import module

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

module.function
module.modulevar

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

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

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

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

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


10
В последнем случае вы всегда можете использовать: import pkgN.sub.module как modN, давая вам разные имена для каждого модуля. Вы также можете использовать шаблон 'import modulename as mod1' для сокращения длинного имени или для переключения между реализациями одного и того же API (например, модулей API DB) с одним изменением имени.
Джефф Шеннон

15
import module

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

from module import function

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


7
Конечно, единственное в глобальном пространстве имен, если вы делаете «модуль импорта», это «модуль»? Вы только загрязняете пространство имен, если делаете «from .. import *».
Джон Фухи

10

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

Если модуль 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). Когда импорт больше не был нужен и удален, нарушающий модуль был сломан.


10

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

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

from package import item

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

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

import item.subitem.subsubitem

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


Еще одна вещь, которую я заметил, заключалась в том, что если элемент также является подмодулем внутри пакета, то «из элемента импорта пакета» работает, но «пакет импорта» package.item.subitem = ... не работает с пустым init .py пакета, если только мы не иметь "элемент импорта" в файле инициализации пакета.
Амитоз Дандиана

6

Поскольку я также начинающий, я попытаюсь объяснить это простым способом: в 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 и вы импортируете math, ваша функция безопасна: есть ваш sqrt, а есть math.sqrt. Однако, если вы делаете из математического импорта *, у вас есть проблема: две разные функции с одинаковым именем. Источник: Codecademy


5
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 

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


4

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


3

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

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


1

Я обнаружил одно существенное отличие, о котором, к удивлению, никто не говорил, это то, что с помощью простого импорта вы можете получить доступ private variableи private functionsиз импортированного модуля, что невозможно с помощью оператора from-import .

введите описание изображения здесь

Код в изображении:

setting.py

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

plain_importer.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

from_importer.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work

0

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

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


0

Есть некоторые встроенные модули, которые содержат в основном голые функции ( base64 , math , os , shutil , sys , time , ...), и это определенно хорошая практика - привязывать эти голые функции к некоторому пространству имен и, таким образом, улучшать читаемость вашего код. Подумайте, насколько сложнее понять смысл этих функций без их пространства имен:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

чем когда они связаны с каким-то модулем:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

Иногда вам даже нужно пространство имен, чтобы избежать конфликтов между различными модулями ( json.load против pickle.load )


С другой стороны, есть некоторые модули, которые содержат в основном классы ( configparser , datetime , tempfile , zipfile , ...), и многие из них делают свои имена классов достаточно понятными:

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

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


0

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

У меня есть следующая структура:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

main.py:

import mod.a
import mod.b as b
from mod import c
import d

Дис.дис показывает разницу:

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

В конце они выглядят одинаково (STORE_NAME - результат в каждом примере), но это стоит отметить, если вам нужно рассмотреть следующие четыре циклических импорта:

example1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

Это работает

example2

bar/
   __init__.py
   a.py
   b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bar\a.py", line 1, in <module>
    import bar.b as b
  File "bar\b.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

Нет кости

example3

baz/
   __init__.py
   a.py
   b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baz\a.py", line 1, in <module>
    from baz import b
  File "baz\b.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

Аналогичная проблема ... но ясно, что из x import y не совпадает с import import xy как y

Example4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

Этот тоже работает


0

Это моя структура каталогов моего текущего каталога:

.  
└─a  
   └─b  
     └─c
  1. importОператор запоминает все промежуточные имена .
    Эти имена должны быть уточнены:

    In[1]: import a.b.c
    
    In[2]: a
    Out[2]: <module 'a' (namespace)>
    
    In[3]: a.b
    Out[3]: <module 'a.b' (namespace)>
    
    In[4]: a.b.c
    Out[4]: <module 'a.b.c' (namespace)>
  2. from ... import ...Заявление помнит только импортное имя .
    Это имя не должно быть квалифицированным:

    In[1]: from a.b import c
    
    In[2]: a
    NameError: name 'a' is not defined
    
    In[2]: a.b
    NameError: name 'a' is not defined
    
    In[3]: a.b.c
    NameError: name 'a' is not defined
    
    In[4]: c
    Out[4]: <module 'a.b.c' (namespace)>

  • Примечание. Конечно, я перезапустил консоль Python между шагами 1 и 2.

0

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

Модульный миф

from math import gcd
...

Использование мифа :

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

Если я импортировал gcdтолько для внутреннего использования, чтобы не раскрывать его пользователям mymath, это может быть неудобно. У меня это довольно часто, и в большинстве случаев я хочу "содержать мои модули в чистоте".

Помимо предложения Яна Вробеля немного скрыть это, используя import mathвместо этого, я начал скрывать импорт от раскрытия, используя ведущие подчеркивания:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

В более крупных проектах эта «лучшая практика» позволяет мне точно контролировать, что раскрывается для последующего импорта, а что нет. Это сохраняет мои модули в чистоте и окупается при определенном размере проекта.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.