Использовать "модуль импорта" или "из модуля импорта"?
Я попытался найти исчерпывающее руководство о том, лучше ли использовать 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
>>>
Этот тоже работает
Ответ 17
Здесь есть две отличия:
1. только "from... import..." может импортировать имя func/class/var;
2. только если имя import func/class/var может изменить значение символов в импортированном пакете/модуле.