Czy powinienem używać `import os.path` czy` import os`?

139

Według oficjalnej dokumentacji , os.pathjest modułem. Jaki jest zatem preferowany sposób importu?

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

Lub...

# Is importing os enough?
import os

NIE odpowiadaj „Importowanie osdziała dla mnie”. Wiem, ja też teraz działa (od Pythona 2.6). Chcę wiedzieć, jakie są oficjalne zalecenia w tej sprawie. Jeśli więc odpowiesz na to pytanie, prześlij swoje referencje .

Denilson Sá Maia
źródło

Odpowiedzi:

157

os.pathdziała w zabawny sposób. Wygląda na to, że ospowinien to być pakiet z modułem podrzędnym path, ale w rzeczywistości osjest to normalny moduł, który robi magię, sys.moduleswstrzykując os.path. Oto, co się dzieje:

  • Podczas uruchamiania Python ładuje kilka modułów do sys.modules. Nie są one powiązane z żadnymi nazwami w twoim skrypcie, ale możesz uzyskać dostęp do już utworzonych modułów, kiedy w jakiś sposób je zaimportujesz.

    • sys.modulesto dykt, w którym buforowane są moduły. Kiedy importujesz moduł, jeśli został już gdzieś zaimportowany, pobiera instancję zapisaną w sys.modules.
  • osnależy do modułów ładowanych podczas uruchamiania Pythona. Przypisuje swój pathatrybut modułowi ścieżki specyficznej dla systemu operacyjnego.

  • Wstrzykuje sys.modules['os.path'] = pathtak, że można " import os.path" robić tak, jakby to był podmoduł.

Staram się myśleć os.pathjako moduł chcę użyć zamiast rzeczy w osmodule , więc nawet jeśli nie jest to naprawdę to moduł podrzędny pakietu o nazwie os, importować go coś jak to jest jeden i zawsze robięimport os.path . Jest to zgodne z sposobem os.pathudokumentowania.


Nawiasem mówiąc, ten rodzaj struktury prowadzi do wielu wczesnych zamieszania programistów Pythona dotyczących modułów i pakietów oraz organizacji kodu. Dzieje się tak naprawdę z dwóch powodów

  1. Jeśli myślisz o ospakiecie i wiesz, że możesz zrobić import osi mieć dostęp do modułu podrzędnego os.path, możesz być później zaskoczony, że nie możesz tego zrobić import twistedi automatycznie uzyskać dostęp twisted.spreadbez importowania go.

  2. To jest mylące, że os.namejest to normalna rzecz, ciąg znaków i os.pathmoduł. Zawsze strukturyzuję swoje pakiety za pomocą pustych __init__.pyplików, tak aby na tym samym poziomie zawsze mieć jeden typ: moduł / pakiet lub inne rzeczy. Kilka dużych projektów Pythona stosuje to podejście, które ma tendencję do tworzenia bardziej ustrukturyzowanego kodu.

Mike Graham
źródło
Doskonała, bardzo pouczająca odpowiedź! Gratulacje! Chociaż nie odpowiada bezpośrednio na pytanie, zawiera wiele przydatnych szczegółów. Ale czy mógłbyś rozwinąć temat „Jest to zgodne z sposobem dokumentowania os.path”? Jak powiedział Chris Hulan, przykład os.walk () importuje tylko os zamiast os.path.
Denilson Sá Maia
3
@Denilson, zawiera bezpośrednią odpowiedź: zawsze robię to import os.pathsam i uważam, że to lepszy sposób. Przez „Jest to zgodne z dokumentacją os.path”, miałem na myśli, że ma on swoją własną stronę w dokumentacji pod adresem docs.python.org/library/os.path.html .
Mike Graham
1
Wow, os.pyrzeczywiście wstrzykuje do sys.modules['os.path']. Dlatego właśnie from os.path import somethingdziała. Byłem ciekawy, kiedy to zostało wprowadzone i sprawdziłem źródło. Ciekawostka: pochodzi z 1999 roku, po raz pierwszy dołączony do Pythona 1.5.2. Oryginalne zatwierdzenie jest tutaj .
Bluehorn,
29

Zgodnie z PEP-20 autorstwa Tima Petersa, „Wyraźne jest lepsze niż niejawne” i „Czytelność liczy się”. Jeśli wszystko, czego potrzebujesz z osmodułu, jest poniżej os.path, import os.pathbyłoby to bardziej szczegółowe i daj innym znać, na czym naprawdę Ci zależy.

Podobnie PEP-20 mówi również, że „proste jest lepsze niż złożone”, więc jeśli potrzebujesz również rzeczy, które znajdują się pod bardziej ogólnym osparasolem, import osbyłoby preferowane.

