从相对路径导入模块

Jud*_*red 749 python relative-path python-import

如何根据相对路径导入Python模块?

例如,如果dirFoo包含Foo.pydirBar,和dirBar包含Bar.py,我怎么导入Bar.pyFoo.py

这是一个直观的表示:

dirFoo\
    Foo.py
    dirBar\
        Bar.py
Run Code Online (Sandbox Code Playgroud)

Foo希望包括Bar,但重组文件夹层次结构不是一种选择.

sor*_*rin 329

假设您的两个目录都是真正的Python包(其中包含__init__.py文件),这里是一个安全的解决方案,可以将模块相对于脚本的位置包含在内.

我假设您要这样做,因为您需要在脚本中包含一组模块.我在几个产品的生产中使用它,并在许多特殊情况下工作,例如:从另一个目录调用的脚本或用python执行而不是打开新的解释器.

 import os, sys, inspect
 # realpath() will make your script run, even if you symlink it :)
 cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
 if cmd_folder not in sys.path:
     sys.path.insert(0, cmd_folder)

 # Use this if you want to include modules from a subfolder
 cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder")))
 if cmd_subfolder not in sys.path:
     sys.path.insert(0, cmd_subfolder)

 # Info:
 # cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE __file__ !!!
 # __file__ fails if the script is called in different ways on Windows.
 # __file__ fails if someone does os.chdir() before.
 # sys.argv[0] also fails, because it doesn't not always contains the path.
Run Code Online (Sandbox Code Playgroud)

作为奖励,这种方法可以让您强制Python使用您的模块而不是系统上安装的模块.

警告!当前模块在egg文件中时,我真的不知道发生了什么.它可能也失败了.

  • 对我来说,'realpath`已经生成了绝对路径,因此我不需要`abspath`.也可以使用`os.path.dirname`而不是split,使索引`[0]`过时.该行将是:`os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))` (7认同)
  • 我可以解释一下这是如何工作的吗?我有一个类似的问题,我喜欢强制python模块DIR而不是运行搜索 (5认同)
  • @ scr4ve你应该使用os.path.join(),欢迎你直接将案例(`cmd_subfolder`)添加到我的答案中.谢谢! (4认同)
  • 如果你要使用子文件夹,请使用它:`os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0])+"/子文件夹")`_NOT_在`abspath`之前添加子文件夹,因为这会导致严重的错误. (2认同)

S.L*_*ott 325

确保dirBar具有该__init__.py文件 - 这使得目录成为Python包.

  • 请注意,此文件可以完全为空. (201认同)
  • 如果dirBar的父目录不在`sys.path`中,那么`dirBar`目录中`__init __.py`的存在对它没有多大帮助. (46认同)
  • "当目录已经在sys.path中时".虽然完全正确,我们怎么能猜测该目录不在问题的`sys.path`中?也许有些遗漏我们没有看到或知道的东西? (12认同)
  • -1,添加`__init.py__`只有当目录已经在sys.path中时才会起作用,而在我的情况下它不是."sorin"(接受者)的解决方案始终有效. (6认同)
  • 这是NO的问题答案:初始化文件是否存在,这不会使python查看子目录.它是如何获得数百个赞成票的? (4认同)
  • 上面的注释假设 dirBar 是一个子包。 (2认同)

And*_*Cox 259

您还可以将子目录添加到Python路径中,以便将其作为普通脚本导入.

