从父文件夹导入模块

发布于 2024-07-16 06:46:50 字数 303 浏览 5 评论 0 原文

我正在运行Python 2.5。

这是我的文件夹树:(

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

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

如何从 life 内部导入 nib 模块模块? 我希望无需修改 sys.path 即可完成。

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

I am running Python 2.5.

This is my folder tree:

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

(I also have __init__.py in each folder, omitted here for readability)

How do I import the nib module from inside the life module? I am hoping it is possible to do without tinkering with sys.path.

Note: The main module being run is in the ptdraft folder.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

霊感 2024-07-23 06:46:50

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

from ... import nib

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

You could use relative imports (Python >= 2.5):

from ... import nib

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

梦言归人 2024-07-23 06:46:50

我也针对有关从兄弟包导入的问题发布了类似的答案。 您可以在此处查看它。

没有 sys.path hacks 的解决

摘要

  • 方案 将代码放入一个文件夹(例如 packaged_stuff
  • 创建一个 pyproject.toml (较旧的替代方案:setup.py
  • Pip 以可编辑状态安装包pip install -e
  • 使用from packaged_stuff.modulename import function_name

导入设置

问题中的文件夹结构相同

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

我假设与我称为的 。 根文件夹,在我的例子中,它位于 C:\tmp\test_imports 中。

步骤


1) 将 pyproject.toml 添加到根文件夹

pyproject.toml 的内容可以是简单的

[project]
name = "ptdraft"
version = "0.1.0"
description = "My small project"

[build-system]
build-backend = "flit_core.buildapi"
requires = ["flit_core >=3.2,<4"]

基本上“任何”有效的 pyproject.toml > 会起作用的。 这只是一个最小的工作示例,它使用 flit 作为构建后端。


2) 使用虚拟环境

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

  • 创建虚拟环境
    • python -m venv venv
  • 激活虚拟环境
    • <代码>。 venv/bin/activate (Linux) 或 ./venv/Scripts/activate (Win)
  • 停用虚拟环境
    • 停用 (Linux)

要了解更多信息,只需 Google 出“python virtualenv 教程”或类似内容即可。 除了创建、激活和停用之外,您可能不需要任何其他命令。

创建并激活虚拟环境后,您的控制台应在括号中给出虚拟环境的名称

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 install 您的项目处于可编辑状态

使用 ptdraft) >点。 诀窍是在安装时使用 -e 标志。 这样它就会以可编辑状态安装,并且对 .py 文件所做的所有编辑都将自动包含在已安装的包中。 请注意,pyproject.toml 的 -e 标志需要 pip 21.3 或更高版本

在根目录下,运行

pip install -e .(注意点,它代表“当前目录”)

您还可以看到它是使用pip freeze安装的

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///home/user/projects/ptdraft
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Preparing editable metadata (pyproject.toml) ... done
....
Successfully built ptdraft
Installing collected packages: ptdraft
Successfully installed ptdraft-0.1.0
(venv) PS C:\tmp\test_imports> pip freeze
ptdraft==0.1.0

4) 通过在每次导入前添加 mainfolder 进行导入

在此示例中,mainfolder 将为 ptdraft。 这样做的优点是您不会遇到与其他模块名称(来自 python 标准库或第 3 方模块)的名称冲突。


用法示例

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!

I posted a similar answer also to the question regarding imports from sibling packages. You can see it here.

Solution without sys.path hacks

Summary

  • Wrap the code into one folder (e.g. packaged_stuff)
  • Create a pyproject.toml (older alternative: setup.py)
  • Pip install the package in editable state with pip install -e <myproject_folder>
  • Import using from packaged_stuff.modulename import function_name

Setup

I assume the same folder structure as in the question

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

I call the . the root folder, and in my case it is located in C:\tmp\test_imports.

Steps


1) Add a pyproject.toml to the root folder

The contents of the pyproject.toml can be simply

[project]
name = "ptdraft"
version = "0.1.0"
description = "My small project"

[build-system]
build-backend = "flit_core.buildapi"
requires = ["flit_core >=3.2,<4"]

Basically "any" valid pyproject.toml would work. This is just a minimal working example, which uses flit as build backend.


2) Use a virtual environment

If you are familiar with virtual environments, activate one, and skip to the next step. Usage of virtual environments are not absolutely required, but they will really help you out in the long run (when you have more than 1 project ongoing..). The most basic steps are (run in the root folder)

  • Create virtual env
    • python -m venv venv
  • Activate virtual env
    • . venv/bin/activate (Linux) or ./venv/Scripts/activate (Win)
  • Deactivate virtual env
    • deactivate (Linux)

