Devo usar `import os.path` ou` import os`?

139

De acordo com a documentação oficial , os.pathé um módulo. Assim, qual é a maneira preferida de importá-lo?

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

Ou...

# Is importing os enough?
import os

Por favor, NÃO responda "importar osobras para mim". Eu sei, ele funciona para mim também agora (a partir do Python 2.6). O que eu quero saber é alguma recomendação oficial sobre esse problema. Portanto, se você responder a essa pergunta, poste suas referências .

Denilson Sá Maia
fonte

Respostas:

157

os.pathfunciona de uma maneira engraçada. Parece que osdeveria ser um pacote com um submódulo path, mas, na realidade, osé um módulo normal que faz mágica com sys.modulesa injeção os.path. Aqui está o que acontece:

  • Quando o Python é iniciado, ele carrega vários módulos sys.modules. Eles não estão vinculados a nenhum nome no seu script, mas você pode acessar os módulos já criados quando importá-los de alguma forma.

    • sys.modulesé um ditado no qual os módulos são armazenados em cache. Quando você importa um módulo, se ele já foi importado em algum lugar, ele obtém a instância armazenada sys.modules.
  • osestá entre os módulos carregados quando o Python é iniciado. Ele atribui seu pathatributo a um módulo de caminho específico do sistema operacional.

  • Ele injeta sys.modules['os.path'] = pathpara que você possa fazer " import os.path" como se fosse um submódulo.

Eu costumo pensar os.pathcomo um módulo que eu quero usar, e não como algo no osmódulo , portanto, mesmo que não seja realmente um submódulo de um pacote chamado os, importo-o como se fosse um e sempre façoimport os.path . Isso é consistente com a os.pathdocumentação.


Aliás, esse tipo de estrutura leva a muitas confusões iniciais dos programadores de Python sobre módulos e pacotes e organização de códigos, eu acho. Isso é realmente por duas razões

  1. Se você pensa osem um pacote e sabe que pode fazer import ose ter acesso ao submódulo os.path, poderá se surpreender mais tarde quando não puder fazer import twistede acessar automaticamente twisted.spreadsem importá-lo.

  2. É confuso que os.nameé uma coisa normal, uma string e os.pathé um módulo. Eu sempre estruturo meus pacotes com __init__.pyarquivos vazios para que, no mesmo nível, eu sempre tenha um tipo de coisa: um módulo / pacote ou outra coisa. Vários grandes projetos Python adotam essa abordagem, que tende a criar código mais estruturado.

Mike Graham
fonte
Excelente, resposta muito informativa! Parabéns! Mesmo que não responda diretamente à pergunta, ele possui muitos detalhes úteis. Mas você poderia elaborar "Isso é consistente com a documentação do os.path"? Como Chris Hulan disse, o exemplo os.walk () importa apenas os em vez de os.path.
Denilson Sá Maia
3
@ Denilson, inclui uma resposta direta: eu sempre faço a import os.pathmim mesmo e acho que é uma maneira melhor. Por "Isso é consistente com a documentação do os.path", quis dizer que ele recebe sua própria página na documentação em docs.python.org/library/os.path.html .
Mike Graham
1
Uau, de os.pyfato se injeta sys.modules['os.path']. Então é por isso que from os.path import somethingrealmente funciona. Fiquei curioso sobre quando isso foi introduzido e verifiquei a fonte. Curiosidade: Isso é de 1999, incluído pela primeira vez no Python 1.5.2. O commit original está aqui .
Bluehorn 18/12/19
29

Conforme PEP-20 de Tim Peters, "Explícito é melhor que implícito" e "Legibilidade conta". Se tudo que você precisa do osmódulo estiver abaixo os.path, import os.pathseria mais explícito e deixaria outras pessoas saberem com o que você realmente se importa.

Da mesma forma, o PEP-20 também diz "Simples é melhor que complexo"; portanto, se você também precisar de coisas que residam sob o osguarda - chuva mais geral , import osseria preferido.

