Использовать «модуль импорта» или «из модуля импорта»? - PullRequest
327 голосов
/ 02 апреля 2009

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

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

Ответы [ 13 ]

396 голосов
/ 02 апреля 2009

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

108 голосов
/ 04 октября 2013

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

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

модуль 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 не будет видеть панель как "апельсины", потому что мои настройки bar просто повлияли на имя "bar" внутри модуля a, она не "достигла" объекта модуля foo и не обновила его "bar".

57 голосов
/ 04 февраля 2014

Несмотря на то, что многие уже рассказывали о 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 из пространства имен locals () вы не сможете получить доступ к 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'
>>>
38 голосов
/ 02 апреля 2009

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

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

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

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

32 голосов
/ 02 апреля 2009

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

from package.subpackage.subsubpackage import module

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

module.function
module.modulevar

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

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

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

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

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

14 голосов
/ 02 апреля 2009
import module

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

from module import function

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

7 голосов
/ 16 января 2014

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

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

from package import item

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

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

import item.subitem.subsubitem

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

6 голосов
/ 22 мая 2013

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

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

4 голосов
/ 05 мая 2018

Поскольку я тоже начинающий, я попытаюсь объяснить это простым способом: В 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

4 голосов
/ 22 февраля 2015
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 

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

...