从相对路径导入模块
- 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
希望包括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 是从以下位置初始化的:
包含输入脚本的目录(或当前目录)。
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']
解决方案 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_1
,module_2.py
python 解释器会说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.py
No module named 'module_1'module_1.py
module_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!")
当然,除非您计划将它们打包在一起。但如果是这样的话,您实际上并不需要两个单独的文件。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件