Import a module from a relative path
如何导入给定相对路径的python模块?
例如,如果
这是一个直观的表示:
1 2 3 4 | dirFoo\ Foo.py dirBar\ Bar.py |
假设您的两个目录都是真实的python包(其中确实有
我假设您希望这样做,因为您需要在脚本中包含一组模块。我在一些产品的生产中使用它,并在许多特殊的场景中工作,例如:从另一个目录调用脚本或使用python execute执行脚本,而不是打开一个新的解释器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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使用您的模块,而不是安装在系统上的模块。
警告!我真的不知道当当前模块在一个
确保dirbar有
您还可以将子目录添加到您的python路径中,以便它作为普通脚本导入。
1 2 3 | import sys sys.path.insert(0, <path to dirFoo>) import Bar |
1 2 3 4 5 6 | import os import sys lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib')) sys.path.append(lib_path) import mymodule |
只需做一些简单的事情,从另一个文件夹导入.py文件即可。
假设您有如下目录:
1 | lib/abc.py |
然后在lib文件夹中保留一个名为的空文件
1 | __init__.py |
然后使用
1 | from lib.abc import <Your Module name> |
将
如果您以这种方式构建项目:
1 2 3 4 5 6 7 8 9 | src\ __init__.py main.py dirFoo\ __init__.py Foo.py dirBar\ __init__.py Bar.py |
那么从foo.py开始,你应该能够做到:
1 | import dirFoo.Foo |
或:
1 | from dirFoo.Foo import FooObject |
根据Tom的评论,这确实要求可以通过
最简单的方法是使用sys.path.append()。
但是,您也可能对IMP模块感兴趣。它提供对内部导入功能的访问。
1 2 3 | # 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 |
当您不知道模块的名称时,可以使用它动态加载模块。
我在过去用它创建了一个应用程序的插件类型接口,在那里用户将编写一个具有应用程序特定功能的脚本,并将其放到一个特定的目录中。
此外,这些功能可能有用:
1 2 | imp.find_module(name[, path]) imp.load_module(name, file, pathname, description) |
这是相关的政治公众人物:
http://www.python.org/dev/peps/pep-0328/
特别是,假设dirfoo是从dirbar向上的目录…
在dirfoofoo.py中:
1 | from ..dirBar import Bar |
不修改脚本的最简单方法是设置pythonpath环境变量。因为sys.path是从以下位置初始化的:
只是运行:
1 | export PYTHONPATH=/absolute/path/to/your/module |
sys.path将包含上述路径,如下所示:
1 2 3 | 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'] |
在我看来,最好的选择是将init.py放在文件夹中,并用
1 | from dirBar.Bar import * |
不建议使用sys.path.append(),因为如果使用与现有python包相同的文件名,可能会出现问题。我还没有测试过,但那将是模棱两可的。
Linux用户快速而肮脏的方法
如果您只是在修补,不关心部署问题,那么可以使用一个符号链接(假设您的文件系统支持它),使模块或包在请求模块的文件夹中直接可见。
1 | ln -s (path)/module_name.py |
或
1 | ln -s (path)/package_name |
注:"模块"是任何扩展名为.py的文件,"包"是任何包含文件
参见:http://docs.python.org/2/tutorial/modules.html
1 | from .dirBar import Bar |
而不是:
1 | from dirBar import Bar |
以防安装了另一个dirbar并混淆了foo.py阅读器。
对于这个案例,要将bar.py导入foo.py,首先我将把这些文件夹转换成python包,如下所示:
1 2 3 4 5 6 | dirFoo\ __init__.py Foo.py dirBar\ __init__.py Bar.py |
然后我会在foo.py中这样做:
1 | from .dirBar import Bar |
如果我想让名称间距看起来像条形图的话。
1 | from . import dirBar |
如果我想要名字间距dirbar.bar.whatever。如果dirbar包下有更多的模块,则第二种情况非常有用。
添加一个uuu init_uuu.py文件:
1 2 3 4 5 | dirFoo\ Foo.py dirBar\ __init__.py Bar.py |
然后将此代码添加到foo.py的开头:
1 2 3 | import sys sys.path.append('dirBar') import Bar |
相对sys.path示例:
1 2 3 4 5 6 7 | # /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 |
基于这个答案。
嗯,正如您提到的,通常您希望能够访问一个文件夹,其中包含与主脚本运行位置相关的模块,所以您只需导入它们。
解决方案:
我有
1 2 3 4 | import sys,site site.addsitedir(sys.path[0] + '\\includes') print (sys.path) # Just verify it is there import oldies |
把一个
如果脚本目录不可用(例如,如果以交互方式调用解释器或从标准输入读取脚本),则
另一种解决方案是安装py-require包,然后在
1 2 | import require Bar = require('./dirBar/Bar') |
只需使用:
例子:
given that the file is name
test.py in directory
Users/user/Desktop , and will import everthing.
代码:
1 | from Desktop.test import * |
但请确保在该目录中生成一个名为"EDOCX1"(43)的空文件
从标准库中查看pkgutil模块。它可以帮助你做你想做的事。
下面是使用相对路径从上面的一个级别导入文件的方法。
基本上,只需将工作目录向上移动一个级别(或任何相对位置),将其添加到您的路径中,然后将工作目录移回它开始的位置。
1 2 3 4 5 6 | #to import from one level above: cwd = os.getcwd() os.chdir("..") below_path = os.getcwd() sys.path.append(below_path) os.chdir(cwd) |
我对python没有经验,所以如果我的话有任何错误,就告诉我。如果文件层次结构按如下方式排列:
1 2 3 | project\ module_1.py module_2.py |
1 2 3 4 5 6 7 | from module_1 import func_1 def func_2(): func_1() if __name__ == '__main__': func_2() |
在命令中运行
1 2 3 4 5 | project\ package_1\ module_1.py module_2.py main.py |
MY.PY:
1 2 3 4 5 6 7 | from package_1.module_2 import func_2 def func_3(): func_2() if __name__ == '__main__': func_3() |
但是我们在
1 2 | def func_1(): print(__name__) |
据
现在让我们把它弄复杂一点。您有一个
1 2 3 4 5 6 7 | project\ package_1\ module_1.py module_2.py config.py config.ini main.py |
由于一些不可避免的原因,您必须使用
1 2 | import ..config pass |
两个点表示从上层导入(三个点访问上层,等等)。现在我们运行
1 2 3 4 5 6 7 | project\ package_1\ module_1.py module_2.py config.py config.ini main.py |
我认为这与排列项目文件层次结构的原则是一致的,您应该在不同的文件夹中排列具有不同功能的模块,只需在外部留下一个顶级调用方,您就可以随心所欲地导入。
这同样有效,而且比使用
1 2 | with open("C:/yourpath/foobar.py") as f: eval(f.read()) |
称我过于谨慎,但我喜欢让我的更便携,因为假设每个计算机上的文件总是在同一个位置是不安全的。就我个人而言,我让代码先查找文件路径。我使用Linux,所以我的看起来像这样:
1 2 3 4 5 6 7 8 | 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!") |
当然,除非你打算把这些包装在一起。但如果是这样的话,你也不需要两个单独的文件。