To learn more about this, just Google out "python virtualenv tutorial" or similar. You probably never need any other commands than creating, activating and deactivating.

Once you have made and activated a virtual environment, your console should give the name of the virtual environment in parenthesis

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 install your project in editable state

Install your top level package (here ptdraft) using pip. The trick is to use the -e flag when doing the install. This way it is installed in an editable state, and all the edits made to the .py files will be automatically included in the installed package. Note that the -e flag with pyproject.toml requires pip 21.3 or newer.

In the root directory, run

pip install -e . (note the dot, it stands for "current directory")

You can also see that it is installed by using pip freeze

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///home/user/projects/ptdraft
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Preparing editable metadata (pyproject.toml) ... done
....
Successfully built ptdraft
Installing collected packages: ptdraft
Successfully installed ptdraft-0.1.0
(venv) PS C:\tmp\test_imports> pip freeze
ptdraft==0.1.0

4) Import by prepending mainfolder to every import

In this example, the mainfolder would be ptdraft. This has the advantage that you will not run into name collisions with other module names (from python standard library or 3rd party modules).


Example Usage

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()

Running life.py

(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!
小清晰的声音 2024-07-23 06:46:50

相对导入(如 from .. import mymodule)仅在包中有效。
要导入当前模块的父目录中的“mymodule”:

import os
import sys
import 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__) 。

Relative imports (as in from .. import mymodule) only work in a package.
To import 'mymodule' that is in the parent directory of your current module:

import os
import sys
import inspect

currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir) 

import mymodule

Note: The __file__ attribute is not always given. Instead of using os.path.abspath(__file__) I suggest using the inspect module to retrieve the filename (and path) of the current file.

野生奥特曼 2024-07-23 06:46:50

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

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

您说 import nib 可以与您一起使用,这可能意味着您添加了 ptdraft 本身(不是它的父级)到 PYTHONPATH。

It seems that the problem is not related to the module being in a parent directory or anything like that.

You need to add the directory that contains ptdraft to PYTHONPATH

You said that import nib worked with you, that probably means that you added ptdraft itself (not its parent) to PYTHONPATH.

染年凉城似染瑾 2024-07-23 06:46:50

您可以在“模块搜索路径”中使用sys.path中列出的与操作系统相关的路径。

因此,您可以轻松添加父目录,如下所示:

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

如果您想添加父目录,

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

这在 Python 2Python 3

You can use an OS-dependent path in "module search path" which is listed in sys.path.

So you can easily add the parent directory like the following:

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

If you want to add the parent-parent directory,

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

This works both in Python 2 and Python 3.

情绪少女 2024-07-23 06:46:50

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

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

...然后人们可以从中导入模块。

I don't know much about Python 2.
In Python 3, the parent folder can be added as follows:

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

...and then one is able to import modules from it.

对岸观火 2024-07-23 06:46:50

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

If adding your module folder to the PYTHONPATH didn't work, You can modify the sys.path list in your program where the Python interpreter searches for the modules to import, the Python documentation says:

When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:

  • the directory containing the input script (or the current directory).
  • PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
  • the installation-dependent default.

After initialization, Python programs can modify sys.path. The directory containing the script being run is placed at the beginning of the search path, ahead of the standard library path. This means that scripts in that directory will be loaded instead of modules of the same name in the library directory. This is an error unless the replacement is intended.

Knowing this, you can do the following in your program:

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
拿命拼未来 2024-07-23 06:46:50

