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

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

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

Ответ 1

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

Ответ 2

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

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

модуль foo:

bar = "apples"

модуль a:

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

модуль b:

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

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

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

from foo import bar
bar = "oranges"

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

Ответ 3

Несмотря на то, что многие уже рассказывали об 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 XY:

>>> 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 из пространства имен 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

Хорошо, давайте проверим, как это выглядит в globals() пространства имен 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'
>>>

Ответ 4

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

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

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

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

Ответ 5

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

from package.subpackage.subsubpackage import module

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

module.function
module.modulevar

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

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

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

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

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

Ответ 6

import module

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

from module import function

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

Ответ 7

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

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

Ответ 8

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

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

from package import item

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

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

import item.subitem.subsubitem

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

Ответ 9

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 

не разрешено.

Ответ 10

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

Ответ 11

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

Ответ 12

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

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

Ответ 13

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

enter image description here

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

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) #does not work
print (public_variable)
public_function()
#_private_function()   #does not work

Ответ 14

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

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

Ответ 15

Есть некоторые встроенные модули, которые содержат в основном голые функции (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()

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

Ответ 16

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

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

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

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

  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 x.y с y

Example4

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

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