当前位置:  开发笔记 > 编程语言 > 正文

从父文件夹导入模块

如何解决《从父文件夹导入模块》经验,为你挑选了14个好方法。

我正在运行Python 2.5.

这是我的文件夹树:

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

(我也在__init__.py每个文件夹中,为了便于阅读,这里省略了)

如何nib从模块内导入life模块?我希望有可能不用修补sys.path.

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



1> f3lix..:

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

from ... import nib

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

编辑:添加了另一个点'.' 上两个包


更准确地说,你需要一个`__init __.py`文件.
`ValueError:在非包中尝试相对导入
尝试相对导入超出顶级包
@endolith:你必须在一个包中,即你必须有一个__init__.py文件.
另请参阅以下答案,因为添加`__init __.py`不是您唯一需要做的事情:http://stackoverflow.com/questions/11536764/attempted-relative-import-in-non-package-even-with -init-PY/27876800#27876800
为了*甚至*更精确,你需要一个`__init __.py`文件.
@karadeniz好吧,这并不更精确。实际上,您省略了在父目录中需要`__init __。py`的事实。

2> Remi..:

相对导入(如在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模块来检索当前文件的文件名(和路径)


更短的东西:`sys.path.insert(1,os.path.join(sys.path [0],'..'))`
有什么理由避免使用sys.path.append()而不是插入?
@JHolta如果您没有处理包裹,那么您的包装是最好的解决方案.
@JHolta好主意。sys.path.insert(1,os.path.realpath(os.path.pardir))也可以工作。
@Tyler - 在其他地方然后是`parentdir`可能很重要,但是在`sys.path`中已经指定的其中一个路径中,还有另一个名为'mymodule'的模块.插入`parentdir`作为`sys.path`列表的第一个元素确保将导入来自`parentdir`的模块.

3> np8..:

关于从兄弟套餐进口的问题,我也发了类似的答案.你可以在这里看到它.以下是使用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.

脚步

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

内容setup.py可以简单

from setuptools import setup, find_packages

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

基本上"任何"setup.py都可以.这只是一个极小的工作示例.

2)使用虚拟环境

如果您熟悉虚拟环境,请激活一个,然后跳到下一步.虚拟环境的使用并非绝对必要,但从长远来看,它们将真正帮助您(当您有超过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>

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

安装您的顶级包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

4)通过附加mainfolder到每个进口进口

在这个例子中,mainfolder将是ptdraft.这样做的好处是,您不会遇到与其他模块名称(来自python标准库或第三方模块)的名称冲突.


示例用法

nib.py

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!


@HomeroBarrocasSEsmeraldo好的问题。PYTHONPATH env var保持不变。它安装在[site-packages](/sf/ask/17360801/)中,该文件已经在sys.path中,并且最终用户通常将代码安装在该位置。这比sys.path骇客要好(并且您可以在该类路径骇客中包括使用PYTHONPATH),因为这意味着开发中的代码对您的行为应与对其他用户的行为相同。相反,在使用路径修改时,将以不同的方式解析import语句。
另外,为什么这比使用sys.path方法更好或更优雅?
到目前为止,这是我读过的最好的解决方案。这将创建一个到当前目录的链接,因此对代码的所有更新都将直接反映到您的工作目录中。如果需要删除该条目,请手动删除egg文件,并从dist-packages(如果使用pip,则为site-packages)中的easy-install中删除该条目。

4> hasen..:

似乎问题与父目录中的模块或类似的东西无关.

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

你说这import nib与你合作,这可能意味着你把ptdraft自己(不是它的父母)添加到了PYTHONPATH.



5> Ricardo Muri..:

如果将模块文件夹添加到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


你的答案很好,但可能并不总是有效,也不是很便携.如果程序被移动到新位置,则必须编辑`/ path/to/ptdraft`.有一些解决方案可以解决文件的当前目录,并从父文件夹中导入它.

6> Shinbero..:

您可以在sys.path中列出的"模块搜索路径"中使用OS依赖路径.因此,您可以轻松添加如下所示的父目录

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

如果要添加父父目录,

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



7> 小智..:

不太了解python 2.
在python 3中,父文件夹可以添加如下:

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

...然后一个人可以从中导入模块


这只适用于当前工作目录是"'.."导致带有相关模块的目录.

8> Edward..:

这是一个简单的答案,因此您可以看到它的工作原理,小型和跨平台.
它仅使用内置模块(os,sysinspect),所以应该工作
在任何操作系统(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



9> Mike..:

这是更通用的解决方案,包括sys.path中的父目录(适用于我):

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



10> 小智..:

我发现以下方法可用于从脚本的父目录导入包。在示例中,我想env.pyapp.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)



11> zviad..:

对我来说,访问父目录的最短和最喜欢的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系统环境变量中.


+1代表必须重组项目的可能性(而不是对问题进行整顿)

12> Andong Zhan..:

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


从其他目录执行时,这将不起作用.

13> 小智..:

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

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

from ...module_name import *

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

from ..module_name import *

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

from ...module_name.another_module import *

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



14> 小智..:

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

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

推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有