从父文件夹导入模块

我正在运行Python 2.5。

这是我的文件夹树:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(我在每个文件夹中都有__init__.py ,为便于阅读,在此省略)

如何从life模块内部导入nib模块? 我希望无需修补sys.path就可以做到。

注意:正在运行的主模块位于ptdraft文件夹中。


#1楼

相对导入(例如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楼

与过去的答案相同的风格-但行数较少:P

import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)

文件返回您正在工作的位置


#3楼

这是更通用的解决方案,其中将父目录包含在sys.path中(对我有用):

import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))

#4楼

您可以在sys.path中列出的“模块搜索路径”中使用取决于OS的路径。 这样您就可以轻松添加父目录,如下所示

import sys
sys.path.insert(0,'..')

如果您要添加父/母目录,

sys.path.insert(0,'../..')

#5楼

使用库。 创建一个名为nib的库,使用setup.py安装它,使其驻留在站点程序包中,您的问题将得到解决。 您不必将自己制作的所有东西都塞进一个包装中。 分解成碎片。


#6楼

这是一个简单的答案,因此您可以了解它的工作原理(小型和跨平台)。
它仅使用内置模块( ossysinspect ),因此应该可以使用
在任何操作系统(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.getsourcefile (第3行),然后删除第一行。
-但是,这会导入所有模块,因此可能需要更多的时间,内存和资源。

我的答案的代码( 较长版本

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执行文件? 使用内置工具查找正在运行的代码的源(文件名)。

 from inspect import getsourcefile from os.path import abspath 

接下来,无论您想在哪里找到源文件,都只需使用:

 abspath(getsourcefile(lambda:0)) 

我的代码向sys.pathPython路径列表)添加了文件路径
因为这允许Python从该文件夹导入模块。

在代码中导入模块后,最好在新行上运行sys.path.pop(0)
当添加的文件夹具有与导入的另一个模块同名的模块时
在程序的后面。 您需要删除导入之前添加的列表项,而不是其他路径。
如果您的程序未导入其他模块,则不删除文件路径是安全的,因为
程序结束(或重新启动Python Shell)后,对sys.path所做的任何编辑都会消失。

有关文件名变量的注释

我的答案没有使用__file__变量来获取正在运行的文件路径/文件名
代码,因为这里的用户经常将其描述为不可靠 。 你不应该用它
用于其他人使用的程序中的父文件夹导入模块

一些不起作用的示例(引用 Stack Overflow问题):

•在某些平台找不到•有时不是完整的文件路径

  • py2exe没有__file__属性,但是有一种解决方法
  • 当您使用execute()从IDLE运行时,没有__file__属性
  • 我得到NameError: global name '__file__' is not defined OS X 10.6 NameError: global name '__file__' is not defined

#7楼

当不在带有__init__.py文件的包环境中时,pathlib库(包含在> = Python 3.4中)使将父目录的路径附加到PYTHONPATH变得非常简洁直观:

import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))

#8楼

import sys sys.path.append('../')


#9楼

对python 2不太了解。
在python 3中,可以按以下方式添加父文件夹:

import sys 
sys.path.append('..')

...然后可以从中导入模块


#10楼

在Linux系统中,可以创建从“ life”文件夹到nib.py文件的软链接。 然后,您可以像这样简单地导入它:

import nib

#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系统环境变量。


#12楼

对于同级软件包的导入问题,我也发表了类似的答案。 你可以在这里看到它。 以下内容已在Windows 10机器的Python 3.6.5(Anaconda,conda 4.5.1)中进行了测试。

没有sys.path hack的解决方案

设定

我假设与问题中的文件夹结构相同

.
└── ptdraft
    ├── __init__.py
    ├── nib.py
    └── simulations
        ├── __init__.py
        └── life
            ├── __init__.py
            └── life.py

我打电话给. 根文件夹,在我的情况下,它位于C:\\tmp\\test_imports

脚步

1)将setup.py添加到根文件夹

setup.py的内容可以很简单

from setuptools import setup, find_packages

setup(name='myproject', version='1.0', packages=find_packages())

基本上,“任何” setup.py都可以。 这只是一个最小的工作示例。

2)使用虚拟环境

如果您熟悉虚拟环境,请激活一个,然后跳到下一步。 使用虚拟环境不是绝对必需的,但是从长远来看(当您正在进行多个项目时),它们确实可以帮助您。 最基本的步骤是(在根文件夹中运行)

  • 创建虚拟环境
    • python -m venv venv
  • 激活虚拟环境
    • . /venv/bin/activate . /venv/bin/activate (Linux)或./venv/Scripts/activate

要了解更多信息,只需在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>

3)pip以可编辑状态安装项目

使用pip安装顶级软件包myproject 。 诀窍是在执行安装时使用-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

4)通过将mainfolder附加到每个导入来进行导入

在这个例子中, mainfolderptdraft 。 这样的好处是您不会与其他模块名称(来自python标准库或3rd party模块)发生名称冲突。


用法示例

笔尖

def function_from_nib():
    print('I am the return value from function_from_nib!')

life.py

from ptdraft.nib import function_from_nib

if __name__ == '__main__':
    function_from_nib()

运行life.py

(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!

#13楼

上述解决方案也很好。 解决此问题的另一种方法是

如果要从顶层目录导入任何内容。 然后,

from ...module_name import *

另外,如果要从父目录导入任何模块。 然后,

from ..module_name import *

另外,如果要从父目录导入任何模块。 然后,

from ...module_name.another_module import *

这样,您可以根据需要导入任何特定方法。


#14楼

我发现以下方法可用于从脚本的父目录导入包。 在示例中,我想从app.db包中导入env.py函数。

.
└── 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)

#15楼

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


#16楼

在装有Linux的Jupyter Notebook中

只要您在Jupyter Notebook中工作,这个简短的解决方案就可能有用:

%cd ..
import nib

即使没有__init__.py文件,它也可以工作。


#17楼

看来问题与该模块位于父目录或类似目录中无关。

您需要将包含ptdraft的目录添加到PYTHONPATH

您说import nib与您一起工作,这可能意味着您已将ptdraft本身(而不是其父项)添加到PYTHONPATH中。


#18楼

您可以使用相对导入(python> = 2.5):

from ... import nib

(Python 2.5的新增功能)PEP 328:绝对导入和相对导入

编辑 :添加了另一个点“。” 上两个包


#19楼

如果将模块文件夹添加到PYTHONPATH不起作用,则可以在程序中修改sys.path列表,Python解释程序会在其中搜索要导入的模块, 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
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值