Что я должен использовать: import os.path или import os?

143

Согласно официальной документации , os.pathэто модуль. Итак, какой способ импорта предпочтительнее?

# Should I always import it explicitly?
import os.path

Или...

# Is importing os enough?
import os

Пожалуйста, НЕ отвечайте на "импорт osработает у меня". Я знаю, у меня это тоже работает прямо сейчас (начиная с Python 2.6). Я хочу знать любые официальные рекомендации по этому поводу. Итак, если вы ответите на этот вопрос, разместите , пожалуйста, свои ссылки .

Денилсон Са Майя
источник

Ответы:

165

os.pathработает забавно. Похоже, это osдолжен быть пакет с подмодулем path, но на самом деле osэто обычный модуль, который творит чудеса с sys.modulesинъекцией os.path. Вот что происходит:

  • Когда Python запускается, он загружает кучу модулей в sys.modules. Они не привязаны к каким-либо именам в вашем скрипте, но вы можете получить доступ к уже созданным модулям, когда вы каким-либо образом их импортируете.

    • sys.modulesэто диктовка, в которой кэшируются модули. Когда вы импортируете модуль, если он уже был куда-то импортирован, он получает экземпляр, хранящийся в sys.modules.
  • osвходит в число модулей, загружаемых при запуске Python. Он назначает свой pathатрибут специфичному для ОС модулю пути.

  • Он внедряет sys.modules['os.path'] = pathтак, чтобы вы могли " import os.path" делать " ", как если бы это был подмодуль.

Я склонен думать , os.pathкак модуль я хочу использовать , а не вещь в osмодуле , так что даже если это не очень подмодуль пакета называется os, я импортировать его вроде как это один и я всегда делаюimport os.path . Это согласуется с тем, как os.pathдокументируется.


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

  1. Если вы думаете о osпакете и знаете, что можете делать import osи иметь доступ к подмодулю os.path, вы можете быть удивлены позже, когда не сможете сделать import twistedи автоматически получить доступ twisted.spreadбез его импорта.

  2. Сбивает с толку, что os.nameэто обычная вещь, строка, а os.pathэто модуль. Я всегда структурирую свои пакеты с пустыми __init__.pyфайлами, чтобы на одном уровне у меня всегда был один тип вещей: модуль / пакет или другие вещи. Этот подход используется в нескольких крупных проектах Python, направленных на создание более структурированного кода.

Майк Грэм
источник
Отличный, очень информативный ответ! Поздравляю! Хотя он не дает прямого ответа на вопрос, в нем есть много полезных деталей. Но не могли бы вы уточнить: «Это согласуется с тем, как документируется os.path»? Как сказал Крис Хулан, пример os.walk () импортирует только os вместо os.path.
Denilson Sá Maia
3
@Denilson, там есть прямой ответ: я всегда делаю import os.pathсам и думаю, что это более приятный способ. Под «Это согласуется с тем, как документируется os.path» я имел в виду, что ему дается отдельная страница в документации по адресу docs.python.org/library/os.path.html .
Майк Грэм,
2
Вау, os.pyдействительно впрыскивает sys.modules['os.path']. Вот почему на from os.path import somethingсамом деле работает. Мне было любопытно, когда это было введено, и я проверил источник. Интересный факт: это с 1999 года, впервые включенное в Python 1.5.2. Оригинальный коммит здесь .
Bluehorn
28

Согласно PEP-20 Тима Петерса, «Явное лучше, чем неявное» и «Читаемость имеет значение». Если все, что вам нужно от osмодуля, находится ниже os.path, import os.pathбудет более явным и пусть другие знают, что вас действительно волнует.

Точно так же PEP-20 также говорит: «Простое лучше, чем сложное», поэтому, если вам также нужны вещи, которые находятся под более общим osзонтом, import osбудет предпочтительнее.

Ник Т
источник
2
Я не понимаю, как import osна самом деле быть «простым» в каком-либо значимом смысле. Просто! = Коротко.
Майк Грэм,
14
Я больше пытался указать на это, import os и это import os.pathглупо, если вам, например, нужно os.getcwd()иos.path.isfile()
Ник Т.
14

