从不同文件夹导入文件

发布于 2024-10-06 17:11:53 字数 405 浏览 1 评论 0 原文

我有这样的文件夹结构:

application
├── app
│   └── folder
│       └── file.py
└── app2
    └── some_folder
        └── some_file.py

How can I import a function from file.py, from inside some_file.py?我尝试过:

from application.app.folder.file import func_name

但不起作用。

I have this folder structure:

application
├── app
│   └── folder
│       └── file.py
└── app2
    └── some_folder
        └── some_file.py

How can I import a function from file.py, from within some_file.py? I tried:

from application.app.folder.file import func_name

but it doesn't work.

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

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

发布评论

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

评论(30

錯遇了你 2024-10-13 17:11:53

注意:这个答案是针对一个非常具体的问题。对于大多数从搜索引擎来到这里的程序员来说,这不是您正在寻找的答案。通常,您会将文件构建为包(请参阅其他答案),而不是修改搜索路径。


默认情况下,你不能。导入文件时,Python 仅搜索运行入口点脚本的目录和 sys.path,其中包括包安装目录等位置(实际上是 比这更复杂一点,但这涵盖了大多数情况)。

但是,您可以在运行时添加到 Python 路径:

# some_file.py
import sys
# caution: path[0] is reserved for script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file

Note: This answer was intended for a very specific question. For most programmers coming here from a search engine, this is not the answer you are looking for. Typically you would structure your files into packages (see other answers) instead of modifying the search path.


By default, you can't. When importing a file, Python only searches the directory that the entry-point script is running from and sys.path which includes locations such as the package installation directory (it's actually a little more complex than this, but this covers most cases).

However, you can add to the Python path at runtime:

# some_file.py
import sys
# caution: path[0] is reserved for script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file
内心激荡 2024-10-13 17:11:53

没有什么问题:

from application.app.folder.file import func_name

只要确保 folder 还包含 __init__.py 即可。这使得它可以作为一个包包含在内。我不确定为什么其他答案谈论 PYTHONPATH

There is nothing wrong with:

from application.app.folder.file import func_name

Just make sure folder also contains an __init__.py. This allows it to be included as a package. I am not sure why the other answers talk about PYTHONPATH.

天生の放荡 2024-10-13 17:11:53

当模块位于并行位置时,如问题所示:

application/app2/some_folder/some_file.py
application/app2/another_folder/another_file.py

此简写使一个模块对另一个模块可见:

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

When modules are in parallel locations, as in the question:

application/app2/some_folder/some_file.py
application/app2/another_folder/another_file.py

This shorthand makes one module visible to the other:

import sys
sys.path.append('../')
夏日浅笑〃 2024-10-13 17:11:53

第一 在 name-file.py 中导入 sys

 import sys

第二 在 name-file.py 中附加文件夹路径

sys.path.insert(0, '/the/folder/path/name-package/')

第三 创建一个名为 __ init __ 的空白文件.py 在你的子目录中(这告诉 Python 它是一个包)

  • name-file.py
  • name-package
    • __ 初始化 __.py
    • 名称模块.py

第四次导入name-file.py文件夹内的模块

from name-package import name-module

First import sys in name-file.py

 import sys

Second append the folder path in name-file.py

sys.path.insert(0, '/the/folder/path/name-package/')

Third Make a blank file called __ init __.py in your subdirectory (this tells Python it is a package)

  • name-file.py
  • name-package
    • __ init __.py
    • name-module.py

Fourth import the module inside the folder in name-file.py

from name-package import name-module
脸赞 2024-10-13 17:11:53

尝试 Python 的相对导入:

from ...app.folder.file import func_name

每个前导点都是从当前目录开始的层次结构中的另一个更高级别。


有问题吗?如果这对你不起作用,那么你可能会被许多相对导入的陷阱所困扰。
阅读答案和评论以获取更多详细信息:
如何修复“尝试相对import in non-package”,即使使用 __init__.py

提示:在每个目录级别都有 __init__.py。您可能需要从顶级目录运行的 python -m application.app2.some_folder.some_file (不包括 .py),或者在 PYTHONPATH 中拥有该顶级目录。 唷!

Try Python's relative imports:

from ...app.folder.file import func_name