这是一个简单的答案,因此您可以了解它是如何工作的,小型且跨平台的。 它仅使用内置模块(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, inform。 在 getsourcefile 开头添加 inspect.(第 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检查导入getsourcefile 
  从 os.path 导入绝对路径 
  

接下来,无论您想在何处查找源文件,只需使用:

abspath(getsourcefile(lambda:0)) 
  

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

在代码中导入模块后,如果添加的文件夹具有与导入的另一个模块同名的模块,最好在新行上运行 sys.path.pop(0)稍后在节目中。 您需要删除导入之前添加的列表项,而不是其他路径。

如果您的程序不导入其他模块,则不要删除文件路径是安全的,因为在程序结束(或重新启动 Python shell)后,对 sys.path 所做的任何编辑都会消失。

关于文件名变量的注释

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

一些它不起作用的示例(引用自这个堆栈溢出问题):

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

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

Here is an answer that's simple so you can see how it works, small and cross-platform. It only uses built-in modules (os, sys and inspect), so it should work on any operating system (OS) because Python is designed for that.

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)

For fewer lines than this, replace the second line with import os.path as path, sys, inspect. Add inspect. at the start of getsourcefile (line 3) and remove the first line.

  • however this imports all of the module so it could need more time, memory and resources.

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.

It uses an example from a Stack Overflow answer How do I get the path of the current executed file in Python? to find the source (filename) of running code with a built-in tool.

from inspect import getsourcefile
from os.path import abspath

Next, wherever you want to find the source file from you just use:

abspath(getsourcefile(lambda:0))

My code adds a file path to sys.path, the Python path list
because this allows Python to import modules from that folder.

After importing a module in the code, it's a good idea to run sys.path.pop(0) on a new line when that added folder has a module with the same name as another module that is imported later in the program. You need to remove the list item added before the import, not other paths.

If your program doesn't import other modules, it's safe to not delete the file path because after a program ends (or restarting the Python shell), any edits made to sys.path disappear.

Notes about a filename variable

My answer doesn't use the __file__ variable to get the file path/filename of running code because users here have often described it as unreliable. You shouldn't use it for importing modules from parent folder in programs used by other people.

Some examples where it doesn't work (quote from this Stack Overflow question):

• it can't be found on some platforms. It sometimes isn't the full file path

  • py2exe doesn't have a __file__ attribute, but there is a workaround
  • When you run from IDLE with execute() there is no __file__ attribute
  • OS X 10.6 where I get NameError: global name '__file__' is not defined
飘逸的'云 2024-07-23 06:46:50

pathlib 库(包含在 >= Python 3.4 中)使得将父目录的路径附加到 PYTHONPATH 变得非常简洁和直观:

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

The pathlib library (included with >= Python 3.4) makes it very concise and intuitive to append the path of the parent directory to the PYTHONPATH:

import sys
from pathlib import Path
sys.path.append(str(Path(__file__).absolute().parent))
你不是我要的菜∠ 2024-07-23 06:46:50

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

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

Here is a more generic solution that includes the parent directory into sys.path (it works for me):

import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
深海蓝天 2024-07-23 06:46:50

Jupyter Notebook 中(使用 JupyterLab 或 Jupyter Notebook)

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

%cd ..
import nib

即使没有__init__.py 文件。

我在 Linux 和 Windows 7 上使用 Anaconda 3 进行了测试。

In a Jupyter Notebook (opened with JupyterLab or Jupyter Notebook)

As long as you're working in a Jupyter Notebook, this short solution might be useful:

%cd ..
import nib

It works even without an __init__.py file.

I tested it with Anaconda 3 on Linux and Windows 7.

岁吢 2024-07-23 06:46:50

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

I found the following way works for importing a package from the script's parent directory. In the example, I would like to import functions in env.py from app.db package.

.
└── 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)
少钕鈤記 2024-07-23 06:46:50

前面提到的解决方案也很好。 此问题的另一个解决方案是:

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

from ...module_name import *

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

from ..module_name import *

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

from ...module_name.another_module import *

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

The previous mentioned solutions are also fine. Another solution to this problem is:

If you want to import anything from top level directory. Then,

from ...module_name import *

Also, if you want to import any module from the parent directory. Then,

from ..module_name import *

Also, if you want to import any module from the parent directory. Then,

from ...module_name.another_module import *

This way you can import any particular method if you want to.

悲念泪 2024-07-23 06:46:50

两行最简单的解决方案

import os, sys
sys.path.insert(0, os.getcwd()) 

如果父级是您的工作目录并且您想从子脚本调用另一个子模块。

您可以在任何脚本中从父目录导入所有子模块并将其执行为

python child_module1/child_script.py

Two line simplest solution

import os, sys
sys.path.insert(0, os.getcwd()) 

If parent is your working directory and you want to call another child modules from child scripts.

You can import all child modules from parent directory in any scripts and execute it as

python child_module1/child_script.py
牵你手 2024-07-23 06:46:50

为了完整起见,有一个简单的解决方案。 它将life.py作为模块运行,如下所示:

cd ptdraft
python -m simulations.life.life

这样您就可以从nib.py导入任何内容,因为ptdraft目录位于路径中。

For completeness, there one simple solution. It's to run life.py as a module like this:

cd ptdraft
python -m simulations.life.life

