我正在运行Python 2.5。
这是我的文件夹树:
ptdraft/
nib.py
simulations/
life/
life.py
(我在每个文件夹中也有__init__.py
,为了便于阅读,这里省略了)
如何从nib
模块中导入life
模块?我希望有可能不用修补sys.path。
注意:正在运行的主模块位于ptdraft
文件夹中。
答案 0 :(得分:535)
您可以使用相对导入(python> = 2.5):
from ... import nib
(What’s New in Python 2.5) PEP 328: Absolute and Relative Imports
编辑:添加了另一个点'。'上两个包
答案 1 :(得分:226)
相对导入(如from .. import mymodule
)仅适用于包。
要导入当前模块的父目录中的“mymodule”:
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
修改:并非始终提供__file__
属性。而不是使用os.path.abspath(__file__)
我现在建议使用inspect模块来检索当前文件的文件名(和路径)
答案 2 :(得分:101)
似乎问题与父目录中的模块或类似的东西无关。
您需要将包含ptdraft
的目录添加到PYTHONPATH
您说import nib
与您合作,这可能意味着您已将ptdraft
本身(不是其父级)添加到PYTHONPATH。
答案 3 :(得分:59)
我也发布了关于从兄弟套餐进口的问题的类似答案。你可以看到它here。以下是使用Python 3.6.5(Anaconda,conda 4.5.1),Windows 10计算机进行测试。
我假设与问题
中的文件夹结构相同.
└── ptdraft
├── __init__.py
├── nib.py
└── simulations
├── __init__.py
└── life
├── __init__.py
└── life.py
我将.
称为根文件夹,在我的情况下,它位于C:\tmp\test_imports
。
setup.py
的内容可以简单地
from setuptools import setup, find_packages
setup(name='myproject', version='1.0', packages=find_packages())
基本上"任何" setup.py会起作用。这只是一个极小的工作示例。
如果您熟悉虚拟环境,请激活一个,然后跳到下一步。虚拟环境的使用不是绝对,但它们将真的帮助你从长远来看(当你有超过1个项目正在进行..)。最基本的步骤是(在根文件夹中运行)
python -m venv venv
. /venv/bin/activate
(Linux)或./venv/Scripts/activate
(Win)要了解有关此内容的更多信息,请参阅Google的" python虚拟环境教程"或类似的。除了创建,激活和停用之外,您可能永远不需要任何其他命令。
制作并激活虚拟环境后,您的控制台应在括号中提供虚拟环境的名称
PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
使用myproject
安装顶级包pip
。诀窍是在安装时使用-e
标志。这样,它以可编辑状态安装,对.py文件所做的所有编辑将自动包含在已安装的包中。
在根目录中,运行
pip install -e .
(注意点,它代表"当前目录")
您还可以使用pip freeze
(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
mainfolder
附加到每个导入在此示例中,mainfolder
将为ptdraft
。这样做的好处是,您不会遇到与其他模块名称(来自python标准库或第三方模块)的名称冲突。
def function_from_nib():
print('I am the return value from function_from_nib!')
from ptdraft.nib import function_from_nib
if __name__ == '__main__':
function_from_nib()
(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!
答案 4 :(得分:50)
如果将模块文件夹添加到PYTHONPATH不起作用,您可以在程序中修改 sys.path 列表,其中Python解释器搜索要导入的模块,{{3} }说:
导入名为垃圾邮件的模块时,解释程序首先搜索具有该名称的内置模块。如果未找到,则会在变量sys.path给出的目录列表中搜索名为 spam.py 的文件。 sys.path从这些位置初始化:
- 包含输入脚本(或当前目录)的目录。
- PYTHONPATH(目录名列表,语法与shell变量PATH相同)。
- 依赖于安装的默认值。
初始化后,Python程序可以修改 sys.path 。包含正在运行的脚本的目录位于搜索路径的开头,位于标准库路径之前。这意味着将加载该目录中的脚本,而不是库目录中的同名模块。除非有意更换,否则这是一个错误。
了解这一点,您可以在程序中执行以下操作:
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
答案 5 :(得分:39)
您可以在 sys.path 中列出的“模块搜索路径”中使用操作系统依赖路径。 因此,您可以轻松添加父目录,如下所示
import sys
sys.path.insert(0,'..')
如果要添加父父目录,
sys.path.insert(0,'../..')
答案 6 :(得分:34)
对python 2不太了解。
在python 3中,可以按如下方式添加父文件夹:
import sys
sys.path.append('..')
...然后一个人可以从中导入模块
答案 7 :(得分:29)
这是一个简单的答案,因此您可以看到它的工作原理,小型和跨平台
它只使用内置模块(os
,sys
和inspect
)因此应该工作
在任何操作系统(OS)上,因为Python就是为此而设计的。
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
,
在inspect.
(第3行)的开头添加getsourcefile
并删除第一行
- 但是这会导入所有模块,因此可能需要更多时间,内存和资源。
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.
它使用Stack Overflow回答 How do I get the path of the current
executed file in Python? 中的示例来查找使用内置工具运行代码的源(文件名)。
from inspect import getsourcefile from os.path import abspath
接下来,无论您想从哪里找到源文件,只需使用:
abspath(getsourcefile(lambda:0))
我的代码添加了sys.path
的文件路径, python路径列表
因为这允许Python从该文件夹导入模块。
在代码中导入模块后,最好在新行上运行sys.path.pop(0)
当添加的文件夹具有与导入的另一个模块同名的模块时
后来在该计划中。您需要删除导入前添加的列表项,而不是其他路径
如果您的程序没有导入其他模块,则不安全删除文件路径,因为
程序结束(或重新启动Python shell)后,对sys.path
所做的任何编辑都会消失。
我的回答并没有使用__file__
变量来获取正在运行的文件路径/文件名
代码,因为此处的用户经常将其描述为不可靠。你不应该使用它
用于从其他人使用的程序中导出父文件夹中的模块。
一些不起作用的示例(引自this Stack Overflow问题):
•在某些平台上找到can't be•有时isn't the full file path
py2exe
没有__file__
属性,但有一种解决方法- 当您使用
execute()
从IDLE运行时,没有__file__
属性- OS X 10.6,我得到
NameError: global name '__file__' is not defined
答案 8 :(得分:27)
这是更通用的解决方案,包括sys.path中的父目录(适用于我):
import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
答案 9 :(得分:11)
对我来说,访问父目录的最短和最喜欢的oneliner是:
sys.path.append(os.path.dirname(os.getcwd()))
或:
sys.path.insert(1, os.path.dirname(os.getcwd()))
os.getcwd()返回当前工作目录的名称,os.path.dirname(directory_name)返回传递的目录名。
实际上,在我看来,Python项目架构应该以子目录中没有一个模块将使用父目录中的任何模块的方式完成。如果发生类似这样的事情,重新考虑项目树是值得的。
另一种方法是将父目录添加到PYTHONPATH系统环境变量。
答案 10 :(得分:7)
import sys
sys.path.append('../')
答案 11 :(得分:6)
当不在包含__init__.py
文件的包环境中时,pathlib库(包含在> = Python 3.4中)使得将父目录的路径追加到PYTHONPATH非常简洁直观:
import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))
答案 12 :(得分:6)
上面提到的解决方案也很好。解决此问题的另一种方法是
如果要从顶层目录导入任何内容。然后,
from ...module_name import *
此外,如果要从父目录导入任何模块。然后,
from ..module_name import *
此外,如果要从父目录导入任何模块。然后,
from ...module_name.another_module import *
通过这种方式,您可以导入任何特定的方法。
答案 13 :(得分:4)
与过去的答案相同的风格 - 但在更少的行中:P
import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)
文件返回您正在使用的位置
答案 14 :(得分:3)
在Jupyter笔记本中
只要您在Jupyter Notebook中工作,此简短的解决方案就可能有用:
%cd ..
import nib
即使没有__init__.py
文件也可以使用。
我在Linux和Windows 7上使用Anaconda3对其进行了测试。
答案 15 :(得分:1)
使用图书馆。 创建一个名为nib的库,使用setup.py安装它,让它驻留在site-packages中,你的问题就解决了。 您不必将所有内容都包含在一个包中。把它分解成碎片。
答案 16 :(得分:1)
我遇到了必须导入Flask应用程序的问题,该应用程序也需要导入单独文件夹中的文件。这部分地使用了Remi's answer,但是假设我们有一个看起来像这样的存储库:
.
└── service
└── misc
└── categories.csv
└── test
└── app_test.py
app.py
pipeline.py
然后,在从app.py
文件导入应用程序对象之前,我们将目录上移一个级别,因此,在导入应用程序(导入pipeline.py
)时,我们还可以读取其他文件就像一个csv文件。
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)
os.chdir('../')
from app import app
导入Flask应用后,您可以使用os.chdir('./test')
,以便不更改工作目录。
答案 17 :(得分:1)
尽管原始作者可能不再在寻找解决方案,但是为了完整性,这里有一个简单的解决方案。将 life.py 作为这样的模块运行:
cd ptdraft
python -m simulations.life.life
这样,您可以从 nib.py 中导入任何内容,因为 ptdraft 目录位于路径中。
答案 18 :(得分:1)
我们的文件夹结构:
/myproject
project_using_ptdraft/
main.py
ptdraft/
__init__.py
nib.py
simulations/
__init__.py
life/
__init__.py
life.py
我理解的方式是以包为中心的视图。
包根是 ptdraft
,因为它是包含 __init__.py
包内的所有文件都可以使用绝对路径(相对于包根目录)进行导入,例如
在 life.py
中,我们只需:
import ptdraft.nib
但是,为了包开发/测试目的而运行 life.py
,而不是 python life.py
,我们需要使用:
cd /myproject
python -m ptdraft.simulations.life.life
请注意,此时我们根本不需要摆弄任何路径。
更令人困惑的是,当我们完成 ptdraft
包时,我们想在驱动程序脚本中使用它,该脚本必须位于 ptdraft
包文件夹之外,也就是 project_using_ptdraft/main.py
,我们需要摆弄路径:
import sys
sys.path.append("/myproject") # folder that contains ptdraft
import ptdraft
import ptdraft.simulations
并使用 python main.py
运行脚本没有问题。
有用的链接:
答案 19 :(得分:1)
答案 20 :(得分:0)
在Linux系统中,您可以创建从“life”文件夹到nib.py文件的软链接。然后,您可以简单地导入它:
import nib
答案 21 :(得分:0)
我发现以下方法可用于从脚本的父目录导入包。在示例中,我想从env.py
包中导入app.db
中的函数。
.
└── my_application
└── alembic
└── env.py
└── app
├── __init__.py
└── db
import os
import sys
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)
答案 22 :(得分:0)
我做了这个库来做这个。
https://github.com/fx-kirin/add_parent_path
# Just add parent path
add_parent_path(1)
# Append to syspath and delete when the exist of with statement.
with add_parent_path(1):
# Import modules in the parent path
pass
答案 23 :(得分:0)
这对我来说可以从更高的文件夹中导入内容。
import os
os.chdir('..')
答案 24 :(得分:-1)
Windows 10中绝对路径的简单解决方案:
import sys
sys.path.insert(0,'C:\\Users\\user01\\Desktop\\pipeline')
from folder1.folder2.filename import function_name
这将导入函数“ function_name” 来自:C:\ Users \ user01 \ Desktop \ pipeline \ folder1 \ folder2 \ filename
答案 25 :(得分:-2)
尽管这违反了所有规则,但我仍然要提及这种可能性:
您可以先将文件从父目录复制到子目录。接下来导入它,然后删除复制的文件:
例如life.py
中的
import os
import shutil
shutil.copy('../nib.py', '.')
import nib
os.remove('nib.py')
# now you can use it just fine:
nib.foo()
当然,当笔尖尝试导入/读取具有相对导入/路径的其他文件时,可能会出现一些问题。