Every leading dot is another higher level in the hierarchy beginning with the current directory.


Problems? If this isn't working for you then you probably are getting bit by the many gotcha's relative imports has.
Read answers and comments for more details:
How to fix "Attempted relative import in non-package" even with __init__.py

Hint: have __init__.py at every directory level. You might need python -m application.app2.some_folder.some_file (leaving off .py) which you run from the top level directory or have that top level directory in your PYTHONPATH. Phew!

零度° 2024-10-13 17:11:53

我认为一种临时方法是使用 环境变量 PYTHONPATH 如文档中所述:Python2, Python3

# Linux and OS X
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

# Windows
set PYTHONPATH=C:\path\to\dirWithScripts\;%PYTHONPATH%

I think an ad hoc way would be to use the environment variable PYTHONPATH as described in the documentation: Python2, Python3

# Linux and OS X
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

# Windows
set PYTHONPATH=C:\path\to\dirWithScripts\;%PYTHONPATH%
许仙没带伞 2024-10-13 17:11:53

问题是 Python 在错误的目录中查找该文件。要解决此问题,请尝试使用相对导入。更改

from application.app.folder.file import func_name

为:

from .application.app.folder.file import func_name

添加点指示 Python 在当前文件夹中查找 application 文件夹,而不是在 Python 安装文件夹中查找。

The issue is that Python is looking in the wrong directory for the file. To solve this, try using relative import. Change

from application.app.folder.file import func_name

to:

from .application.app.folder.file import func_name

Adding the dot instructs Python to look for the application folder within the current folder, instead of in the Python install folder.

友欢 2024-10-13 17:11:53

给定一个文件夹结构,如

├── main.py
└── myfolder
    └── myfile.py

其中 myfile.py 包含

def myfunc():
    print('hello')

要从 main.py 调用 myfunc,请使用:

from myfolder.myfile import myfunc
myfunc()

Given a folder structure like

├── main.py
└── myfolder
    └── myfile.py

Where myfile.py contains

def myfunc():
    print('hello')

To call myfunc from main.py, use:

from myfolder.myfile import myfunc
myfunc()
还如梦归 2024-10-13 17:11:53

在 Python 3.4 及更高版本中,您可以从直接源文件(链接到文档)。这不是最简单的解决方案,但为了完整性我将这个答案包括在内。

这是一个例子。首先,要导入的文件,名为 foo.py:

def announce():
    print("Imported!")

导入上面文件的代码,很大程度上受到文档中示例的启发:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

foo = module_from_file("foo", "/path/to/foo.py")

if __name__ == "__main__":
    print(foo)
    print(dir(foo))
    foo.announce()

输出:

<module 'foo' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

请注意变量名称,模块名称,并且文件名不需要匹配。此代码仍然有效:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

baz = module_from_file("bar", "/path/to/foo.py")

if __name__ == "__main__":
    print(baz)
    print(dir(baz))
    baz.announce()

输出:

<module 'bar' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Python 3.1 中引入了以编程方式导入模块,使您可以更好地控制模块的导入方式。请参阅文档以获取更多信息。

In Python 3.4 and later, you can import from a source file directly (link to documentation). This is not the simplest solution, but I'm including this answer for completeness.

Here is an example. First, the file to be imported, named foo.py:

def announce():
    print("Imported!")

The code that imports the file above, inspired heavily by the example in the documentation:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

foo = module_from_file("foo", "/path/to/foo.py")

if __name__ == "__main__":
    print(foo)
    print(dir(foo))
    foo.announce()

The output:

<module 'foo' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Note that the variable name, the module name, and the filename need not match. This code still works:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

baz = module_from_file("bar", "/path/to/foo.py")

if __name__ == "__main__":
    print(baz)
    print(dir(baz))
    baz.announce()

The output:

<module 'bar' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Programmatically importing modules was introduced in Python 3.1 and gives you more control over how modules are imported. Refer to the documentation for more information.

三生殊途 2024-10-13 17:11:53

将应用程序移动到其他环境时,使用带有绝对路径的 sys.path.append 并不理想。使用相对路径并不总是有效,因为当前工作目录取决于脚本的调用方式。

