¿Debo usar `import os.path` o` import os`?

139

Según la documentación oficial , os.pathes un módulo. Entonces, ¿cuál es la forma preferida de importarlo?

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

O...

# Is importing os enough?
import os

Por favor, NO responda "importar ostrabajos para mí". Lo sé, también funciona para mí en este momento (a partir de Python 2.6). Lo que quiero saber es cualquier recomendación oficial sobre este tema. Entonces, si responde esta pregunta, publique sus referencias .

Denilson Sá Maia
fuente

Respuestas:

157

os.pathFunciona de una manera divertida. Parece que osdebería ser un paquete con un submódulo path, pero en realidad oses un módulo normal que hace magia sys.modulespara inyectar os.path. Esto es lo que pasa:

  • Cuando Python se inicia, carga un montón de módulos sys.modules. No están vinculados a ningún nombre en su script, pero puede acceder a los módulos ya creados cuando los importe de alguna manera.

    • sys.moduleses un dict en el que los módulos se almacenan en caché. Cuando importa un módulo, si ya se ha importado en alguna parte, se almacena la instancia sys.modules.
  • osse encuentra entre los módulos que se cargan cuando se inicia Python. Asigna su pathatributo a un módulo de ruta específico del sistema operativo.

  • Se inyecta sys.modules['os.path'] = pathpara que pueda " import os.path" hacer como si fuera un submódulo.

Tiendo a pensar os.pathen un módulo que quiero usar en lugar de una cosa en el osmódulo , por lo que aunque no es realmente un submódulo de un paquete llamado os, lo importo como si fuera uno y siempre lo hagoimport os.path . Esto es consistente con cómo os.pathse documenta.


Por cierto, este tipo de estructura conduce a una gran confusión temprana de los programadores de Python sobre módulos y paquetes y organización de código, creo. Esto es realmente por dos razones

  1. Si piensa osen un paquete y sabe que puede hacer import osy tener acceso al submódulo os.path, puede sorprenderse más tarde cuando no pueda hacerlo import twistedy acceder automáticamente twisted.spreadsin importarlo.

  2. Es confuso que os.namesea ​​algo normal, una cadena y que os.pathsea ​​un módulo. Siempre estructuro mis paquetes con __init__.pyarchivos vacíos para que al mismo nivel siempre tenga un tipo de cosas: un módulo / paquete u otras cosas. Varios grandes proyectos de Python adoptan este enfoque, que tiende a crear un código más estructurado.

Mike Graham
fuente
Excelente, muy informativa respuesta! ¡Felicidades! Aunque no responde directamente a la pregunta, tiene muchos detalles útiles. Pero, ¿podría explicarnos "Esto es coherente con la forma en que se documenta os.path"? Como dijo Chris Hulan, el ejemplo os.walk () importa solo os en lugar de os.path.
Denilson Sá Maia
3
@Denilson, incluye una respuesta directa: siempre lo hago import os.pathyo mismo y creo que es una mejor manera. Por "Esto es coherente con la forma en que se documenta os.path" quise decir que se le da su propia página en la documentación en docs.python.org/library/os.path.html .
Mike Graham el
1
Wow, de os.pyhecho se inyecta en sys.modules['os.path']. Entonces esta es la razón por la que from os.path import somethingrealmente funciona. Tenía curiosidad sobre cuándo se introdujo esto y verifiqué la fuente. Dato curioso: esto es de 1999, incluido por primera vez en Python 1.5.2. El compromiso original está aquí .
Bluehorn
29

Según PEP-20 de Tim Peters, "explícito es mejor que implícito" y "la legibilidad cuenta". Si todo lo que necesita del osmódulo está debajo os.path, import os.pathsería más explícito y dejaría que otros sepan lo que realmente le importa.

Del mismo modo, PEP-20 también dice que "lo simple es mejor que lo complejo", por lo que si también necesita cosas que residan bajo el osparaguas más general , import ossería preferible.