This way you can import anything from nib.py as ptdraft directory is in the path.

我的黑色迷你裙 2024-07-23 06:46:50

我认为您可以在该特定示例中尝试此操作,但在 Python 3.6.3 中:

在此处输入图像描述

I think you can try this in that specific example, but in Python 3.6.3:

Enter image description here

囚你心 2024-07-23 06:46:50

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

For me the shortest and my favorite oneliner for accessing to the parent directory is:

sys.path.append(os.path.dirname(os.getcwd()))

or:

sys.path.insert(1, os.path.dirname(os.getcwd()))

os.getcwd() returns the name of the current working directory, os.path.dirname(directory_name) returns the directory name for the passed one.

Actually, in my opinion Python project architecture should be done the way where no one module from child directory will use any module from the parent directory. If something like this happens it is worth to rethink about the project tree.

Another way is to add parent directory to PYTHONPATH system environment variable.

转角预定愛 2024-07-23 06:46:50
import sys
sys.path.append('../')
import sys
sys.path.append('../')
酷遇一生 2024-07-23 06:46:50

我有一个专门针对 Git 存储库的解决方案。

首先,我使用了 sys.path.append('..') 和类似的解决方案。 如果您导入的文件本身是使用 sys.path.append('..') 导入文件,这会导致特别的问题。

然后我决定始终附加 Git 存储库的根目录。 在一行中,它看起来像这样:

sys.path.append(git.Repo('.', search_parent_directories=True).working_tree_dir)

或者更详细地这样:

import os
import sys
import git
def get_main_git_root(path):
    main_repo_root_dir = git.Repo(path, search_parent_directories=True).working_tree_dir
    return main_repo_root_dir
main_repo_root_dir = get_main_git_root('.')
sys.path.append(main_repo_root_dir)

对于最初的问题:根据存储库的根目录是什么,导入将是

import ptdraft.nib

import nib

I have a solution specifically for Git repositories.

First I used sys.path.append('..') and similar solutions. This causes especially problems if you are importing files which are themselves importing files with sys.path.append('..').

I then decided to always append the root directory of the Git repository. In one line it would look like this:

sys.path.append(git.Repo('.', search_parent_directories=True).working_tree_dir)

Or in more details like this:

import os
import sys
import git
def get_main_git_root(path):
    main_repo_root_dir = git.Repo(path, search_parent_directories=True).working_tree_dir
    return main_repo_root_dir
main_repo_root_dir = get_main_git_root('.')
sys.path.append(main_repo_root_dir)

For the original question: Based on what the root directory of the repository is, the import would be

import ptdraft.nib

or

import nib
花开浅夏 2024-07-23 06:46:50

这与过去的答案具有相同的风格,但行数较少:P

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

file 返回您正在工作的位置。

This is the same sort of style as the past answers, but in fewer lines :P

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

file returns the location you are working in.

樱娆 2024-07-23 06:46:50

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

import nib

In a Linux system, you can create a soft link from the "life" folder to the nib.py file. Then, you can simply import it like:

import nib
小镇女孩 2024-07-23 06:46:50

我们的文件夹结构:

/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来毫无问题地运行脚本。

有用的链接:

Our folder structure:

/myproject
  project_using_ptdraft/
    main.py
  ptdraft/
    __init__.py
    nib.py
    simulations/
      __init__.py
      life/
        __init__.py
        life.py

The way I understand this is to have a package-centric view.
The package root is ptdraft, since it's the top most level that contains __init__.py

All the files within the package can use absolute paths (that are relative to package root) for imports, for example
in life.py, we have simply:

import ptdraft.nib

However, to run life.py for package dev/testing purposes, instead of python life.py, we need to use:

cd /myproject
python -m ptdraft.simulations.life.life

Note that we didn't need to fiddle with any path at all at this point.


Further confusion is when we complete the ptdraft package, and we want to use it in a driver script, which is necessarily outside of the ptdraft package folder, aka project_using_ptdraft/main.py, we would need to fiddle with paths:

import sys
sys.path.append("/myproject")  # folder that contains ptdraft
import ptdraft
import ptdraft.simulations

and use python main.py to run the script without problem.

Helpful links:

离线来电— 2024-07-23 06:46:50

与图书馆合作。
创建一个名为 nib 的库,使用 setup.py 安装它,让它驻留在站点包中,您的问题就解决了。
您不必将制作的所有东西都装在一个包装中。 把它打碎。

