如何根据相对路径导入Python模块?
例如,如果dirFoo
包含Foo.py
和dirBar
,和dirBar
包含Bar.py
,我怎么导入Bar.py
到Foo.py
?
这是一个直观的表示:
dirFoo\ Foo.py dirBar\ Bar.py
Foo
希望包括Bar
,但重组文件夹层次结构不是一种选择.
假设您的两个目录都是真正的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.
作为奖励,这种方法可以让您强制Python使用您的模块而不是系统上安装的模块.
警告!当前模块在egg
文件中时,我真的不知道发生了什么.它可能也失败了.
确保dirBar具有该__init__.py
文件 - 这使得目录成为Python包.
您还可以将子目录添加到Python路径中,以便将其作为普通脚本导入.
import sys sys.path.insert(0,) import Bar
import os import sys lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib')) sys.path.append(lib_path) import mymodule
只需简单的操作就可以从其他文件夹中导入.py文件.
假设你有一个像这样的目录:
lib/abc.py
然后在lib文件夹中保留一个空文件作为命名
__init__.py
然后使用
from lib.abc import
将__init__.py
文件保留在导入模块的层次结构的每个文件夹中.
如果以这种方式构建项目:
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的评论,这确实需要src
通过site_packages
或您的搜索路径访问该文件夹.此外,正如他所提到的,__init__.py
当您首次导入该包/目录中的模块时,会隐式导入.通常__init__.py
只是一个空文件.
最简单的方法是使用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
当您不知道模块的名称时,这可用于动态加载模块.
我过去曾使用它来创建应用程序的插件类型接口,用户可以在其中编写具有应用程序特定功能的脚本,并将脚本放在特定目录中.
此外,这些功能可能很有用:
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环境变量.因为sys.path是从这些位置初始化的:
包含输入脚本(或当前目录)的目录.
PYTHONPATH(目录名列表,语法与shell变量PATH相同).
依赖于安装的默认值.
赶紧跑:
export PYTHONPATH=/absolute/path/to/your/module
您的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']
在我看来,最好的选择是将__ init __.py放在文件夹中并使用
from dirBar.Bar import *
建议不要使用sys.path.append(),因为如果使用与现有python包相同的文件名,可能会出错.我没有测试,但那将是模棱两可的.
如果您只是在修补并且不关心部署问题,则可以使用符号链接(假设您的文件系统支持它)使模块或包直接在请求模块的文件夹中可见.
ln -s (path)/module_name.py
要么
ln -s (path)/package_name
注意:"模块"是任何扩展名为.py的文件,"package"是包含该文件的任何文件夹__init__.py
(可以是空文件).从使用的角度来看,模块和包是相同的 - 都通过import
命令公开它们包含的"定义和语句" .
请参阅:http://docs.python.org/2/tutorial/modules.html
from .dirBar import Bar
代替:
from dirBar import Bar
以防万一可以安装另一个dirBar并混淆foo.py阅读器.
对于这种情况,将Bar.py导入Foo.py,首先我将这些文件夹转换为Python包,如下所示:
dirFoo\ __init__.py Foo.py dirBar\ __init__.py Bar.py
然后我会在Foo.py中这样做:
from .dirBar import Bar
如果我希望命名空间看起来像Bar.无论如何,或
from . import dirBar
如果我想要命名空间dirBar.Bar.不管.如果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
将print('done')
放在中oldies.py
,以便您确认一切正常。这种方法始终有效,因为sys.path
根据程序启动时初始化的Python定义,此列表的第一项path[0]
是包含用于调用Python解释器的脚本的目录。
如果脚本目录不可用(例如,如果解释器是交互式调用的,或者从标准输入中读取了脚本),path[0]
则为空字符串,它将引导Python首先搜索当前目录中的模块。请注意,作为的结果,在插入条目之前插入了脚本目录PYTHONPATH
。