我应该使用`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起)。我想知道的是有关此问题的任何官方建议。因此,如果您回答这个问题,请发表您的参考资料

Answers:


157

os.path以一种有趣的方式工作。看起来os应该是带有子模块的程序包path,但实际上os是一个普通的模块,sys.modules可以注入魔力os.path。这是发生了什么:

  • Python启动时,会将一堆模块加载到中sys.modules。它们没有绑定到脚本中的任何名称,但是以某种方式导入它们时,您可以访问已创建的模块。

    • sys.modules是在其中缓存模块的命令。导入模块时,如果已经将其导入到某处,则它将实例存储在中sys.modules
  • os是Python启动时加载的模块之一。它将其path属性分配给特定于os的路径模块。

  • 它会注入,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的记录方式一致”?如Chris Hulan所说,os.walk()示例仅导入os而不是os.path。
DenilsonSáMaia'4

3
@Denilson,它的确包含直接答案:我总是import os.path自己做,认为那是更好的方法。“这与os.path的记录方式一致”是指在docs.python.org/library/os.path.html的文档中为它提供了自己的页面。
Mike Graham

1
哇,os.py确实注入了sys.modules['os.path']。所以这就是为什么from os.path import something有效的原因。我很好奇这是什么时候引入并检查了源代码。有趣的事实:这是从1999年开始的,首先包含在Python 1.5.2中。原始提交在这里
Bluehorn,

29

根据蒂姆·彼得斯(Tim Peters)撰写的PEP-20,“显式胜于隐式”和“可读性”。如果您需要从os模块中获得的全部在之下os.pathimport os.path则会更加明确,并让其他人知道您真正关心的是什么。

同样,PEP-20也说“简单胜于复杂”,因此,如果您还需要一些更笼统的资料osimport os则首选。


2
我看不到import os以任何有意义的方式变得“简单” 到底是怎么回事。简单!=简短。
Mike Graham 2010年

14
我更想指出的是,import os 一个import os.path是愚蠢的,如果你需要如os.getcwd()os.path.isfile()
尼克ŧ

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
我根本不认为该文档字符串应该被解释,尽管这完全是一种误导。请记住这句话"Instead of importing this module directly, import os and refer to this module as os.path."位于posixpath.py(或macpath.pyntpath.py等等)。我相当确定他们的意思是不应该import posixpath(有效),而是通过导入模块os以提高可移植性。我不认为他们打算给一个建议是否import osimport os.path优先。
flornquake

1
我同意@flornquake的大部分评论,但不同意最后一句话。posixpath.py和ntpath.py都说“导入os并将此模块称为os.path”。他们没有说“导入os.path并将此模块称为os.path”。macpath.py无关紧要。
皮特·佛曼

3
这是一个很好的例子,显示了包含this指针的文档可能会引起误解: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在以后避免该错误就可以了。我通常只将os整体导入,但是可以看到为什么有些人希望import os.path从技术上提高效率,并向代码读者传达这是os需要使用的模块的唯一部分。在我看来,它本质上可以归结为样式问题。


2
from os import path如果速度是问题,将使对path的调用更快。
贾斯汀·皮

作为pythonic,显式比隐式好吗?实际上,我认为这实际上是用户的判断调用,无论用户是只使用os.path还是使用os中的多个模块。也许一种方法更符合您的哲学,而不是另一种?
安德鲁·寇

23
计时这是我所见过的一些最早的过早优化。这从来都不是任何人的瓶颈,在这里的时间对于某人应该如何编码并不重要。
Mike Graham 2010年

5

常识在这里起作用:os是模块,os.path也是模块。因此,只需导入要使用的模块:

  • 如果要在os模块中使用功能,请导入os

  • 如果要在os.path模块中使用功能,请导入os.path

  • 如果要在两个模块中使用功能,则导入两个模块:

    import os
    import os.path

以供参考:


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.