由于应用程序文件夹结构是固定的,我们可以使用 os.path 来获取我们想要导入的模块的完整路径。例如,如果结构如下:

/home/me/application/app2/some_folder/vanilla.py
/home/me/application/app2/another_folder/mango.py

假设您要导入 mango 模块。您可以在 vanilla.py 中执行以下操作:

import sys, os.path
mango_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ '/another_folder/')
sys.path.append(mango_dir)
import mango

当然,您不需要 mango_dir 变量。

要了解其工作原理,请查看此交互式会话示例:

>>> import os
>>> mydir = '/home/me/application/app2/some_folder'
>>> newdir = os.path.abspath(os.path.join(mydir, '..'))
>>> newdir
    '/home/me/application/app2'
>>> newdir = os.path.abspath(os.path.join(mydir, '..')) + '/another_folder'
>>> 
>>> newdir
'/home/me/application/app2/another_folder'
>>> 

并检查 os.path< /a> 文档。

另外值得注意的是,使用 packages 时,处理多个文件夹会变得更加容易,因为可以使用点模块名称。

Using sys.path.append with an absolute path is not ideal when moving the application to other environments. Using a relative path won't always work because the current working directory depends on how the script was invoked.

Since the application folder structure is fixed, we can use os.path to get the full path of the module we wish to import. For example, if this is the structure:

/home/me/application/app2/some_folder/vanilla.py
/home/me/application/app2/another_folder/mango.py

And let's say that you want to import the mango module. You could do the following in vanilla.py:

import sys, os.path
mango_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ '/another_folder/')
sys.path.append(mango_dir)
import mango

Of course, you don't need the mango_dir variable.

To understand how this works look at this interactive session example:

>>> import os
>>> mydir = '/home/me/application/app2/some_folder'
>>> newdir = os.path.abspath(os.path.join(mydir, '..'))
>>> newdir
    '/home/me/application/app2'
>>> newdir = os.path.abspath(os.path.join(mydir, '..')) + '/another_folder'
>>> 
>>> newdir
'/home/me/application/app2/another_folder'
>>> 

And check the os.path documentation.

Also worth noting that dealing with multiple folders is made easier when using packages, as one can use dotted module names.

蛮可爱 2024-10-13 17:11:53

据我所知,直接在要导入的函数的文件夹中添加一个 __init__.py 文件即可完成这项工作。

From what I know, add an __init__.py file directly in the folder of the functions you want to import will do the job.

残花月 2024-10-13 17:11:53

我面临着同样的挑战,特别是在导入多个文件时,这就是我设法克服它的方法。

import os, sys

from os.path import dirname, join, abspath
sys.path.insert(0, abspath(join(dirname(__file__), '..')))

from root_folder import file_name

I was faced with the same challenge, especially when importing multiple files, this is how I managed to overcome it.

import os, sys

from os.path import dirname, join, abspath
sys.path.insert(0, abspath(join(dirname(__file__), '..')))

from root_folder import file_name
疾风者 2024-10-13 17:11:53

这在 Linux 上的 Python 3 中对我有用:

import sys
sys.path.append(pathToFolderContainingScripts)
from scriptName import functionName #scriptName without .py extension

This worked for me in Python 3 on Linux:

import sys
sys.path.append(pathToFolderContainingScripts)
from scriptName import functionName #scriptName without .py extension
别挽留 2024-10-13 17:11:53

application 视为 Python 项目的根目录,在 applicationapp 中创建一个空的 __init__.py 文件> 和 folder 文件夹。然后在 some_file.py 中进行如下更改以获取 func_name 的定义:

import sys
sys.path.insert(0, r'/from/root/directory/application')

from application.app.folder.file import func_name ## You can also use '*' wildcard to import all the functions in file.py file.
func_name()

Considering application as the root directory for your Python project, create an empty __init__.py file in the application, app and folder folders. Then in your some_file.py, make changes as follows to get the definition of func_name:

import sys
sys.path.insert(0, r'/from/root/directory/application')

from application.app.folder.file import func_name ## You can also use '*' wildcard to import all the functions in file.py file.
func_name()
沧笙踏歌 2024-10-13 17:11:53
├───root
│   ├───dir_a
│   │   ├───file_a.py
│   │   └───file_xx.py
│   ├───dir_b
│   │   ├───file_b.py
│   │   └───file_yy.py
│   ├───dir_c
│   └───dir_n

