Чи слід використовувати `import os.path` або` import os`?


139

Згідно з офіційною документацією , os.pathце модуль. Отже, який є кращим способом імпорту?

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

Або ...

# Is importing os enough?
import os

Будь ласка, не відповідайте "імпорт osтворів для мене". Я знаю, він працює для мене і зараз (як у Python 2.6). Я хочу знати будь-які офіційні рекомендації щодо цього питання. Отже, якщо ви відповідаєте на це запитання, будь ласка, опублікуйте свої довідки .

Відповіді:


157

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 .
Майк Грехем

1
Нічого собі, os.pyвсе-таки вводиться sys.modules['os.path']. Тому це from os.path import somethingнасправді працює. Мені було цікаво, коли це було введено та перевірено джерело. Веселий факт: це з 1999 року, вперше включений у Python 1.5.2. Оригінальний комітет тут .
Блюхорн

29

Відповідно до PEP-20 Тим Петерс, "Явне краще, ніж неявне" та "Читання читається". Якщо все , що вам потрібно від osмодуля під os.path, import os.pathбуде більш явним , і нехай інші знають , що ви дійсно дбаєте о.

Крім того, PEP-20 також каже: "Просте краще, ніж складне", тому якщо вам також потрібні речі, які знаходяться під загальним osпарасолькою, import osбуло б кращим.


2
Я не бачу, як import osнасправді в тому, щоб бути "простим" будь-яким змістовним чином. Просте! = Коротке.
Майк Грехем

14
Я більше намагався зазначити, що import os і a, import os.pathце даф, якщо вам, наприклад, потрібно os.getcwd()іos.path.isfile()
Nick T

15

Остаточна відповідь: 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).
...

13
Зауважте, що це не документи для os.pathмодуля, який не існує, а для posixpath.
WRAR

18
Це зовсім не так, як я вважаю, що docstring мається на увазі інтерпретуватись, хоча це досить оману. Майте на увазі , що пропозиція "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

1
Я згоден з більшістю коментарів @flornquake, але не згоден з останнім реченням. І posixpath.py, і ntpath.py кажуть "імпортувати os та посилаються на цей модуль як os.path". Вони не кажуть "імпортувати os.path і посилаються на цей модуль як os.path". macpath.py нічого не має з цього приводу.
Піт Форман

3
Це хороший приклад показу, як документ, що містить цей покажчик, може вводити в оману: 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зробить дзвінки до шляху ще швидшими, якщо швидкість буде проблемою.
Джастін Піл

Будучи пітонічним, явним краще, ніж неявне право? Насправді я думаю, що це дійсно вирок користувачеві, чи користувач лише буде використовувати os.path або декілька модулів в межах os. Може бути, один метод більше відповідає вашій філософії над іншим?
Ендрю Коу

23
Час цього є деякою з передчасної передчасної оптимізації, яку я коли-небудь бачив. Це ніколи не було нічиїм вузьке місце і час тут байдуже , як хто - то повинен закодувати.
Майк Грехем

5

Тут діє здоровий глузд: osце модуль і os.pathтеж модуль. Тому просто імпортуйте модуль, який ви хочете використовувати:

  • Якщо ви хочете використовувати функції в osмодулі, то імпортуйте os.

  • Якщо ви хочете використовувати функції в os.pathмодулі, то імпортуйте os.path.

  • Якщо ви хочете використовувати функції в обох модулях, то імпортуйте обидва модулі:

    import os
    import os.path

Довідково:


4

Не вдалося знайти жодної остаточної посилання, але я бачу, що приклад коду для os.walk використовує os.path, але лише імпортує os

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.