import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
Run Code Online (Sandbox Code Playgroud)

  • 这**可以与相对路径一起工作 - 您只需要了解相对路径将取决于您运行的目录,这使得除了快速入侵之外的其他任何东西都是一个糟糕的解决方案. (22认同)
  • 您可以执行类似`sys.path.append(os.path.dirname(__ file __)+"/ relative/path/to/module")的操作. (11认同)
  • 看起来您的答案不适用于相对路径,请参阅http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder/6098238#6098238 (5认同)

lef*_*kir 116

import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)

import mymodule
Run Code Online (Sandbox Code Playgroud)

  • 您应该使用`os.path.join()`而不是通过'/'加入,这将在(跛脚)窗口中中断. (20认同)
  • 这不可靠.它取决于当前工作目录是什么,而不是脚本所在的目录. (17认同)
  • 正斜杠在我的Windows机器上正常工作. (13认同)
  • 我之所以这样,是因为您可以灵活地转到目录。 (2认同)

小智 104

只需简单的操作就可以从其他文件夹中导入.py文件.

假设你有一个像这样的目录:

lib/abc.py
Run Code Online (Sandbox Code Playgroud)

然后在lib文件夹中保留一个空文件作为命名

__init__.py
Run Code Online (Sandbox Code Playgroud)

然后使用

from lib.abc import <Your Module name>
Run Code Online (Sandbox Code Playgroud)

__init__.py文件保留在导入模块的层次结构的每个文件夹中.


bou*_*ard 80

如果以这种方式构建项目:

src\
  __init__.py
  main.py
  dirFoo\
    __init__.py
    Foo.py
  dirBar\
    __init__.py
    Bar.py
Run Code Online (Sandbox Code Playgroud)

然后从Foo.py你应该能够做到:

import dirFoo.Foo
Run Code Online (Sandbox Code Playgroud)

要么:

from dirFoo.Foo import FooObject
Run Code Online (Sandbox Code Playgroud)

根据Tom的评论,这确实需要src通过site_packages或您的搜索路径访问该文件夹.此外,正如他所提到的,__init__.py当您首次导入该包/目录中的模块时,会隐式导入.通常__init__.py只是一个空文件.

  • 为什么有人想从Foo.py本身导入Foo.应该来自Bar.py,我想. (7认同)
  • 这是我正在寻找的最简单的解决方案.如果要导入的文件肯定在其中一个子目录中,则此解决方案是gem. (3认同)
  • 如何从 Foo.py 导入 Bar.py? (2认同)

mon*_*kut 45

最简单的方法是使用sys.path.append().

但是,您可能也对imp模块感兴趣.它提供对内部导入功能的访问.

# mod_name is the filename without the .py/.pyc extention
py_mod = imp.load_source(mod_name,filename_path) # Loads .py file
py_mod = imp.load_compiled(mod_name,filename_path) # Loads .pyc file 
Run Code Online (Sandbox Code Playgroud)

当您不知道模块的名称时,这可用于动态加载模块.

我过去曾使用它来创建应用程序的插件类型接口,用户可以在其中编写具有应用程序特定功能的脚本,并将脚本放在特定目录中.

此外,这些功能可能很有用:

imp.find_module(name[, path])
imp.load_module(name, file, pathname, description)
Run Code Online (Sandbox Code Playgroud)


Pet*_*ree 43

这是相关的PEP:

http://www.python.org/dev/peps/pep-0328/

特别是,假设dirFoo是dirBar的目录......

在dirFoo\Foo.py中:

from ..dirBar import Bar
Run Code Online (Sandbox Code Playgroud)

  • 相对导入在非包中不起作用. (33认同)

Jam*_*Gan 23

不对脚本进行任何修改的最简单方法是设置PYTHONPATH环境变量.因为sys.path是从这些位置初始化的:

  1. 包含输入脚本(或当前目录)的目录.
  2. PYTHONPATH(目录名列表,语法与shell变量PATH相同).
  3. 依赖于安装的默认值.

赶紧跑:

export PYTHONPATH=/absolute/path/to/your/module
Run Code Online (Sandbox Code Playgroud)

您的sys.path将包含上面的路径,如下所示:

print sys.path

['', '/absolute/path/to/your/module', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client', '/usr/lib/python2.7/dist-packages/ubuntuone-client', '/usr/lib/python2.7/dist-packages/ubuntuone-control-panel', '/usr/lib/python2.7/dist-packages/ubuntuone-couch', '/usr/lib/python2.7/dist-packages/ubuntuone-installer', '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']
Run Code Online (Sandbox Code Playgroud)


小智 13

在我看来,最好的选择是将__ init __.py放在文件夹中并使用

from dirBar.Bar import *
Run Code Online (Sandbox Code Playgroud)

建议不要使用sys.path.append(),因为如果使用与现有python包相同的文件名,可能会出错.我没有测试,但那将是模棱两可的.

  • @tester:使用`from dirBar import Bar`. (2认同)

nob*_*bar 11

Linux用户的快捷方式

如果您只是在修补并且不关心部署问题,则可以使用符号链接(假设您的文件系统支持它)使模块或包直接在请求模块的文件夹中可见.

ln -s (path)/module_name.py
Run Code Online (Sandbox Code Playgroud)

要么

ln -s (path)/package_name
Run Code Online (Sandbox Code Playgroud)

注意:"模块"是任何扩展名为.py的文件,"package"是包含该文件的任何文件夹__init__.py(可以是空文件).从使用的角度来看,模块和包是相同的 - 都通过import命令公开它们包含的"定义和语句" .

请参阅:http://docs.python.org/2/tutorial/modules.html


jgo*_*mo3 10

from .dirBar import Bar
Run Code Online (Sandbox Code Playgroud)

代替:

from dirBar import Bar
Run Code Online (Sandbox Code Playgroud)

以防万一可以安装另一个dirBar并混淆foo.py阅读器.

  • 我无法在Windows上执行此操作.这是在Linux上吗? (2认同)
  • 它将通过导入 Foo 的脚本工作。即:main.py 导入 dirFoo.Foo。如果您尝试将 Foo.py 作为脚本运行,它将失败。请参阅http://stackoverflow.com/questions/72852/how-to-do-relative-imports-in-python (2认同)

Al *_*rad 9

对于这种情况,将Bar.py导入Foo.py,首先我将这些文件夹转换为Python包,如下所示:

dirFoo\
    __init__.py
    Foo.py
    dirBar\
        __init__.py
        Bar.py
Run Code Online (Sandbox Code Playgroud)

然后我会在Foo.py中这样做:

from .dirBar import Bar
Run Code Online (Sandbox Code Playgroud)

如果我希望命名空间看起来像Bar.无论如何,或

from . import dirBar
Run Code Online (Sandbox Code Playgroud)

如果我想要命名空间dirBar.Bar.不管.如果dirBar包下有更多模块,则第二种情况很有用.


小智 7

添加__init__.py文件:

dirFoo\
    Foo.py
    dirBar\
        __init__.py
        Bar.py
Run Code Online (Sandbox Code Playgroud)

然后将此代码添加到Foo.py的开头:

import sys
sys.path.append('dirBar')
import Bar
Run Code Online (Sandbox Code Playgroud)

  • 如果`dirBar`已经是一个Python包(由于存在`dirBar/__ init __.py`),则不需要将`dirBar`附加到`sys.path`,不是吗?来自`Foo.py`的语句`import Bar`就足够了. (5认同)

Der*_*ter 5

相对sys.path示例:

# /lib/my_module.py
# /src/test.py


if __name__ == '__main__' and __package__ is None:
    sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../lib')))
import my_module
Run Code Online (Sandbox Code Playgroud)

基于这个答案.


Ave*_*Gez 5

好了,正如您提到的,通常您希望访问一个包含您的模块的文件夹(相对于您的主脚本的运行位置),因此您只需导入它们即可。

解:

我有脚本D:/Books/MyBooks.py和一些模块(如oldies.py)。我需要从子目录导入D:/Books/includes

import sys,site
site.addsitedir(sys.path[0] + '\\includes')
print (sys.path)  # Just verify it is there
import oldies
Run Code Online (Sandbox Code Playgroud)

print('done')放在中oldies.py,以便您确认一切正常。这种方法始终有效,因为sys.path根据程序启动时初始化的Python定义,此列表的第一项path[0]是包含用于调用Python解释器的脚本的目录。

如果脚本目录不可用(例如,如果解释器是交互式调用的,或者从标准输入中读取了脚本),path[0]则为空字符串,它将引导Python首先搜索当前目录中的模块。请注意,作为的结果,在插入条目之前插入了脚本目录PYTHONPATH