Importing modules from parent folder
我在运行python 2.5。
这是我的文件夹树:
1 2 3 4 5 | ptdraft/ nib.py simulations/ life/ life.py |
(我在每个文件夹中也有
如何从
注:正在运行的主模块位于
可以使用相对导入(python>=2.5):
1 | from ... import nib |
(python 2.5的新功能)pep 328:绝对和相对导入
编辑:添加了另一个点"."以向上移动两个包
相对进口(如
1 2 3 4 5 6 | import os,sys,inspect currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) parentdir = os.path.dirname(currentdir) sys.path.insert(0,parentdir) import mymodule |
编辑:并不总是给定
这个问题似乎与模块在父目录或类似的目录中无关。
您需要将包含
你说
我也发布了一个类似的答案,关于从兄弟包中导入的问题。你可以在这里看到。下面用python 3.6.5(anaconda,conda 4.5.1),windows 10机器进行测试。
没有sys.path hacks的解决方案安装程序我假设与问题中的文件夹结构相同
1 2 3 4 5 6 7 8 9 | . └── ptdraft ├── __init__.py ├── nib.py └── simulations ├── __init__.py └── life ├── __init__.py └── life.py |
我把
1 2 3 | from setuptools import setup, find_packages setup(name='myproject', version='1.0', packages=find_packages()) |
基本上,"any"setup.py可以工作。这只是一个最小的工作示例。
2)使用虚拟环境如果您熟悉虚拟环境,请激活其中一个,然后跳到下一步。虚拟环境的使用并不是绝对必要的,但从长远来看,它们确实会帮助您(当您有一个以上的项目正在进行时)。最基本的步骤是(在根文件夹中运行)
- 创建虚拟环境
python -m venv venv
- 激活虚拟环境
. /venv/bin/activate (linux)或./venv/Scripts/activate (win)
要了解更多信息,只需谷歌出"python virtual env tutorial"或类似内容。除了创建、激活和停用之外,您可能永远不需要任何其他命令。
创建并激活虚拟环境后,控制台应在括号中给出虚拟环境的名称。
1 2 3 | PS C:\tmp\test_imports> python -m venv venv PS C:\tmp\test_imports> .\venv\Scripts\activate (venv) PS C:\tmp\test_imports> |
3)pip在可编辑状态下安装项目
使用
在根目录中,运行
您还可以看到它是通过使用
1 2 3 4 5 6 7 | (venv) PS C:\tmp\test_imports> pip install -e . Obtaining file:///C:/tmp/test_imports Installing collected packages: myproject Running setup.py develop for myproject Successfully installed myproject (venv) PS C:\tmp\test_imports> pip freeze myproject==1.0 |
4)每项进口附加
在这个例子中,
1 2 | def function_from_nib(): print('I am the return value from function_from_nib!') |
生命.Py
1 2 3 4 | from ptdraft.nib import function_from_nib if __name__ == '__main__': function_from_nib() |
运行寿命
1 2 | (venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py I am the return value from function_from_nib! |
如果将模块文件夹添加到python path不起作用,可以修改程序中的sys.path列表,其中python解释器搜索要导入的模块,python文档说:
When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:
- the directory containing the input script (or the current directory).
- PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
- the installation-dependent default.
After initialization, Python programs can modify sys.path. The directory containing the script being run is placed at the beginning of the search path, ahead of the standard library path. This means that scripts in that directory will be loaded instead of modules of the same name in the library directory. This is an error unless the replacement is intended.
< /块引用>
知道了这一点,您可以在程序中执行以下操作:
1
2
3
4
5
6
7
8 import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append('/path/to/ptdraft/')
# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft您可以在sys.path中列出的"模块搜索路径"中使用OS依赖路径。这样您就可以轻松地添加父目录,如下所示
1
2 import sys
sys.path.insert(0,'..')如果要添加父目录,
1 sys.path.insert(0,'../..')不太了解python 2。
在python 3中,可以按如下方式添加父文件夹:
1
2 import sys
sys.path.append('..')…然后可以从中导入模块
下面是更通用的解决方案,它将父目录包含到sys.path中(对我有效):
1
2 import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))这里有一个简单的答案,你可以看到它是如何工作的,小而跨平台。它只使用内置模块(
更短的应答代码-更少的行和变量os 、sys 和inspect ,因此应该可以工作在任何操作系统(OS)上,因为python是为此而设计的。
1
2
3
4
5
6 from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module # Replace"my_module" here with the module name.
sys.path.pop(0)对于少于此的线路,用
我的答案代码(较长版本)import os.path as path, sys, inspect 替换第二条线路。在getsourcefile 的开头(第3行)加上inspect. ,去掉第一行。-但是,这会导入所有模块,因此可能需要更多的时间、内存和资源。
1
2
3
4
5
6
7
8
9
10
11 from inspect import getsourcefile
import os.path
import sys
current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]
sys.path.insert(0, parent_dir)
import my_module # Replace"my_module" here with the module name.它使用一个来自堆栈溢出应答的示例,如何获取当前的路径在python中执行文件?使用内置工具查找运行代码的源(文件名)。
1
2 from inspect import getsourcefile
from os.path import abspathNext, wherever you want to find the source file from you just use:
1 abspath(getsourcefile(lambda:0))我的代码为
sys.path 添加了一个文件路径,即python路径列表因为这允许python从该文件夹导入模块。在代码中导入模块后,最好在新行上运行
关于文件名变量的说明sys.path.pop(0) 。当添加的文件夹具有与导入的另一个模块同名的模块时在节目后期。您需要删除导入前添加的列表项,而不是其他路径。如果您的程序不导入其他模块,则不删除文件路径是安全的,因为程序结束(或重新启动python shell)后,对sys.path 所做的任何编辑都将消失。我的答案不使用
__file__ 变量获取运行的文件路径/文件名。因为这里的用户经常说它不可靠。你不应该用它用于从其他人使用的程序中的父文件夹导入模块。一些不起作用的例子(引用这个堆栈溢出问题):
?在某些平台上找不到?有时不是完整的文件路径
py2exe doesn't have a__file__ attribute, but there is a workaround- When you run from IDLE with
execute() there is no__file__ attribute- OS X 10.6 where I get
NameError: global name '__file__' is not defined 对于我来说,访问父目录的最短和最喜欢的一行程序是:
1 sys.path.append(os.path.dirname(os.getcwd()))或:
1 sys.path.insert(1, os.path.dirname(os.getcwd()))getcwd()返回当前工作目录的名称,os.path.dirname(directory_name)返回传递的目录的名称。
实际上,在我看来,python项目体系结构应该以这样的方式完成:子目录中的任何模块都不会使用父目录中的任何模块。如果发生这样的事情,就值得重新考虑项目树。
另一种方法是将父目录添加到pythonpath系统环境变量。
import sys
sys.path.append('../')
当不在包含
__init__.py 文件的包环境中时,pathlib库(包含在>=python 3.4中)使将父目录的路径附加到python path变得非常简洁和直观:
1
2
3 import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))上述解决方案也可以。这个问题的另一个解决办法是
如果要从顶级目录导入任何内容。然后,
1 from ...module_name import *另外,如果您想从父目录导入任何模块。然后,
1 from ..module_name import *另外,如果您想从父目录导入任何模块。然后,
1 from ...module_name.another_module import *这样,您可以导入任何特定的方法(如果需要)。
和过去的答案一样的风格-但是用更少的行:p
1
2
3 import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)文件返回您工作的位置
使用库。创建一个名为nib的库,使用setup.py安装它,让它驻留在站点包中,您的问题就解决了。你不必把你做的每样东西都装在一个包裹里。把它分成几块。
在Linux系统中,您可以创建一个从"life"文件夹到nib.py文件的软链接。然后,您可以简单地导入它,如下所示:
1 import nib