Окончательный ответ: import osи пользуйтесь os.path. не делайте import os.pathпрямо.

Из документации самого модуля:

>>> import os
>>> help(os.path)
...
Instead of importing this module directly, import os and refer to
this module as os.path.  The "os.path" name is an alias for this
module on Posix systems; on other systems (e.g. Mac, Windows),
os.path provides the same operations in a manner specific to that
platform, and is an alias to another module (e.g. macpath, ntpath).
...
лесмана
источник
15
Обратите внимание, что это не документация для os.pathмодуля, которого не существует, а для posixpath.
wRAR
19
Я думаю, что строка документации должна интерпретироваться совсем не так, хотя это довольно вводит в заблуждение. Имейте в виду, что предложение "Instead of importing this module directly, import os and refer to this module as os.path."находится в posixpath.py(или macpath.pyи ntpath.pyт. Д.). Я почти уверен, что они означают, что не следует import posixpath(что работает), а лучше импортировать модуль через osдля лучшей переносимости. Я не думаю , что они намерены дать рекомендации в отношении того import osили import os.pathпредпочтителен.
flornquake 05
1
Я согласен с большинством комментариев @flornquake, но не согласен с последним предложением. И posixpath.py, и ntpath.py говорят: «import os и ссылаются на этот модуль как на os.path». Они не говорят «импортировать os.path и ссылаться на этот модуль как на os.path». В macpath.py нет ничего по этому поводу.
Пит Форман
4
Это хороший пример того, как документ, содержащий указатель this, может вводить в заблуждение: D
Cyker
7

Что интересно, импорт os.path импортирует все файлы os. попробуйте следующее в интерактивной подсказке:

import os.path
dir(os)

Результат будет таким же, как если бы вы только что импортировали os. Это связано с тем, что os.path будет ссылаться на другой модуль в зависимости от того, какая у вас операционная система, поэтому python будет импортировать os, чтобы определить, какой модуль загружать для пути.

Справка

С некоторыми модулями высказывание import fooне раскрывается foo.bar, поэтому я предполагаю, что это действительно зависит от дизайна конкретного модуля.


В общем, простой импорт явных модулей, которые вам нужны, должен быть немного быстрее. На моей машине:

import os.path: 7.54285810068e-06 секунды

import os: 9.21904878972e-06 секунды

Эти времена достаточно близки, чтобы ими можно было пренебречь. Ваша программа может нуждаться в использовании других модулей osлибо сейчас, либо позже, поэтому обычно имеет смысл просто пожертвовать двумя микросекундами и использовать их, import osчтобы избежать этой ошибки в более позднее время. Я обычно поддерживаю простой импорт ОС в целом, но могу понять, почему некоторые предпочли import os.pathбы технически быть более эффективными и донести до читателей кода, что это единственная часть osмодуля, которую нужно будет использовать. По сути, в моем понимании это сводится к вопросу о стиле.

Мэтт Бём
источник
2
from os import pathвызовет path еще быстрее, если проблема в скорости.
Джастин Пил,
Будучи питоническим, явное лучше, чем неявное, верно? На самом деле я думаю, что это действительно суждение пользователя о том, собирается ли пользователь использовать только os.path или несколько модулей в операционной системе. Может быть, один метод больше соответствует вашей философии, чем другой?
Эндрю Ку
24
Выбор времени - одна из самых преждевременных оптимизаций, которые я когда-либо видел. Это никогда не было чьим- либо узким местом, и время здесь не имеет значения для того, как кто-то должен кодировать.
Майк Грэм,
5

Здесь работает здравый смысл: osэто модуль, и os.pathэто тоже модуль. Так что просто импортируйте модуль, который хотите использовать:

  • Если вы хотите использовать функции osмодуля, импортируйте os.

  • Если вы хотите использовать функции os.pathмодуля, импортируйте os.path.

  • Если вы хотите использовать функции обоих модулей, импортируйте оба модуля:

    import os
    import os.path
    

Для справки:

Cyker
источник
4

Не удалось найти какой-либо исчерпывающей ссылки, но я вижу, что пример кода для os.walk использует os.path, но импортирует только os

Крис Хулан
источник