您可以将父目录添加到PYTHONPATH,为了实现这一点,您可以在sys.path中列出的“模块搜索路径”中使用取决于操作系统的路径。因此,您可以轻松添加父目录,如下所示:

# file_b.py

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

from dir_a.file_a import func_name
├───root
│   ├───dir_a
│   │   ├───file_a.py
│   │   └───file_xx.py
│   ├───dir_b
│   │   ├───file_b.py
│   │   └───file_yy.py
│   ├───dir_c
│   └───dir_n

You can add the parent directory to PYTHONPATH, in order to achieve that, you can use OS depending path in the "module search path" which is listed in sys.path. So you can easily add the parent directory like following:

# file_b.py

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

from dir_a.file_a import func_name
旧情勿念 2024-10-13 17:11:53

一种方法是创建一个包并使用绝对导入来访问该包中的其他模块。从包根目录下的脚本启动程序。这种结构允许使用和访问子包、父包以及同级包和模块。

例如,尝试创建以下文件夹结构:

package/
├── __init__.py
├── main_module.py
├── module_0.py
├── subpackage_1/
|   ├── __init__.py
|   ├── module_1.py
|   └── sub_subpackage_3/
|       ├── __init__.py
|       └── module_3.py
└── subpackage_2/
    ├── __init__.py
    └── module_2.py

main_module.py 的内容:

import subpackage_1.module_1

module_0.py 的内容:

print('module_0 at parent directory, is imported')

module_1.py 的内容:

print('importing other modules from module_1...')
import module_0
import subpackage_2.module_2
import subpackage_1.sub_subpackage_3.module_3

module_2.py 的内容:

print('module_2 at same level directory, is imported')

module_3.py 的内容:

print('module_3 at sub directory, is imported')

将所有 __init__.py 文件留空。

现在运行main_module.py;输出将是

importing other modules from module_1...
module_0 at parent directory, is imported
module_2 at same level directory, is imported
module_3 at sub directory, is imported

One way is to create a package and use absolute import to access other modules from the package. Start the program from a script at the root of the package. This structure allows using and accessing sub-packages, parent package, and sibling packages and modules.

As an example, try creating the following folder structure:

package/
├── __init__.py
├── main_module.py
├── module_0.py
├── subpackage_1/
|   ├── __init__.py
|   ├── module_1.py
|   └── sub_subpackage_3/
|       ├── __init__.py
|       └── module_3.py
└── subpackage_2/
    ├── __init__.py
    └── module_2.py

Contents of main_module.py:

import subpackage_1.module_1

Contents of module_0.py:

print('module_0 at parent directory, is imported')

Contents of module_1.py:

print('importing other modules from module_1...')
import module_0
import subpackage_2.module_2
import subpackage_1.sub_subpackage_3.module_3

Contents of module_2.py:

print('module_2 at same level directory, is imported')

Contents of module_3.py:

print('module_3 at sub directory, is imported')

Leave all __init__.py files empty.

Now run main_module.py; the output will be

importing other modules from module_1...
module_0 at parent directory, is imported
module_2 at same level directory, is imported
module_3 at sub directory, is imported
初懵 2024-10-13 17:11:53

就我而言,我有一个类要导入。我的文件如下所示:

# /opt/path/to/code/log_helper.py
class LogHelper:
    # stuff here

在我的主文件中,我通过以下方式包含了代码:

import sys
sys.path.append("/opt/path/to/code/")
from log_helper import LogHelper

In my case I had a class to import. My file looked like this:

# /opt/path/to/code/log_helper.py
class LogHelper:
    # stuff here

In my main file I included the code via:

import sys
sys.path.append("/opt/path/to/code/")
from log_helper import LogHelper
屋檐 2024-10-13 17:11:53

这对我在 Windows 上有效:

# some_file.py on mainApp/app2
import sys
sys.path.insert(0, sys.path[0]+'\\app2')

import some_file

This works for me on Windows:

# some_file.py on mainApp/app2
import sys
sys.path.insert(0, sys.path[0]+'\\app2')

