从相对路径导入模块

2024-11-27 10:43:00
admin
原创
12
摘要:问题描述:如何根据给定的相对路径导入 Python 模块?例如,如果dirFoo包含Foo.py和dirBar,且dirBar包含Bar.py,我该如何Bar.py导入Foo.py?以下是一个直观的表示:dirFoo\n Foo.py dirBar\n Bar.py Foo希望包括...

问题描述:

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

例如,如果dirFoo包含Foo.pydirBar,且dirBar包含Bar.py,我该如何Bar.py导入Foo.py

以下是一个直观的表示:

dirFoo\n    Foo.py
    dirBar\n        Bar.py

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


解决方案 1:

假设您的两个目录都是真正的 Python 包(__init__.py其中确实有文件),那么这里有一个相对于脚本位置包含模块的安全解决方案。

我假设您想要这样做,因为您需要在脚本中包含一组模块。我在多个产品的生产中都使用了这种方法,并且适用于许多特殊场景,例如:从另一个目录调用脚本或使用 python execute 执行脚本,而不是打开新的解释器。

 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文件内部时会发生什么。它可能也会失败。

解决方案 2:

确保 dirBar 有该__init__.py文件——这会将目录变成 Python 包。

解决方案 3:

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

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

解决方案 4:

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

import mymodule

解决方案 5:

只需做一些简单的事情就可以从不同的文件夹导入.py 文件。

假设您有一个如下目录:

lib/abc.py

然后只需在 lib 文件夹中保留一个名为

__init__.py

然后使用

from lib.abc import <Your Module name>

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

解决方案 6:

如果你按照如下方式构建你的项目:

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

然后从 Foo.py 你应该能够执行以下操作:

import dirFoo.Foo

或者:

from dirFoo.Foo import FooObject

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

解决方案 7:

这是相关的 PEP:

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

具体来说,假设 dirFoo 是 dirBar 的上游目录……

在 dirFoo\Foo.py 中:

from .dirBar import Bar

解决方案 8:

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

解决方案 9:

最简单的方法就是设置 PYTHONPATH 环境变量,而无需对脚本进行任何修改。因为 sys.path 是从以下位置初始化的:

  1. 包含输入脚本的目录(或当前目录)。

  2. PYTHONPATH(目录名称列表,语法与 shell 变量 PATH 相同)。

  3. 依赖于安装的默认值。

只需运行:

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']

解决方案 10:

我认为最好的选择是将__ init __.py放在文件夹中,然后使用以下命令调用该文件

from dirBar.Bar import *

不建议使用 sys.path.append(),因为如果使用与现有 python 包相同的文件名,可能会出错。我还没有测试过,但那样会产生歧义。

解决方案 11:

from .dirBar import Bar

而不是:

from dirBar import Bar

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

解决方案 12:

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

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

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

from .dirBar import Bar

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

from . import dirBar

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

解决方案 13:

Linux 用户的快捷方法

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

ln -s (path)/module_name.py

或者

ln -s (path)/package_name

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

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

解决方案 14:

添加__init__.py文件:

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

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

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

解决方案 15:

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

根据这个答案。

解决方案 16:

另一个解决方案是安装py-require包,然后在Foo.py

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

解决方案 17:

嗯,正如您所说,通常您希望访问一个包含模块的文件夹,该文件夹相对于主脚本的运行位置,因此您只需导入它们。

解决方案:

我有脚本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

解决方案 18:

您只需使用:from Desktop.filename import something

例子:

假设文件是test.py​​目录中的
名称Users/user/Desktop,并且将导入所有内容。

代码:

from Desktop.test import *

__init__.py但请确保在该目录中创建一个名为“

解决方案 19:

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

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

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

解决方案 20:

我对 Python 不是很熟悉,所以如果我说的有错,请告诉我。如果你的文件层次结构如下:

project\n    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.pypython 解释器会说No module named '__main__.module_1'; '__main__' is not a package。因此,为了解决这个问题,我们只需保留我们刚刚所做的更改,将两个模块移到一个包中,并将第三个模块作为调用者来运行module_2.py

project\n    package_1\n        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()

但是我们在.之前添加一个的原因是如果我们不这样做并运行,python 解释器会说,这有点棘手,就在旁边。现在我让in做一些事情:module_1`module_2.pymain.pyNo module named 'module_1'module_1.pymodule_2.pyfunc_1()module_1.py`

def func_1():
    print(__name__)

记录了__name__谁调用了 func_1。现在我们保留.之前的module_1,运行main.py,它将打印package_1.module_1,而不是module_1。它表明调用者func_1()与 处于同一层次main.py.暗示module_1与其自身处于同一层次module_2.py。因此,如果没有点,main.py它将识别module_1与自身处于同一层次,它可以识别package_1,但不能识别其“下方”的内容。

现在让我们让它变得复杂一点。你有一个,config.ini并且一个模块定义了一个函数来在与“main.py”相同的层次结构中读取它。

project\n    package_1\n        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.py它在 旁边main.py,它们在同一个层次,config.py不在 之下main.py,或者它不是由 引导的main.py,所以它在 之外main.py。要解决这个问题,最简单的方法是:

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

我认为这与安排项目文件层次的原则是一致的,你应该将具有不同功能的模块安排在不同的文件夹中,并在外面留下一个最上面的调用者,你可以随意导入。

解决方案 21:

这也有效,并且比使用该sys模块的任何方法都简单得多:

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

解决方案 22:

也许我过于谨慎,但我想让我的代码更具可移植性,因为假设文件在每台计算机上总是位于同一个位置是不安全的。我个人会让代码先查找文件路径。我使用 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!")

当然,除非您计划将它们打包在一起。但如果是这样的话,您实际上并不需要两个单独的文件。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   642  
  引言在当今快速变化的科技市场中,企业要想保持竞争力,就必须具备高效的产品开发流程。小米作为一家以创新驱动的科技公司,其集成产品开发(IPD)流程在业界颇受关注。其中,技术路线图规划作为IPD流程的核心环节,对于确保产品技术领先、满足市场需求以及实现长期战略目标至关重要。本文将深入探讨小米IPD流程中的技术路线图规划,分...
华为IPD是什么   0  
  在当今快速变化的商业环境中,项目管理的高效执行是企业成功的关键。为了应对日益复杂的产品开发挑战,企业纷纷寻求将产品开发流程(Product Development Process, PDCP)与集成产品开发(Integrated Product Development, IPD)流程相结合的策略,以实现更高效、更协同的...
IPD管理   0  
  在当今竞争激烈的市场环境中,提高客户满意度是企业持续发展和成功的关键。为了实现这一目标,企业需要不断优化其产品开发和管理流程。IPD(Integrated Product Development,集成产品开发)流程图作为一种高效的项目管理工具,能够帮助企业实现跨部门协作、优化资源配置,并最终提升客户满意度。本文将深入探...
IPD流程是谁发明的   0  
  在项目管理领域,集成产品开发(IPD, Integrated Product Development)流程被视为提升项目成功率的关键框架。IPD通过其系统化的方法,将产品开发过程中的各个阶段紧密连接,确保从概念到市场的每一步都经过深思熟虑和高效执行。本文将深入探讨IPD流程的六个核心阶段如何深刻影响项目成功,并为项目管...
IPD流程中CDCP   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用