给定相对路径,如何导入Python模块?
例如,如果dirFoo
包含Foo.py
和dirBar
,和dirBar
包含Bar.py
,我怎么导入Bar.py
到Foo.py
?
这是一个视觉表示:
dirFoo\
Foo.py
dirBar\
Bar.py
Foo
希望包含Bar
,但重组文件夹层次结构不是一种选择。
给定相对路径,如何导入Python模块?
例如,如果dirFoo
包含Foo.py
和dirBar
,和dirBar
包含Bar.py
,我怎么导入Bar.py
到Foo.py
?
这是一个视觉表示:
dirFoo\
Foo.py
dirBar\
Bar.py
Foo
希望包含Bar
,但重组文件夹层次结构不是一种选择。
Answers:
假设您的两个目录都是真实的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
文件中时会发生什么。它也可能失败。
os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]) + "/subfolder")
待办事项NOT前添加子文件夹abspath
,因为这会导致严重的错误。
cmd_subfolder
)直接添加到我的答案中。谢谢!
realpath
已经生成了绝对路径,所以我不需要abspath
。也os.path.dirname
可以代替拆分使用,从而使索引[0]
过时。该行如下:os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))
确保dirBar具有__init__.py
文件-这会将目录创建到Python包中。
sys.path
那么存在 __init__.py
的dirBar
目录并没有多大帮助。
__init.py__
仅当目录已经在sys.path中并且在我而言不是的情况下,添加才起作用。通过“ sorin”(已接受)解决方案始终有效。
sys.path
问题中呢?也许有一些我们没有看到或不知道的遗漏?
您也可以将子目录添加到Python路径中,以便将其作为普通脚本导入。
import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
sys.path.append(os.path.dirname(__file__) + "/relative/path/to/module")
sys.path.append(__name__ if __name__ != '__main__' else __loader__.fullname)
sys.path.insert(0, <path to dirFoo>)
因为它将在其他位置存储的同名模块之前加载此模块。
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)
import mymodule
os.path.join()
而不是通过'/'进行连接,否则会在(层)窗口中中断。
os.path.abspath(os.path.join(__file__,'..','lib'))
呢?
只需执行简单的操作即可从其他文件夹导入.py文件。
假设您有一个目录,例如:
lib/abc.py
然后只需将一个空文件保留在lib文件夹中,命名为
__init__.py
然后用
from lib.abc import <Your Module name>
将__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
只是一个空文件。
from dirFoo import Foo
说Foo.bla()
。如果使用import dirFoo.Foo
一个应该使用dirFoo.Foo.bla()
-即使没有骆驼盒也很丑陋。
最简单的方法是使用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是从以下位置初始化的:
赶紧跑:
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包相同的文件名,则可能会出错。我还没有测试,但这将是模棱两可的。
from dirBar.Bar import *
,但是没有效果from dirBar.Bar import Bar
。你知道为什么*有效吗?如果我在dirBar /中有多个文件并且只想抓取其中几个文件(使用类似于您在此处发布的方法)怎么办?
from dirBar import Bar
。
from
指示了源,之后的所有内容import
都是从该源获取的内容。from dirBar.Bar import Bar
表示“从源导入本身”,这没有任何意义。在*
虽然手段,“给我的一切,从源头”
如果您只是在修改而不关心部署问题,则可以使用符号链接(假设文件系统支持它)使模块或程序包直接在请求模块的文件夹中可见。
ln -s (path)/module_name.py
要么
ln -s (path)/package_name
注意:“模块”是带有.py扩展名的任何文件,“包”是包含该文件的任何文件夹__init__.py
(可以是空文件)。从使用的角度来看,模块和程序包是相同的-都按照import
命令的要求公开了它们包含的“定义和语句” 。
from .dirBar import Bar
代替:
from dirBar import Bar
以防万一可能会安装另一个dirBar并混淆foo.py阅读器。
好了,正如您提到的,通常您希望访问一个包含您的模块的文件夹,该模块相对于您运行主脚本的位置,因此您只需导入它们即可。
解:
我有脚本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
。
site.addsitedir(sys.path[0]+'/includes')
在我的第一个简单Python程序break_time.py中使用一个正斜杠而不是两个反斜杠(即):https : //github.com/ltfschoen/PythonTest。我使用的系统为:MacOS v10.11.5,Python 2.7.12,IDLE IDE 2.7.12,Tk 8.5.9
只需使用即可: from Desktop.filename import something
例:
鉴于该文件是
test.py
directory目录中的 nameUsers/user/Desktop
,并且将导入所有内容。
编码:
from Desktop.test import *
但是请确保__init__.py
在该目录中创建一个名为“ ” 的空文件
import something
然后为什么我说要使其变得更简单,*
基本上它对ram
另一种解决方案是安装py-require软件包,然后在Foo.py
import require
Bar = require('./dirBar/Bar')
require()
函数,可以看一下我的Node.py项目:github.com/nodepy/nodepy
这是一种使用相对路径从上一级导入文件的方法。
基本上,只需将工作目录上移某个级别(或任何相对位置),然后将其添加到您的路径中,然后再将工作目录移回其开始位置即可。
#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path = os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)
我对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()
并且您python module_2.py
在cmd中运行,它将按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\
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_1
的module_2.py
是,如果我们不这样做,并运行main.py
,Python解释器会说No module named 'module_1'
,这是一个有点棘手,module_1.py
是旁边module_2.py
。现在让我func_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\
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:attempted relative import beyond top-level package
。这里的“顶级程序包”是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
我认为这与安排项目文件层次结构的原理是一致的,您应该将具有不同功能的模块安排在不同的文件夹中,而仅在外部放置一个顶级调用方,然后可以随心所欲地导入。
称我过于谨慎,但我想让我的便携式计算机更加便携,因为假设文件始终位于每台计算机上的同一位置是不安全的。我个人的代码首先查找文件路径。我使用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!")
当然,除非您计划将它们打包在一起。但是,在这种情况下,您实际上并不需要两个单独的文件。