Nick T.
źródło
2
Nie rozumiem, jak import osnaprawdę można być „prostym” w jakikolwiek znaczący sposób. Proste! = Krótkie.
Mike Graham
14
Byłem bardziej stara się podkreślić, że import os iimport os.path jest stuknięty, jeśli np potrzeby os.getcwd()ios.path.isfile()
Nick T
15

Ostateczna odpowiedź: import osi użyj os.path. nie import os.pathbezpośrednio.

Z dokumentacji samego modułu:

>>> 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).
...
lesmana
źródło
13
Zauważ, że nie jest to dokumentacja dla os.pathmodułu, który nie istnieje, ale dla posixpath.
WRAR
18
Wcale nie tak uważam, że należy interpretować ten ciąg dokumentów, chociaż jest to dość mylące. Należy pamiętać, że zdanie "Instead of importing this module directly, import os and refer to this module as os.path."znajduje się posixpath.py(lub macpath.py, ntpath.pyitd.). Jestem prawie pewien, że mają na myśli to, że nie należy import posixpath(co działa), ale raczej zaimportować moduł przez, osaby zapewnić lepszą przenośność. Nie sądzę, że mają zamiar dać zalecenie, czy import osczy import os.pathjest to korzystne.
flornquake
1
Zgadzam się z większością komentarzy @flornquake, ale nie zgadzam się z ostatnim zdaniem. Zarówno posixpath.py, jak i ntpath.py mówią „import os i określają ten moduł jako os.path”. Nie mówią „import os.path i odnoszą się do tego modułu jako os.path”. macpath.py nie ma nic na ten temat.
Pete Forman
3
To jest dobry przykład pokazujący, w jaki sposób dokument zawierający ten wskaźnik może wprowadzać w błąd: D
Cyker
7

Co ciekawe, import os.path zaimportuje cały os. spróbuj wykonać następujące czynności w interaktywnym monicie:

import os.path
dir(os)

Wynik będzie taki sam, jak gdybyś właśnie zaimportował os. Dzieje się tak, ponieważ os.path będzie odnosić się do innego modułu w zależności od posiadanego systemu operacyjnego, więc Python zaimportuje system operacyjny, aby określić, który moduł załadować dla ścieżki.

odniesienie

Z niektórymi modułami powiedzenie import foosię nie ujawni foo.bar, więc myślę, że to naprawdę zależy od projektu konkretnego modułu.


Ogólnie rzecz biorąc, samo importowanie potrzebnych jawnych modułów powinno być nieznacznie szybsze. Na moim komputerze:

import os.path: 7.54285810068e-06 sekundy

import os: 9.21904878972e-06 sekundy

Te czasy są na tyle bliskie, że można je pominąć. Twój program może wymagać użycia innych modułów od osteraz lub później, więc zwykle sensowne jest po prostu poświęcenie dwóch mikrosekund i użycie go, import osaby uniknąć tego błędu w późniejszym czasie. Zwykle opowiadam import os.pathsię po prostu za importowaniem systemu operacyjnego jako całości, ale widzę, dlaczego niektórzy woleliby być technicznie bardziej wydajni i przekazać czytelnikom kod, który jest jedyną częścią osmodułu, która będzie musiała zostać użyta. Zasadniczo sprowadza się to do pytania o styl w mojej głowie.

Matt Boehm
źródło
2
from os import pathspowoduje, że wywołania ścieżki będą jeszcze szybsze, jeśli problemem jest szybkość.
Justin Peel
Będąc pythonicznym, wyraźne jest lepsze niż ukryte, prawda? W rzeczywistości myślę, że tak naprawdę jest to wywołanie oceny przez użytkownika, czy użytkownik będzie używał tylko os.path, czy wielu modułów w systemie operacyjnym. Może jedna metoda jest bardziej zgodna z twoją filozofią niż druga?
Andrew Kou
23
Czas to jedna z przedwczesnych przedwczesnych optymalizacji, jakie kiedykolwiek widziałem. To nigdy nie było dla nikogo wąskim gardłem, a czas tutaj nie ma znaczenia dla tego, jak ktoś powinien kodować.
Mike Graham
5

Zdrowy rozsądek działa tutaj: osjest modułem i też os.pathjest modułem. Po prostu zaimportuj moduł, którego chcesz użyć:

  • Jeśli chcesz skorzystać z funkcjonalności w osmodule to importuj os.

  • Jeśli chcesz skorzystać z funkcjonalności w os.pathmodule to importuj os.path.

  • Jeśli chcesz korzystać z funkcjonalności w obu modułach, zaimportuj oba moduły:

    import os
    import os.path

Na przykład:

Cyker
źródło
4

Nie udało się znaleźć żadnego ostatecznego odniesienia, ale widzę, że przykładowy kod dla os.walk używa os.path, ale tylko importuje os

Chris Hulan
źródło