我正在运行Python 2.5.
这是我的文件夹树:
ptdraft/ nib.py simulations/ life/ life.py
(我也在__init__.py
每个文件夹中,为了便于阅读,这里省略了)
如何nib
从模块内导入life
模块?我希望有可能不用修补sys.path.
注意:正在运行的主模块位于该ptdraft
文件夹中.
您可以使用相对导入(python> = 2.5):
from ... import nib
(Python 2.5中的新功能)PEP 328:绝对和相对导入
编辑:添加了另一个点'.' 上两个包
相对导入(如在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模块来检索当前文件的文件名(和路径)
关于从兄弟套餐进口的问题,我也发了类似的答案.你可以在这里看到它.以下是使用Python 3.6.5(Anaconda,conda 4.5.1),Windows 10计算机进行测试的.
没有sys.path -hacks或相对导入的解决方案我假设与问题中的文件夹结构相同
. ??? 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)
要了解更多相关信息,只需谷歌"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!
似乎问题与父目录中的模块或类似的东西无关.
您需要将包含的目录添加ptdraft
到PYTHONPATH
你说这import nib
与你合作,这可能意味着你把ptdraft
自己(不是它的父母)添加到了PYTHONPATH.
如果将模块文件夹添加到PYTHONPATH不起作用,您可以在程序中修改Python解释器搜索要导入的模块的sys.path列表,python文档说:
导入名为spam的模块时,解释器首先搜索具有该名称的内置模块.如果未找到,则会在变量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
您可以在sys.path中列出的"模块搜索路径"中使用OS依赖路径.因此,您可以轻松添加如下所示的父目录
import sys sys.path.insert(0,'..')
如果要添加父父目录,
sys.path.insert(0,'../..')
不太了解python 2.
在python 3中,父文件夹可以添加如下:
import sys sys.path.append('..')
...然后一个人可以从中导入模块
这是一个简单的答案,因此您可以看到它的工作原理,小型和跨平台.
它仅使用内置模块(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
,在(第3行)的开头
添加并删除第一行.
- 但是这会导入所有模块,因此可能需要更多时间,内存和资源.inspect.
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中的示例答案如何
在Python中获取当前执行文件的路径?使用内置工具查找正在运行的代码的源(filename).
from inspect import getsourcefile from os.path import abspath接下来,无论您想从哪里找到源文件,只需使用:
abspath(getsourcefile(lambda:0))
我的代码添加了python路径列表的文件路径sys.path
,
因为这允许Python从该文件夹导入模块.
在代码中导入模块后,
当添加的文件夹具有与
稍后在程序中导入的另一个模块同名的模块时,最好sys.path.pop(0)
在新行上运行.您需要删除导入前添加的列表项,而不是其他路径.
如果您的程序没有导入其他模块,那么不删除文件路径是安全的,因为
在程序结束(或重新启动Python shell)之后,任何编辑都会消失.sys.path
我的答案不使用__file__
变量来获取正在运行的
代码的文件路径/文件名,因为这里的用户经常将其描述为不可靠.你不应该使用它
为从父文件夹导入模块中的其他人使用的程序.
一些例子在那里不起作用(从报价这个堆栈溢出的问题):
• 在某些平台上找不到它•它有时不是完整的文件路径
py2exe
没有__file__
属性,但有一个解决方法从IDLE运行时
execute()
没有__file__
属性OS X 10.6我得到的地方
NameError: global name '__file__' is not defined
这是更通用的解决方案,包括sys.path中的父目录(适用于我):
import os.path, sys sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
我发现以下方法可用于从脚本的父目录导入包。在示例中,我想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)
对我来说,访问父目录的最短和最喜欢的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系统环境变量中.
import sys
sys.path.append('../')
上述解决方案也很好。解决此问题的另一种方法是
如果要从顶层目录导入任何内容。然后,
from ...module_name import *
另外,如果要从父目录导入任何模块。然后,
from ..module_name import *
另外,如果要从父目录导入任何模块。然后,
from ...module_name.another_module import *
这样,您可以根据需要导入任何特定方法。
当不在包含__init__.py
文件的包环境中时,pathlib库(包含在> = Python 3.4中)使得将父目录的路径附加到PYTHONPATH非常简洁直观:
import sys from pathlib import Path sys.path.append(str(Path('.').absolute().parent))