import some_file
傻比既视感 2024-10-13 17:11:53

我多次遇到同样的问题,所以我想分享我的解决方案。

Python 版本:3.X

以下解决方案适用于在 Python 版本 3.X 中开发应用程序的人员,因为 自 2020 年 1 月 1 日起不再支持 Python 2

项目结构

在 python 3 中,由于 隐式命名空间包。请参阅init Python 3.3+ 中的包不需要 .py

Project 
├── main.py
├── .gitignore
|
├── a
|   └── file_a.py
|
└── b
    └── file_b.py

问题陈述

file_b.py 中,我想在 file_a.py 中导入类 A 在文件夹a下。

解决方案

#1 一种快速但肮脏的方法

无需安装软件包,就像您当前正在开发一个新项目一样

使用 try catch 检查是否有错误。代码示例:

import sys
try:
    # The insertion index should be 1 because index 0 is this file
    sys.path.insert(1, '/absolute/path/to/folder/a')  # the type of path is string
    # because the system path already have the absolute path to folder a
    # so it can recognize file_a.py while searching 
    from file_a import A
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

#2 安装你的包

一旦你安装了你的应用程序(在这篇文章中,不包括安装教程),

你就可以简单地

try:
    from __future__ import absolute_import
    # now it can reach class A of file_a.py in folder a 
    # by relative import
    from ..a.file_a import A  
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

快乐编码!

I bumped into the same question several times, so I would like to share my solution.

Python Version: 3.X

The following solution is for someone who develops your application in Python version 3.X because Python 2 is not supported since Jan/1/2020.

Project Structure

In python 3, you don't need __init__.py in your project subdirectory due to the Implicit Namespace Packages. See Is init.py not required for packages in Python 3.3+

Project 
├── main.py
├── .gitignore
|
├── a
|   └── file_a.py
|
└── b
    └── file_b.py

Problem Statement

In file_b.py, I would like to import a class A in file_a.py under the folder a.

Solutions

#1 A quick but dirty way

Without installing the package like you are currently developing a new project

Using the try catch to check if the errors. Code example:

import sys
try:
    # The insertion index should be 1 because index 0 is this file
    sys.path.insert(1, '/absolute/path/to/folder/a')  # the type of path is string
    # because the system path already have the absolute path to folder a
    # so it can recognize file_a.py while searching 
    from file_a import A
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

#2 Install your package

Once you installed your application (in this post, the tutorial of installation is not included)

You can simply

try:
    from __future__ import absolute_import
    # now it can reach class A of file_a.py in folder a 
    # by relative import
    from ..a.file_a import A  
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

Happy coding!

2024-10-13 17:11:53

我很特别:我在 Windows 上使用 Python!

我只是完成信息:对于 Windows 和 Linux,相对路径和绝对路径都适用于 sys.path(我需要相对路径,因为我在多台 PC 上和不同的主目录下使用我的脚本)。

