从相对path导入模块

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

例如,如果dirFoo包含Foo.pydirBar ,并且dirBar包含Bar.py ,那么如何将Bar.py导入到Foo.py

这是一个视觉表示:

 dirFoo\ Foo.py dirBar\ Bar.py 

Foo希望包含Bar ,但重构文件夹层次结构不是一种select。

假设你的两个目录都是真正的Python包(里面有__init__.py文件),这里有一个安全的解决scheme来包含相对于脚本位置的模块。

我假设你想这样做,因为你需要在脚本中包含一组模块。 我在几个产品的生产中使用它,并在许多特殊的情况下工作,如:从另一个目录调用脚本或用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. 

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

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

确保dirBar具有__init__.py文件 – 这使得一个目录变成一个Python包。

您也可以将子目录添加到您的Pythonpath,以便作为普通脚本导入。

 import sys sys.path.append(<path to dirFoo>) import Bar 
 import os, sys lib_path = os.path.abspath(os.path.join('..', '..', '..', 'lib')) sys.path.append(lib_path) import mymodule 

只需做简单的事情来从另一个文件夹导入.py文件。

假设你有一个目录:

 lib/abc.py 

然后只保留一个空文件在lib文件夹中作为named

 __init__.py 

然后使用

 from lib.abc import <Your Module name> 

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

如果你这样构build你的项目:

 src\ __init__.py main.py dirFoo\ __init__.py Foo.py dirBar\ __init__.py Bar.py 

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

 import dirFoo.Foo 

要么:

 from dirFoo.Foo import FooObject 

根据Tom的评论,这确实需要通过site_packages或searchpath来访问src文件夹。 另外,正如他所提到的,当您首次在该包/目录中导入一个模块时,隐式地导入__init__.py 。 通常__init__.py是一个简单的空文件。

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

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

 # 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 

当你不知道模块的名字时,这可以用来dynamic地加载模块。

过去我使用过这种方式为应用程序创build一个插件types的接口,用户可以在其中编写一个具有特定应用程序function的脚本,然后将脚本放在特定的目录中。

另外,这些function可能是有用的:

 imp.find_module(name[, path]) imp.load_module(name, file, pathname, description) 

这是相关的PEP:

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

特别是,假设dirFoo是一个从dirBar的目录…

在dirFoo \ Foo.py中:

 from ..dirBar import Bar 

没有任何修改脚本的最简单的方法是设置PYTHONPATH环境variables。 因为sys.path是从这些位置初始化的:

  1. 包含input脚本(或当前目录)的目录。
  2. PYTHONPATH(目录名称列表,与shellvariablesPATH语法相同)。
  3. 安装相关的默认值。

赶紧跑:

 export PYTHONPATH=/absolute/path/to/your/module 

你的sys.path将包含上面的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'] 

在我看来,最好的select是将__ init __.py放在文件夹中,然后调用该文件

 from dirBar.Bar import * 

不build议使用sys.path.append(),因为如果使用与现有python包相同的文件名,可能会出现问题。 我没有testing,但这将是暧昧的。

 from .dirBar import Bar 

代替:

 from dirBar import Bar 

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

Linux用户的快捷方式

如果您只是摆弄一下,不关心部署问题,则可以使用符号链接(假定您的文件系统支持该链接)使模块或包在请求模块的文件夹中直接可见。

 ln -s (path)/module_name.py 

要么

 ln -s (path)/package_name 

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

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

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

 dirFoo\ __init__.py Foo.py dirBar\ __init__.py Bar.py 

那么我会在Foo.py中这样做:

 from .dirBar import Bar 

如果我想命名空间看起来像吧。 无论什么 ,或者

 from . import dirBar 

如果我想命名空间dirBar.Bar。 不pipe 。 如果在dirBar包中有更多的模块,则第二种情况非常有用。

添加一个__init__.py文件:

 dirFoo\ Foo.py dirBar\ __init__.py Bar.py 

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

 import sys sys.path.append('dirBar') import Bar 

相对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 

根据这个答案。

那么,正如你所提到的那样,通常你想使用模块访问一个文件夹,相对于你的主脚本运行的地方,所以你只需要导入它们。

解:

我有在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 