Work with libraries.
Make a library called nib, install it using setup.py, let it reside in site-packages and your problems are solved.
You don't have to stuff everything you make in a single package. Break it up to pieces.

独闯女儿国 2024-07-23 06:46:50

我遇到了一个问题,我必须导入 Flask 应用程序,该应用程序的导入还需要导入单独文件夹中的文件。 这部分使用了 Remi 的答案,但假设我们有一个如下所示的存储库:

.
└── 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') 这样您的工作目录就不会更改。

I had a problem where I had to import a Flask application, that had an import that also needed to import files in separate folders. This is partially using Remi's answer, but suppose we had a repository that looks like this:

.
└── service
    └── misc
        └── categories.csv
    └── test
        └── app_test.py
    app.py
    pipeline.py

Then before importing the app object from the app.py file, we change the directory one level up, so when we import the app (which imports the pipeline.py), we can also read in miscellaneous files like a csv file.

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

After having imported the Flask app, you can use os.chdir('./test') so that your working directory is not changed.

忆依然 2024-07-23 06:46:50

在我看来,您实际上并不需要导入父模块。 假设在 nib.py 中你有 func1() 和 data1,你需要在 life.py 中使用

nib.py

import simulations.life.life as life
def func1():
   pass
data1 = {}
life.share(func1, data1)

life.py

func1 = data1 = None

def share(*args):
   global func1, data1
   func1, data1 = args

现在你可以在 life.py 中访问 func1 和 data。 当然,在尝试使用它们之前,您必须小心地将它们填充到 life.py 中,

It's seems to me that you don't really need to import the parent module. Let's imagine that in nib.py you have func1() and data1, you need to use in life.py

nib.py

import simulations.life.life as life
def func1():
   pass
data1 = {}
life.share(func1, data1)

life.py

func1 = data1 = None

def share(*args):
   global func1, data1
   func1, data1 = args

And now you have the access to func1 and data in life.py. Of course you have to be careful to populate them in life.py before you try to use them,

南冥有猫 2024-07-23 06:46:50

删除一些系统路径黑客后,我认为添加

我的首选解决方案可能很有价值。

注意:这是一个框架挑战 - 没有必要在代码中进行。

假设一棵树,

project
└── pkg
    └── test.py

其中 test.py 包含

import sys, json; print(json.dumps(sys.path, indent=2)) 

使用路径执行仅包含包目录

python pkg/test.py
[
  "/project/pkg",
 ...
]

但使用模块参数包含项目目录

python -m pkg.test
[
  "/project",
  ...
]

现在,所有导入都可以是绝对的,从项目目录。 不需要进一步的诈骗。

After removing some sys path hacks, I thought it might be valuable to add

My preferred solution.

Note: this is a frame challenge - it's not necessary to do in-code.

Assuming a tree,

project
└── pkg
    └── test.py

Where test.py contains

import sys, json; print(json.dumps(sys.path, indent=2)) 

Executing using the path only includes the package directory

python pkg/test.py
[
  "/project/pkg",
 ...
]

But using the module argument includes the project directory

python -m pkg.test
[
  "/project",
  ...
]

Now, all imports can be absolute, from the project directory. No further skullduggery required.

水晶透心 2024-07-23 06:46:50

使用pathlib.Path

import sys
from pathlib import Path
sys.path.append(str(Path(f"{__file__}").parent.parent))
import my_module

Using pathlib.Path

import sys
from pathlib import Path
sys.path.append(str(Path(f"{__file__}").parent.parent))
import my_module
清引 2024-07-23 06:46:50

在开发新模块时,我经常遇到这个问题,但采用了将目录附加到 os.path 的解决方案,所以我所做的就是添加到 every __init__.py 在我的项目中:

import os, sys
pardir = ""
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(current_dir))
while pardir != "p":
    parent_dir = os.path.abspath(os.path.join(current_dir, os.pardir))
    pardir = os.path.basename(parent_dir)
    current_dir = parent_dir
    sys.path.append(parent_dir)

其中“p”是我的项目文件夹,例如:
c:/p/
当向其他人开放项目时,此解决方案不会对您有帮助,您将不得不(像我一样)找到另一个解决方案(当我完成关于我如何从这里开始的代码时,我可能会将其发布在这里),但至少这将帮助您更快地开始原型设计。
我知道这个解决方案已经被讨论过,我只是想分享我的复制粘贴解决方案。
我的结构是这样的:

p
|---project
    |---src
    |    |----__init__.py
    |    |----module.py
    |---tests
    |    |----__init__.py
    |    |----tests.py
    |---__init__.py