当使用 Windows 时,\/ 都可以用作文件名的分隔符,当然你必须将 \ 复制到 Python 字符串中。以下是一些有效的示例:(

sys.path.append('c:\\tools\\mydir')
sys.path.append('..\\mytools')
sys.path.append('c:/tools/mydir')
sys.path.append('../mytools')

注意:我认为 /\ 更方便,即使它不太“Windows 原生”,因为它是 Linux 兼容的并且更容易编写并复制到 Windows 资源管理器

I'm quite special: I use Python with Windows!

I just complete information: for both Windows and Linux, both relative and absolute paths work into sys.path (I need relative paths because I use my scripts on the several PCs and under different main directories).

And when using Windows, both \ and / can be used as a separator for file names and of course you must double \ into Python strings. Here are some valid examples:

sys.path.append('c:\\tools\\mydir')
sys.path.append('..\\mytools')
sys.path.append('c:/tools/mydir')
sys.path.append('../mytools')

(Note: I think that / is more convenient than \, even if it is less 'Windows-native', because it is Linux-compatible and simpler to write and copy to Windows Explorer)

横笛休吹塞上声 2024-10-13 17:11:53

以下内容对我有用:

操作系统:Windows 10

Python:v3.10.0

注意:由于我是Python v3.10.0,所以我没有使用__init__.py 文件,无论如何这对我不起作用。

application
├── app
│   └── folder
│       └── file.py
└── app2
    └── some_folder
        └── some_file.py

WY Hsu的第一个解决方案对我有用。为了清楚起见,我用绝对文件引用重新发布了它:

import sys
sys.path.insert(1, 'C:\\Users\\<Your Username>\\application')
import app2.some_folder.some_file

some_file.hello_world()

替代解决方案:但是,这也对我有用:

import sys
sys.path.append( '.' )
import app2.some_folder.some_file

some_file.hello_world()

虽然,我不明白它为什么有效。我认为点是对当前目录的引用。但是,当打印当前文件夹的路径时,当前目录已列在顶部:

for path in sys.path:
    print(path)

The following worked for me:

OS: Windows 10

Python: v3.10.0

Note: Since I am Python v3.10.0, I am not using __init__.py files, which did not work for me anyway.

application
├── app
│   └── folder
│       └── file.py
└── app2
    └── some_folder
        └── some_file.py

WY Hsu's first solution worked for me. I have reposted it with an absolute file reference for clarity:

import sys
sys.path.insert(1, 'C:\\Users\\<Your Username>\\application')
import app2.some_folder.some_file

some_file.hello_world()

Alternative Solution: However, this also worked for me:

import sys
sys.path.append( '.' )
import app2.some_folder.some_file

some_file.hello_world()

Although, I do not understand why it works. I thought the dot is a reference to the current directory. However, when printing out the paths to the current folder, the current directory is already listed at the top:

for path in sys.path:
    print(path)
云裳 2024-10-13 17:11:53

不要仅仅执行导入...,而是执行以下操作:

from import

MyFile 位于 MySubFolder 内。

Instead of just doing an import ..., do this :

from <MySubFolder> import <MyFile>

MyFile is inside the MySubFolder.

薯片软お妹 2024-10-13 17:11:53

我正在开发项目 a,我希望用户通过 pip install a 安装该项目,其中包含以下文件列表:

.
├── setup.py
├── MANIFEST.in
└── a
    ├── __init__.py
    ├── a.py
    └── b
        ├── __init__.py
        └── b.py

setup.py

from setuptools import setup

setup (
  name='a',
  version='0.0.1',
  packages=['a'],
  package_data={
    'a': ['b/*'],
  },
)

MANIFEST.in

recursive-include b *.*

a/init.py

from __future__ import absolute_import

from a.a import cats
import a.b

a/a.py

cats = 0

a/b/init.py

from __future__ import absolute_import

from a.b.b import dogs

a/b/b.py

dogs = 1

我通过从 MANIFEST.in

python setup.py install

然后,从我的文件系统 /moustache/armwrestle 上的一个完全不同的位置运行:

import a
dir(a)

这证实了 a.cats 确实等于 0 和 正如预期的那样,abdogs 确实等于 1。

I was working on project a that I wanted users to install via pip install a with the following file list:

.
├── setup.py
├── MANIFEST.in
└── a
    ├── __init__.py
    ├── a.py
    └── b
        ├── __init__.py
        └── b.py

setup.py

from setuptools import setup

setup (
  name='a',
  version='0.0.1',
  packages=['a'],
  package_data={
    'a': ['b/*'],
  },
)

MANIFEST.in

recursive-include b *.*

a/init.py

from __future__ import absolute_import

from a.a import cats
import a.b

a/a.py

cats = 0

a/b/init.py

from __future__ import absolute_import

from a.b.b import dogs

a/b/b.py

dogs = 1

I installed the module by running the following from the directory with MANIFEST.in:

python setup.py install

Then, from a totally different location on my filesystem /moustache/armwrestle I was able to run:

import a
dir(a)

Which confirmed that a.cats indeed equalled 0 and a.b.dogs indeed equalled 1, as intended.

咽泪装欢 2024-10-13 17:11:53

我的解决方案适用于包中包含所有必要的 __init__.py 的人,但导入仍然不起作用。

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

import application.app.folder.file as file

My solution for people who have all the necessary __init__.py in the package, but import still doesn't work.

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

import application.app.folder.file as file
好倦 2024-10-13 17:11:53

已经有很多其他解决方案,但这是我的两分钱。假设您不想执行以下任何操作:

  • add __init__.py files
  • run with python -m mymodule
  • edit __package__
  • add if 签入 __main__
  • 手动编辑 sys.path
  • 编辑 PYTHONPATH
  • 重组项目

您可以使用一个工具来代替将向 sys.path 添加给定的绝对/相对路径,同时确保路径有效且格式正确。

$ pip install importmonkey [github] [pip]

# Example structure
├─ src
│   └─ project
│       ├─ __init__.py
│       └─ module.py
└─ test
    └─ test.py
# Example solution using the tool, in test.py

from importmonkey import add_path
add_path("../src")  # relative to current __file__
import project

# You can add as many paths as needed, absolute or relative, in any file.
# Relative paths start from the current __file__ directory.
# Normal unix path conventions work so you can use '..' and '.' and so on.
# The paths you try to add are checked for validity etc. help(add_path) for details.

隶属关系披露:我制作了 importmonkey。

There are plenty of other solutions already but here is my two cents. Let's say you don't want to do any of these:

  • add __init__.py files
  • run with python -m mymodule
  • edit __package__
  • add if check in __main__
  • edit sys.path by hand
  • edit PYTHONPATH
  • restructure the project

You can instead use a tool that will that will add a given absolute/relative path to sys.path while making sure the path is valid and in the correct format.

$ pip install importmonkey [github] [pip]

# Example structure
├─ src
│   └─ project
│       ├─ __init__.py
│       └─ module.py
└─ test
    └─ test.py
# Example solution using the tool, in test.py

from importmonkey import add_path
add_path("../src")  # relative to current __file__
import project

# You can add as many paths as needed, absolute or relative, in any file.
# Relative paths start from the current __file__ directory.
# Normal unix path conventions work so you can use '..' and '.' and so on.
# The paths you try to add are checked for validity etc. help(add_path) for details.

Disclosure of affiliation: I made importmonkey.

醉殇 2024-10-13 17:11:53

下面的代码以 Python 版本安全的方式导入由其路径给出的 Python 脚本,无论它位于何处:

def import_module_by_path(path):
    name = os.path.splitext(os.path.basename(path))[0]
    if sys.version_info[0] == 2:
        # Python 2
        import imp
        return imp.load_source(name, path)
    elif sys.version_info[:2] <= (3, 4):
        # Python 3, version <= 3.4
        from importlib.machinery import SourceFileLoader
        return SourceFileLoader(name, path).load_module()
    else:
        # Python 3, after 3.4
        import importlib.util
        spec = importlib.util.spec_from_file_location(name, path)
        mod = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(mod)
        return mod

我在 psutils,位于 psutils.test.__init__.py截至 2020 年 10 月 9 日的最新提交)。

