Dois-je utiliser `import os.path` ou` import os`?

139

Selon la documentation officielle , os.pathest un module. Quelle est donc la manière préférée de l'importer?

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

Ou...

# Is importing os enough?
import os

Veuillez NE PAS répondre "l'importation de ostravaux pour moi". Je sais, cela fonctionne aussi pour moi en ce moment (à partir de Python 2.6). Ce que je veux savoir, c'est toute recommandation officielle à ce sujet. Donc, si vous répondez à cette question, veuillez poster vos références .

Denilson Sá Maia
la source

Réponses:

157

os.pathfonctionne d'une manière amusante. Cela ressemble à osun package avec un sous-module path, mais en réalité, osc'est un module normal qui fait de la magie sys.modulespour injecter os.path. Voici ce qui se passe:

  • Lorsque Python démarre, il charge un tas de modules dans sys.modules. Ils ne sont liés à aucun nom dans votre script, mais vous pouvez accéder aux modules déjà créés lorsque vous les importez d'une manière ou d'une autre.

    • sys.modulesest un dict dans lequel les modules sont mis en cache. Lorsque vous importez un module, s'il a déjà été importé quelque part, il obtient l'instance stockée dans sys.modules.
  • osfait partie des modules chargés au démarrage de Python. Il affecte son pathattribut à un module de chemin spécifique au système d'exploitation.

  • Il injecte de sys.modules['os.path'] = pathsorte que vous puissiez faire " import os.path" comme s'il s'agissait d'un sous-module.

J'ai tendance à penser os.pathà un module que je veux utiliser plutôt qu'à une chose dans le osmodule , donc même si ce n'est pas vraiment un sous-module d'un package appelé os, je l'importe un peu comme si c'était un et je le fais toujoursimport os.path . Ceci est cohérent avec la façon dont os.pathest documenté.


Incidemment, ce type de structure conduit à beaucoup de confusion précoce des programmeurs Python sur les modules et les packages et l'organisation du code, je pense. C'est vraiment pour deux raisons

  1. Si vous pensez osà un package et que vous savez que vous pouvez faire import oset avoir accès au sous-module os.path, vous pourriez être surpris plus tard de ne pas pouvoir le faire import twistedet y accéder automatiquement twisted.spreadsans l'importer.

  2. Il est déroutant que ce os.namesoit une chose normale, une chaîne et os.pathun module. Je structure toujours mes packages avec des __init__.pyfichiers vides de sorte qu'au même niveau j'ai toujours un type de chose: un module / package ou autre. Plusieurs grands projets Python adoptent cette approche, qui tend à rendre le code plus structuré.

Mike Graham
la source
Excellente réponse très informative! Toutes nos félicitations! Même s'il ne répond pas directement à la question, il contient de nombreux détails utiles. Mais pourriez-vous s'il vous plaît préciser "Ceci est cohérent avec la façon dont os.path est documenté"? Comme Chris Hulan l'a dit, l'exemple os.walk () importe uniquement os au lieu de os.path.
Denilson Sá Maia
3
@Denilson, cela inclut une réponse directe: je fais toujours import os.pathmoi - même et je pense que c'est une meilleure façon. Par "Ceci est cohérent avec la façon dont os.path est documenté", je voulais dire qu'il a sa propre page dans la documentation à docs.python.org/library/os.path.html .
Mike Graham
1
Wow, os.pyinjecte en effet dans sys.modules['os.path']. Voilà pourquoi from os.path import somethingfonctionne réellement. J'étais curieux de savoir quand cela a été introduit et j'ai vérifié la source. Fait amusant: il s'agit de 1999, initialement inclus dans Python 1.5.2. Le commit original est ici .
Bluehorn
29

Selon PEP-20 de Tim Peters, «l'explicite est meilleur que l'implicite» et «la lisibilité compte». Si tout ce dont vous avez besoin du osmodule est sous os.path, import os.pathserait plus explicite et laisser les autres savoir ce qui vous tient vraiment à cœur.

De même, PEP-20 dit également "Simple est mieux que complexe", donc si vous avez également besoin de choses qui se trouvent sous le osparapluie plus général , il import osserait préférable.