Nick T
fuente
2
No veo cómo se import ostrata realmente de ser "simple" de ninguna manera significativa. Simple! = Corto.
Mike Graham
14
Estaba más tratando de señalar eso import os yimport os.path es una tontería si, por ejemplo, necesitas os.getcwd()yos.path.isfile()
Nick T
15

Respuesta definitiva: import osy uso os.path. No lo hagas import os.pathdirectamente.

De la documentación del módulo en sí:

>>> 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
fuente
13
Tenga en cuenta que no son documentos para un os.pathmódulo que no existe, sino para posixpath.
WRAR
18
De ninguna manera es así como creo que la cadena de documentos debe interpretarse, aunque es bastante engañosa. Tenga en cuenta que la oración "Instead of importing this module directly, import os and refer to this module as os.path."se encuentra en posixpath.py(o macpath.py, ntpath.pyetc.). Estoy bastante seguro de que lo que quieren decir es que uno no debería import posixpath(lo que funciona), sino más bien importar el módulo a través osde una mejor portabilidad. No creo que tengan la intención de dar una recomendación sobre si se prefiere import oso no import os.path.
flornquake
1
Estoy de acuerdo con la mayoría de los comentarios de @flornquake pero no estoy de acuerdo con la última oración. Tanto posixpath.py como ntpath.py dicen "import os y se refieren a este módulo como os.path". No dicen "import os.path y se refieren a este módulo como os.path". macpath.py no tiene nada al respecto.
Pete Forman
3
Este es un buen ejemplo de cómo un documento que contiene este puntero puede ser engañoso: D
Cyker
7

Curiosamente, importar os.path importará todos los sistemas operativos. intente lo siguiente en el mensaje interactivo:

import os.path
dir(os)

El resultado será el mismo que si acaba de importar el sistema operativo. Esto se debe a que os.path se referirá a un módulo diferente según el sistema operativo que tenga, por lo que python importará os para determinar qué módulo cargar para la ruta.

referencia

Con algunos módulos, decir import foono expondrá foo.bar, así que supongo que realmente depende del diseño del módulo específico.


En general, solo importar los módulos explícitos que necesita debería ser marginalmente más rápido. En mi máquina

import os.path: 7.54285810068e-06 segundos

import os: 9.21904878972e-06 segundos

Estos tiempos son lo suficientemente cercanos como para ser bastante insignificantes. Es posible que su programa necesite usar otros módulos desde osahora o más adelante, por lo que generalmente tiene sentido sacrificar los dos microsegundos y usar import ospara evitar este error en un momento posterior. Por lo general, me inclino por importar el sistema operativo en su conjunto, pero puedo ver por qué algunos preferirían import os.pathser técnicamente más eficientes y transmitir a los lectores del código que esa es la única parte del osmódulo que deberá usarse. Esencialmente se reduce a una pregunta de estilo en mi mente.

Matt Boehm
fuente
2
from os import pathhará que las llamadas al camino sean aún más rápidas si la velocidad es el problema.
Justin Peel
Siendo pitón, explícito es mejor que implícito ¿verdad? En realidad, creo que realmente es la decisión del usuario, si el usuario solo va a usar os.path o múltiples módulos dentro de os. ¿Quizás un método está más en línea con su filosofía sobre el otro?
Andrew Kou
23
El tiempo es una de las optimizaciones prematuras más prematuras que he visto. Este nunca ha sido el cuello de botella de nadie y el tiempo aquí es irrelevante para cómo alguien debería codificar.
Mike Graham
5

El sentido común funciona aquí: oses un módulo y también os.pathes un módulo. Tan solo importe el módulo que desea utilizar:

  • Si desea utilizar funcionalidades en el osmódulo, importe os.

  • Si desea utilizar funcionalidades en el os.pathmódulo, importe os.path.

  • Si desea utilizar funcionalidades en ambos módulos, importe ambos módulos:

    import os
    import os.path

Para referencia:

Cyker
fuente
4

No se pudo encontrar ninguna referencia definitiva, pero veo que el código de ejemplo para os.walk usa os.path pero solo importa os

Chris Hulan
fuente