使用示例:

script = "/home/username/Documents/some_script.py"
some_module = import_module_by_path(script)
print(some_module.foo())

重要警告:该模块将被视为顶级模块;从其中的父包进行任何相对导入都会失败。

The code below imports the Python script given by its path, no matter where it is located, in a Python version-safe way:

def import_module_by_path(path):
    name = os.path.splitext(os.path.basename(path))[0]
    if sys.version_info[0] == 2:
        # Python 2
        import imp
        return imp.load_source(name, path)
    elif sys.version_info[:2] <= (3, 4):
        # Python 3, version <= 3.4
        from importlib.machinery import SourceFileLoader
        return SourceFileLoader(name, path).load_module()
    else:
        # Python 3, after 3.4
        import importlib.util
        spec = importlib.util.spec_from_file_location(name, path)
        mod = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(mod)
        return mod

I found this in the codebase of psutils, at line 1042 in psutils.test.__init__.py (most recent commit as of 09.10.2020).

Usage example:

script = "/home/username/Documents/some_script.py"
some_module = import_module_by_path(script)
print(some_module.foo())

Important caveat: The module will be treated as top-level; any relative imports from parent packages in it will fail.

装迷糊 2024-10-13 17:11:53

这对我有用。

Python 将包含您启动的脚本的文件夹添加到 PYTHONPATH,因此,如果您运行,

python application/app2/some_folder/some_file.py