Nick T
la source
2
Je ne vois pas en quoi import osconsiste vraiment à être «simple» d'une manière significative. Simple! = Court.
Mike Graham
14
J'essaie de plus souligner que import os et un import os.pathest daft par exemple si vous besoin os.getcwd()etos.path.isfile()
Nick T
15

Réponse définitive: import oset utilisation os.path. pas import os.pathdirectement.

Depuis la documentation du module lui-même:

>>> 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
la source
13
Notez que ce n'est pas de la documentation pour un os.pathmodule qui n'existe pas, mais pour posixpath.
wRAR
18
Ce n'est pas du tout comme ça que je pense que docstring est censé être interprété, bien que ce soit assez trompeur. Gardez à l'esprit que la phrase "Instead of importing this module directly, import os and refer to this module as os.path."se trouve dans posixpath.py(ou macpath.py, ntpath.pyetc.). Je suis assez sûr que ce qu'ils veulent dire, c'est qu'il ne faut pas import posixpath(ce qui fonctionne), mais plutôt importer le module via ospour une meilleure portabilité. Je ne pense pas qu'ils aient l'intention de faire une recommandation sur l'opportunité import osou la import os.pathpréférence.
flornquake
1
Je suis d'accord avec la plupart des commentaires de @flornquake mais en désaccord avec la dernière phrase. Les deux posixpath.py et ntpath.py disent "import os et se réfèrent à ce module comme os.path". Ils ne disent pas "import os.path et se réfèrent à ce module comme os.path". macpath.py n'a rien à ce sujet.
Pete Forman
3
Voici un bon exemple montrant comment un document contenant un pointeur this peut être trompeur: D
Cyker
7

Il est intéressant de noter que l'importation de os.path importera tous les fichiers os. essayez ce qui suit dans l'invite interactive:

import os.path
dir(os)

Le résultat sera le même que si vous venez d'importer os. C'est parce que os.path fera référence à un module différent en fonction du système d'exploitation que vous avez, donc python importera os pour déterminer quel module charger pour le chemin.

référence

Avec certains modules, dire import foone sera pas exposé foo.bar, donc je suppose que cela dépend vraiment de la conception du module spécifique.


En général, importer simplement les modules explicites dont vous avez besoin devrait être légèrement plus rapide. Sur ma machine:

import os.path: 7.54285810068e-06 secondes

import os: 9.21904878972e-06 secondes

Ces temps sont suffisamment proches pour être assez négligeables. Votre programme peut avoir besoin d'utiliser d'autres modules à partir de osmaintenant ou plus tard, il est donc généralement logique de simplement sacrifier les deux microsecondes et de les utiliser import ospour éviter cette erreur plus tard. Je suis généralement d'accord avec l'importation d'os dans son ensemble, mais je peux voir pourquoi certains préféreraient import os.pathêtre techniquement plus efficaces et transmettre aux lecteurs du code que c'est la seule partie du osmodule qui devra être utilisée. Cela se résume essentiellement à une question de style dans mon esprit.

Matt Boehm
la source
2
from os import pathrendra les appels au chemin encore plus rapides si la vitesse est le problème.
Justin Peel
Être pythonique, explicite vaut mieux que l'implicite, n'est-ce pas? En réalité, je pense que c'est vraiment le jugement de l'utilisateur, que l'utilisateur n'utilise que os.path ou plusieurs modules dans os. Peut-être qu'une méthode est plus conforme à votre philosophie que l'autre?
Andrew Kou
23
Le timing est l'une des optimisations prématurées les plus prématurées que j'ai jamais vues. Cela n'a jamais été le goulot d' étranglement de personne et le temps ici n'a pas d'importance pour la façon dont quelqu'un devrait coder.
Mike Graham
5

Le bon sens fonctionne ici: osest un module, et os.pathest aussi un module. Alors importez simplement le module que vous souhaitez utiliser:

  • Si vous souhaitez utiliser les fonctionnalités du osmodule, importez os.

  • Si vous souhaitez utiliser les fonctionnalités du os.pathmodule, importez os.path.

  • Si vous souhaitez utiliser des fonctionnalités dans les deux modules, importez les deux modules:

    import os
    import os.path

Pour référence:

Cyker
la source
4

Impossible de trouver une référence définitive, mais je vois que l'exemple de code pour os.walk utilise os.path mais importe seulement os

Chris Hulan
la source