oldies.py放置一个print('done') ,这样你就可以确认一切正常。 这种方式总是有效的,因为通过程序启动时初始化的Python定义sys.path ,这个列表的第一个项目path[0]是包含用于调用Python解释器的脚本的目录。

如果脚本目录不可用(例如,如果解释器是交互式调用的,或者脚本是从标准input读取的),则path[0]是空string,它指示Python首先search当前目录中的模块。 请注意,由于PYTHONPATH而插入的条目之前插入了脚本目录。

另一个解决scheme是安装py-require包,然后在Foo.py使用以下Foo.py

 import require Bar = require('./dirBar/Bar') 

查看标准库中的pkgutil模块。 它可以帮助你做你想做的事情。

这是一种使用相对path从上面的一个级别导入文件的方法。

基本上,只要将工作目录上移一层(或任何相对位置),将其添加到path中,然后将工作目录移回到开始的位置。

 #to import from one level above: cwd = os.getcwd() os.chdir("..") below_path = os.getcwd() sys.path.append(below_path) os.chdir(cwd) 

我对python没有经验,所以如果我的话有任何错误,告诉我。 如果你的文件层次结构如下所示:

 project\ module_1.py module_2.py 

module_1.py定义了一个函数func_1()module_2.py

 from module_1 import func_1 def func_2(): func_1() if __name__ == '__main__': func_2() 

你在cmd中运行python module_2.py ,它会运行func_1()定义的内容。 这通常是我们如何导入相同的层次结构文件。 但是,当你from .module_1 import func_1module_2.py ,python解释器将会说No module named '__main__.module_1'; '__main__' is not a package No module named '__main__.module_1'; '__main__' is not a package 。 所以为了解决这个问题,我们只保留刚做出的修改,然后把这两个模块都移到一个包中,然后把第三个模块作为调用者来运行module_2.py

 project\ package_1\ module_1.py module_2.py main.py 

main.py

 from package_1.module_2 import func_2 def func_3(): func_2() if __name__ == '__main__': func_3() 

但是我们添加一个.module_1中的module_2.py之前,如果我们不这样做,并运行main.py ,python解释器会说No module named 'module_1' ,这有点棘手, module_1.py正好在module_2.py旁边。 现在我让func_1()做一些事情:

 def func_1(): print(__name__) 

__name__logging谁调用func_1。 现在我们保持.module_1之前运行main.py ,它将打印package_1.module_1 ,而不是module_1 。 它表明调用func_1()的人与main.py具有相同的层次结构. 意味着module_1module_2.py本身具有相同的层次结构。 因此,如果没有一个点, main.py会识别module_1与它本身相同的层次结构,它可以识别package_1 ,但不能识别package_1

现在让我们来复杂一点。 你有一个config.ini和一个模块定义一个函数来读取它在'main.py'相同的层次结构。

 project\ package_1\ module_1.py module_2.py config.py config.ini main.py 

而且由于一些不可避免的原因,你必须使用module_2.py来调用它,所以它必须从上层导入。 module_2.py

  import ..config pass 

两点意味着从上层导入(三点以上访问比上层,等等)。 现在我们运行main.py ,解释器会说: ValueError:attempted relative import beyond top-level package 。 这里的“顶级包”是main.py 只是因为config.pymain.py旁边,它们处于相同的层次结构, config.py不是在main.py ,或者不是由main.py “引导”的,所以它不在main.py 。 要解决这个问题,最简单的方法是:

 project\ package_1\ module_1.py module_2.py config.py config.ini main.py 

我认为这与安排项目文件层次结构的原则是一致的,你应该在不同的文件夹中安排具有不同function的模块,只在外面留下一个顶层调用者,你可以导入你想要的东西。

打电话给我过于谨慎,但是我喜欢让我的手机更加便携,因为假设文件总是在每台电脑的相同位置是不安全的。 我个人有代码首先查找文件path。 我使用Linux,所以我会看起来像这样:

 import os, sys from subprocess import Popen, PIPE try: path = Popen("find / -name 'file' -type f", shell=True, stdout=PIPE).stdout.read().splitlines()[0] if not sys.path.__contains__(path): sys.path.append(path) except IndexError: raise RuntimeError("You must have FILE to run this program!") 

当然,除非你打算把这些打包在一起。 但是,如果是这样的话,你不需要两个单独的文件。