我应该使用`import os.path`还是`import os`?

Den*_*aia 132 python coding-style python-import

根据官方文档,os.path是一个模块.那么,导入它的首选方式是什么?

# Should I always import it explicitly?
import os.path
Run Code Online (Sandbox Code Playgroud)

要么...

# Is importing os enough?
import os
Run Code Online (Sandbox Code Playgroud)

请不要回答" os为我导入作品".我知道,它现在也适用于我(从Python 2.6开始).我想知道的是关于这个问题的任何官方建议.因此,如果您回答此问题,请发布您的推荐信.

Mik*_*ham 151

os.path以滑稽的方式工作.它看起来os应该是一个带有子模块的包path,但实际上它os是一个普通的模块,可以sys.modules实现注入魔法os.path.这是发生的事情:

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

    • sys.modules是一个缓存模块的字典.导入模块时,如果已经在某处导入了模块,则会将实例存储在其中sys.modules.
  • os是Python启动时加载的模块之一.它将其path属性分配给特定于操作系统的路径模块.

  • 它会注入,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项目采用这种方法,这往往会产生更多结构化代码.

  • @Denilson,它确实包括一个直接的答案:我总是自己做`import os.path`并认为这是一个更好的方式.通过"这与os.path的记录方式一致"我的意思是它在http://docs.python.org/library/os.path.html的文档中给出了自己的页面. (3认同)
  • 哇,`os.py`确实注入到`sys.modules['os.path']`中。这就是为什么“from os.path import Something”实际上有效。我很好奇这是何时引入的并检查了来源。有趣的事实:这是从 1999 年开始的,首次包含在 Python 1.5.2 中。原始提交位于[此处](https://github.com/python/cpython/commit/0237909e420db2897034a371087963be4a312552)。 (2认同)

Nic*_*k T 29

根据Tim Peters的PEP-20,"明确比隐含更好"和"可读性计数".如果您需要从os模块中获得所需的全部内容os.path,import os.path则会更明确,让其他人知道您真正关心的是什么.

同样,PEP-20也说"简单比复杂更好",所以如果你还需要更常见的os伞下的东西,import os那就更好了.

  • 我更想指出`import os`**和**`import os.path`是愚蠢的,如果你需要`os.getcwd()`和`os.path.isfile()` (12认同)
  • 我不知道`import os`是如何以任何有意义的方式变得"简单"的.简单!=简短. (2认同)

les*_*ana 16

明确答案: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).
...
Run Code Online (Sandbox Code Playgroud)

  • 这根本不是我认为文档字符串是要解释的,尽管它有很多误导性.请记住句子""而不是直接导入此模块,导入操作系统并将此模块称为os.path."`位于`posixpath.py`(或`macpath.py`,`ntpath.py`等等.).我很确定他们的意思是不应该`导入​​posixpath`(有效),而是通过`os`导入模块以获得更好的可移植性.我不认为他们打算建议是否首选`import os`或`import os.path`. (15认同)
  • 请注意,它不是'os.path`模块的文档,它不存在,但是对于`posixpath`. (12认同)
  • 这是一个很好的例子,显示了包含* this *指针的文档可能会引起误解:D (2认同)

小智 6

找不到任何明确的参考,但我看到os.walk的示例代码使用 os.path 但只导入 os


Mat*_*ehm 5

有趣的是,导入os.path将导入所有操作系统.在交互式提示中尝试以下操作:

import os.path
dir(os)
Run Code Online (Sandbox Code Playgroud)

结果将与您刚刚导入的os相同.这是因为os.path将根据您拥有的操作系​​统引用不同的模块,因此python将导入os以确定要为路径加载哪个模块.

参考

有些模块,说import foo不会暴露foo.bar,所以我猜这真的取决于具体模块的设计.


通常,只需导入所需的显式模块应该稍微快一点.在我的机器上:

import os.path: 7.54285810068e-06

import os: 9.21904878972e-06

这些时间足够接近,可以忽略不计.您的程序可能需要os现在或以后使用其他模块,因此通常只需要牺牲2微秒并使用import os以避免以后出现此错误.我通常只是将os作为一个整体导入,但可以看出为什么有些人更愿意import os.path在技​​术上更高效,并向代码的读者传达这是os模块中唯一需要使用的部分.它基本上归结为我脑海中的一个风格问题.

  • 时间这是我见过的最早的过早优化.这从来就不是*任何人的瓶颈,而且这里的时间对于某人应该如何编码并不重要. (21认同)
  • 如果速度是问题,`来自os导入路径`将使路径调用更快. (2认同)

Cyk*_*ker 5

常识在这里起作用:os是一个模块,os.path也是一个模块。所以只需导入您要使用的模块:

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

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

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

    import os
    import os.path
    
    Run Code Online (Sandbox Code Playgroud)

以供参考: