如何导入给定相对路径的Python模块?

例如,如果dirFoo包含Foo.py和dirBar,而dirBar包含Bar.py,我如何将Bar.py导入Foo.py?

下面是一个视觉表示:

dirFoo\
    Foo.py
    dirBar\
        Bar.py

Foo希望包含Bar,但重组文件夹层次结构不是一个选项。


确保dirBar具有__init__.py文件——这会将一个目录放入Python包中。


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

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

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

import dirFoo.Foo

Or:

from dirFoo.Foo import FooObject

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


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

import sys
sys.path.insert(0, <path to dirFoo>)
import Bar

这是相关的政治公众人物:

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

特别是,假设dirFoo是从dirBar开始的目录。。。

在dirFoo\Foo.py中:

from ..dirBar import Bar

最简单的方法是使用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)

添加__init__.py文件:

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

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

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

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

from dirBar.Bar import *

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


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 <Your Module name>

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


假设您的两个目录都是真正的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使用您的模块,而不是安装在系统上的模块。

警告我真的不知道当当前模块在蛋文件中时会发生什么。它可能也会失败。


from .dirBar import Bar

而不是:

from dirBar import Bar

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


称我过于谨慎,但我喜欢让我的更便携,因为假设文件总是在每台计算机上的同一位置是不安全的。就我个人而言,我让代码先查找文件路径。我使用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!")

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


以下是使用相对路径从上面的一个级别导入文件的方法。

基本上,只需将工作目录向上移动一个级别(或任何相对位置),将其添加到路径中,然后将工作目录移回其起始位置。

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

Linux用户快速而肮脏的方式

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

ln -s (path)/module_name.py

or

ln -s (path)/package_name

注意:“模块”是扩展名为.py的任何文件,“包”是包含__init__.py文件(可以是空文件)的任何文件夹。从使用的角度来看,模块和包是相同的——都会根据import命令的请求公开其包含的“定义和语句”。

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


不修改脚本的最简单方法是设置PYTHONPATH环境变量。因为sys.path是从以下位置初始化的:

包含输入脚本的目录(或当前目录)。PYTHONPATH(目录名列表,与语法作为外壳变量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']

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

基于这个答案。


在本例中,要将Bar.py导入Foo.py,首先我会将这些文件夹转换为Python包,如下所示:

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

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

from .dirBar import Bar

如果我希望名字空间看起来像Bar.whatever,或者

from . import dirBar

如果我想要名称空间dirBar.Bar.whatever。如果您在dirBar包下有更多模块,则第二种情况非常有用。


嗯,正如您所提到的,通常您希望能够访问与主脚本运行位置相关的模块文件夹,因此只需导入它们。

解决方案:

我有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中放置一个打印(“done”),这样您就可以验证一切正常。这种方式总是有效的,因为根据程序启动时初始化的Python定义sys.path,此列表的第一项路径[0]是包含用于调用Python解释器的脚本的目录。

如果脚本目录不可用(例如,如果以交互方式调用解释器或从标准输入读取脚本),则路径[0]是空字符串,它指示Python首先搜索当前目录中的模块。请注意,脚本目录是在PYTHONPATH插入的条目之前插入的。


另一个解决方案是安装py-require包,然后在Foo.py中使用以下内容

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

我对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,它将运行func1()定义的内容。这通常是我们导入相同层次结构文件的方式。但当您从module_2.py中的.module_1 import func_1写入时,python解释器将显示No module named'__main__.module_1';'__main__'不是包。因此,为了解决这个问题,我们只需保留刚才所做的更改,并将两个模块移动到一个包中,然后将第三个模块作为调用方运行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_2.py中的module_1之前,如果我们不这样做并运行main.py,python解释器会说没有名为“module_1”的模块,这有点棘手,module_1.py就在module_.py旁边。现在我让module_1.y中的func_1()做一些事情:

def func_1():
    print(__name__)

__name__记录谁调用func_1。现在我们保留。在module1之前,运行main.py,它将打印package1.module1,而不是module1。它表示调用func_1()的人与main.py位于同一层次结构中。暗示module1与module2.py本身处于同一层次结构。因此,如果没有点,main.py将在与自身相同的层次结构中识别模块_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:试图在顶级包之外进行相对导入。这里的“顶级包”是main.py。正因为config.py在main.py的旁边,所以它们处于相同的层次结构中,config.py不是“在”main.py之下,或者它不是由main.py“引导”的,所以它超出了main.py之外。要解决这个问题,最简单的方法是:

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

我认为这符合排列项目文件层次结构的原则,您应该在不同的文件夹中排列具有不同功能的模块,只需在外部保留一个顶级调用程序,您就可以随意导入。


只需使用:从Desktop.filename导入一些内容

例子:

给定目录中的文件名为test.py用户/用户/桌面,并将导入所有内容。

代码:

from Desktop.test import *

但请确保在该目录中创建一个名为“__init__.py”的空文件


这同样有效,而且比使用sys模块简单得多:

with open("C:/yourpath/foobar.py") as f:
    eval(f.read())