在所有地方都有一个 __init__.py 并不能帮助我从 p/project/tests/tests.py 运行我的tests.py

我现在尝试了很多解决方案,但大多数其中一些让我害怕,或者根本不适合我。 为什么 python 这么复杂? 我选择的解决方案也不能让我满意。

i struggled with this a lot when developing a new module, but went with the solution to append the directories to os.path, so what i did was to add to every __init__.py in my project this:

import os, sys
pardir = ""
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(current_dir))
while pardir != "p":
    parent_dir = os.path.abspath(os.path.join(current_dir, os.pardir))
    pardir = os.path.basename(parent_dir)
    current_dir = parent_dir
    sys.path.append(parent_dir)

where "p" is my project folder, like:
c:/p/
this solution won't help you when opening the project to others and you will have to (like me) find another solution (i probably will post it here when i'm done with my code on how i went from here) but at least this will help you start into prototyping faster.
i know this solution has been discussed, i just wanted to share my copy-and-paste solution.
My structure was this:

p
|---project
    |---src
    |    |----__init__.py
    |    |----module.py
    |---tests
    |    |----__init__.py
    |    |----tests.py
    |---__init__.py

having an __init__.py in all places did not help me running my tests.py from p/project/tests/tests.py

i tried a lot of solutions by now, but most of them scared me or simply didnt work for me. Why is this so complicated with python? The solution i chose did not satisfy me either.

一个人的旅程 2024-07-23 06:46:50

首先是代码:

from pathlib import Path
import sys
ptdraft = str(Path(sys.path[0]).parent.parent)
sys.path.insert(0, ptdraft)
import nib

根据文档

sys.path 从这些位置初始化:

  • 包含输入脚本的目录(或当前目录
    当未指定文件时)。

  • PYTHONPATH(目录名称列表,语法与
    shell 变量 PATH)。

  • 依赖于安装的默认值(按照惯例,包括
    site-packages 目录,由 site 模块处理)。

因此,sys.path 是一个类似 ["script/directory/path", "pythonpath/element/1", "pythonpath/element/2", ..., " 的列表。 ../lib/python3.x", ..., ".../lib/python3.x/site-packages"]

脚本目录的路径始终位于该列表的位置 0。 由于OP有他想要导入两个目录的模块(nib.py),他可以使用Path(sys.path[0].parent.parent). sys.path 仅适用于字符串,因此结果必须包装在 str() 中。

下一步是将此路径插入到 sys.path 中的正确位置。 仅当可以在 sys.path 目录中的任何位置找到多个同名模块时,该位置才重要。 为此,有三个明智的选择:

  • .insert(0, ptdraft) 在列表的开头插入,因此具有最高优先级。
  • .insert(1, ptdraft) 将(大)父目录放在脚本目录之后、PYTHONPATH 上的目录之前。
  • .append(ptdraft) 将(大)父目录放在最后作为后备。

First the code:

from pathlib import Path
import sys
ptdraft = str(Path(sys.path[0]).parent.parent)
sys.path.insert(0, ptdraft)
import nib

Per the docs,

sys.path is initialized from these locations:

  • The directory containing the input script (or the current directory
    when no file is specified).

  • PYTHONPATH (a list of directory names, with the same syntax as the
    shell variable PATH).

  • The installation-dependent default (by convention including a
    site-packages directory, handled by the site module).

Hence, sys.path is a list like ["script/directory/path", "pythonpath/element/1", "pythonpath/element/2", ..., ".../lib/python3.x", ..., ".../lib/python3.x/site-packages"]

The path to the script directory is always in position 0 of that list. Since OP has the module (nib.py) that he wants to import two directories up, he can get its directory with Path(sys.path[0].parent.parent). sys.path only works with strings, so the result must be wrapped in str().

The next step is to insert this path into the correct location in sys.path. The location only matters if multiple modules with the same name can be found anywhere in the sys.path directories. There are three sensible choices for this:

  • .insert(0, ptdraft) inserts at the start of the list, hence the highest priority.
  • .insert(1, ptdraft) puts the (grand)parent directory after the script directory and before the directories on the PYTHONPATH.
  • .append(ptdraft) puts the (grand)parent directory at the very end as a fall-back.
最冷一天 2024-07-23 06:46:50

这是对我有用的最简单的解决方案:

from ptdraft import nib

This is the simplest solution that works for me:

from ptdraft import nib
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文