Nick T
fonte
2
Não vejo como import osé realmente ser "simples" de maneira significativa. Simples! = Curto.
Mike Graham
14
Eu estava mais tentando mostrar que import os e um import os.pathé idiota se você por exemplo, necessidade os.getcwd()eos.path.isfile()
Nick T
15

Resposta definitiva: import ose use os.path. não import os.pathdiretamente.

A partir da documentação do próprio módulo:

>>> 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
fonte
13
Observe que não são documentos para um os.pathmódulo que não existe, mas para posixpath.
WRAR
18
Não é assim que eu acho que a doutrina deve ser interpretada, embora seja bastante enganadora. Tenha em mente que a sentença "Instead of importing this module directly, import os and refer to this module as os.path."está localizado em posixpath.py(ou macpath.py, ntpath.pyetc.). Estou bastante certo de que o que eles querem dizer é que não se deve import posixpath(o que funciona), mas sim importar o módulo via ospara melhor portabilidade. Eu não acho que eles pretendem dar uma recomendação sobre se é import osou import os.pathnão preferido.
flornquake
1
Concordo com a maioria dos comentários de @flornquake, mas discordo da última frase. Posixpath.py e ntpath.py dizem "import os e referem-se a este módulo como os.path". Eles não dizem "import os.path e referem-se a este módulo como os.path". O macpath.py não tem nada a ver.
Pete Forman
3
Este é um bom exemplo de como um documento que contém esse ponteiro pode ser enganador: D
Cyker
7

Curiosamente, a importação do os.path importará todo o os. tente o seguinte no prompt interativo:

import os.path
dir(os)

O resultado será o mesmo que se você tivesse importado os. Isso ocorre porque o os.path se refere a um módulo diferente com base em qual sistema operacional você possui, portanto, o python importará o os para determinar qual módulo carregar para o caminho.

referência

Em alguns módulos, o ditado import foonão será exposto foo.bar, então acho que depende realmente do design do módulo específico.


Em geral, apenas importar os módulos explícitos necessários deve ser um pouco mais rápido. Na minha máquina:

import os.path: 7.54285810068e-06 segundos

import os: 9.21904878972e-06 segundos

Estes tempos estão próximos o suficiente para serem razoavelmente insignificantes. Seu programa pode precisar usar outros módulos osagora ou mais tarde; portanto, geralmente faz sentido sacrificar os dois microssegundos e usá-lo import ospara evitar esse erro posteriormente. Eu costumo lado apenas importando os como um todo, mas posso ver por que alguns preferem import os.pathser tecnicamente mais eficientes e transmitir aos leitores do código que essa é a única parte do osmódulo que precisará ser usada. Essencialmente, tudo se resume a uma questão de estilo em minha mente.

Matt Boehm
fonte
2
from os import pathtornará as chamadas para o caminho ainda mais rápidas se a velocidade for o problema.
23610 Justin Peel
Sendo pitônico, explícito é melhor do que implícito, certo? Na realidade, eu acho que realmente é a decisão do usuário, se ele usará apenas o os.path ou vários módulos no sistema operacional. Talvez um método esteja mais de acordo com sua filosofia do que o outro?
Andrew Kou
23
Cronometrar esta é uma das otimizações prematuras prematuras que eu já vi. Isso nunca foi o gargalo de ninguém e o tempo aqui é irrelevante para como alguém deve codificar.
Mike Graham
5

O senso comum funciona aqui: osé um módulo e também os.pathé um módulo. Portanto, basta importar o módulo que você deseja usar:

  • Se você deseja usar funcionalidades no osmódulo, importe os.

  • Se você deseja usar funcionalidades no os.pathmódulo, importe os.path.

  • Se você deseja usar funcionalidades nos dois módulos, importe os dois módulos:

    import os
    import os.path

Para referência:

Cyker
fonte
4

Não foi possível encontrar nenhuma referência definitiva, mas vejo que o código de exemplo para os.walk usa os.path, mas importa apenas os

Chris Hulan
fonte