从父文件夹导入模块

问题描述 投票:477回答:17

我正在运行Python 2.5。

这是我的文件夹树:

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

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

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

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

python module path directory python-import
17个回答
101
投票

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

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

你说import nib和你一起工作,这可能意味着你把ptdraft本身(不是它的父母)添加到了PYTHONPATH。


10
投票

对我来说,访问父目录的最短和最喜欢的一个班轮是:

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


8
投票

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


6
投票

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

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

6
投票

上面提到的解决方案也很好。这个问题的另一个解决方案是

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

from ...module_name import *

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

from ..module_name import *

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

from ...module_name.another_module import *

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


4
投票

与过去的答案相同的风格 - 但在更少的行中:P

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

file返回您正在使用的位置


3
投票

我发现以下方法适用于从脚本的父目录导入包。在这个例子中,我想从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)

1
投票

与图书馆合作。创建一个名为nib的库,使用setup.py安装它,让它驻留在site-packages中,你的问题就解决了。您不必将所有内容都包含在一个包中。把它分解成碎片。


0
投票

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

import nib

540
投票

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

from ... import nib

(What’s New in Python 2.5) PEP 328: Absolute and Relative Imports

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


231
投票

相对导入(如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__属性。我现在建议使用inspect模块来检索当前文件的文件名(和路径),而不是使用os.path.abspath(__file__)


67
投票

关于从兄弟套餐进口的问题,我也发了类似的答案。你可以看到它here。以下是使用Python 3.6.5(Anaconda,conda 4.5.1),Windows 10计算机进行测试的。

Solution without 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标准库或第三方模块)的名称冲突。


Example Usage

你不.朋友

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

life.朋友

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!

50
投票

如果将模块文件夹添加到PYTHONPATH不起作用,您可以在程序中修改Python解释器搜索要导入的模块的sys.path列表,python documentation说:

导入名为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

40
投票

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

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

如果要添加父父目录,

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

34
投票

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

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

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


29
投票

这是一个简单的答案,因此您可以看到它的工作原理,小型和跨平台。 它只使用内置模块(ossysinspect)所以应该工作 在任何操作系统(OS)上,因为Python就是为此而设计的。

Shorter code for answer - fewer lines and variables

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并删除第一行。 - 但是这会导入所有模块,因此可能需要更多时间,内存和资源。

The code for my answer (longer version)

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所做的任何编辑都会消失。

Notes about a filename variable

我的回答是不使用__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

27
投票

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

import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
© www.soinside.com 2019 - 2024. All rights reserved.