则仅将文件夹 application/app2/some_folder 添加到路径(而不是您的基本目录)重新执行中的命令)。相反,将文件作为模块运行,并在 some_folder 目录中添加 __init__.py 。

python -m application.app2.some_folder.some_file

这会将基目录添加到可执行文件 python 的路径中,然后可以通过非相对导入来访问类。

This worked for me.

Python adds the folder containing the script you launch to the PYTHONPATH, so if you run

python application/app2/some_folder/some_file.py

Only the folder application/app2/some_folder is added to the path (not the base directory that you're executing the command in). Instead, run your file as a module and add a __init__.py in your some_folder directory.

python -m application.app2.some_folder.some_file

This will add the base directory to the path to executable python, and then classes will be accessible via a non-relative import.

冬天旳寂寞 2024-10-13 17:11:53

如果从特定路径加载模块的目的是在开发自定义模块期间为您提供帮助,则可以在测试脚本的同一文件夹中创建一个符号链接,指向自定义模块的根目录。对于在该文件夹中运行的任何脚本,此模块引用将优先于安装的任何其他同名模块。

我在 Linux 上对此进行了测试,但它应该可以在任何支持符号链接的现代操作系统中工作。

这种方法的一个优点是,您可以指向位于您自己的本地软件版本控制分支工作副本中的模块,这可以大大简化开发周期时间并减少管理不同版本模块的故障模式。

If the purpose of loading a module from a specific path is to assist you during the development of a custom module, you can create a symbolic link in the same folder of the test script that points to the root of the custom module. This module reference will take precedence over any other modules installed of the same name for any script run in that folder.

I tested this on Linux but it should work in any modern OS that supports symbolic links.

One advantage to this approach is that you can you can point to a module that's sitting in your own local software version control branch working copy which can greatly simplify the development cycle time and reduce failure modes of managing different versions of the module.

不美如何 2024-10-13 17:11:53

您可以使用 pippip install -e . 命令。您必须在项目目录的根目录中创建一个名为 setup.py 的文件,其中包含以下内容:

from setuptools import find_packages, setup

setup(
    name='src',
    packages=find_packages(),
    version='0.1.0',
    description='my_project',
    author='author',
    license='MIT',
)

然后,在项目的根目录中输入 pip install -e . 。这将使所有目录能够以其名称作为模块来调用。例如,如果您的根目录包含子目录 module1module2,每个子目录中都包含脚本,您将能够使用以下命令从任何子目录访问它们: module1

导入 module1.script1 作为 script1

You can use pip's pip install -e . command. You must create a file called setup.py in the root of the project's directory which contains the following:

from setuptools import find_packages, setup

setup(
    name='src',
    packages=find_packages(),
    version='0.1.0',
    description='my_project',
    author='author',
    license='MIT',
)

Afterwards, enter pip install -e . while in your project's root directory. This will enable all directories to be called with their name as a module. For example, if your root directory contains the subdirectories module1 and module2, each with scripts inside them, you will be able to access them from any subdirectories with the following command, for module1:

import module1.script1 as script1

逆光飞翔i 2024-10-13 17:11:53

这个问题可能是由于 PyCharm

我在使用 PyCharm 时遇到了同样的问题。我有这个项目结构

skylake\
   backend\
      apps\
          example.py
      configuration\
          settings.py
   frontend\
      ...some_stuff

,并且 example.py 中的代码 from configuration import settings 引发了导入错误。

问题是,当我打开 PyCharm 时,它认为 skylake 是根路径并运行此代码。

sys.path.extend(['D:\\projects\\skylake', 'D:/projects/skylake'])

为了解决这个问题,我只是将后端目录标记为源根目录。

输入图片这里的描述

它解决了我的问题。

This problem may be due to PyCharm

I had the same problem while using PyCharm. I had this project structure

skylake\
   backend\
      apps\
          example.py
      configuration\
          settings.py
   frontend\
      ...some_stuff

and code from configuration import settings in example.py raised an import error.

The problem was that when I opened PyCharm, it considered that skylake is the root path and ran this code.

sys.path.extend(['D:\\projects\\skylake', 'D:/projects/skylake'])

To fix this I just marked backend directory as the source root.

Enter image description here

And it's fixed my problem.

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