从不同的文件夹导入文件

问题描述 投票:984回答:21

我有以下文件夹结构。

application/app/folder/file.py

我想从另一个驻留的Python文件中的file.py中导入一些函数

application/app2/some_folder/some_file.py

我试过了

from application.app.folder.file import func_name

和其他一些尝试,但到目前为止我无法正确导入。我怎样才能做到这一点?

python importerror python-import
21个回答
1118
投票

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

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

# some_file.py
import sys
sys.path.insert(0, '/path/to/application/app/folder')

import file

17
投票

在linux上的python3中为我工作

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

17
投票

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

import os, sys

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

from root_folder import file_name

15
投票

在Python 3.4及更高版本中,您可以使用import from a source file directly (link to documentation)。这不是最简单的解决方案,但我将这个答案包括在内以便完整。

这是一个例子。首先,要导入的文件名为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中引入了以编程方式导入模块,使您可以更好地控制模块的导入方式。有关更多信息,请参阅文档。


13
投票

试试Python的相对导入:

from ...app.folder.file import func_name

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


问题?如果这不适合你,那么你可能会得到许多陷阱的相对进口。阅读答案和评论以获取更多详细信息:How to fix "Attempted relative import in non-package" even with __init__.py

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


12
投票

这适用于Windows

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

import some_file

12
投票

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

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

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

让我们说你要导入“芒果”模块。您可以在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文档。


9
投票

我很特别:我在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-native',因为它与Linux兼容,并且更易于编写和复制到Windows资源管理器)


6
投票

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

我在Linux上测试了它,但它应该适用于任何支持符号链接的现代操作系统。

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


2
投票

在我的情况下,我有一个类导入。我的文件看起来像这样:

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

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

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

1
投票

您可以按f5刷新Python shell,或转到Run-> Run Module。这样您就不必更改目录以从文件中读取内容。 Python会自动更改目录。但是,如果您想使用Python Shell中不同目录中的不同文件,那么您可以更改sys,as Cameron said中的目录。


559
投票

没有错:

from application.app.folder.file import func_name

只要确保folder还包含__init__.py,这允许它作为包包含在内。不知道为什么其他答案谈论PYTHONPATH


1
投票

所以我刚刚点击我的IDE,并添加了一个新的folder,并想知道为什么我无法从它导入。后来我意识到我必须右键单击并创建一个Python包,而不是一个经典的文件系统文件夹。或者像其他答案中提到的那样,添加__init__.py(使python将文件系统文件夹视为包)的验尸方法。在这里添加这个答案,万一有人走这条路。


0
投票

我正在研究项目a,我希望用户通过pip install a安装以下文件列表:

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

setup.朋友

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,a.b.dogs确实等于1,如预期的那样。


74
投票

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

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

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

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

46
投票

我认为一种特殊的方式是使用文档中描述的the environment variable PYTHONPATHPython2Python3

# Linux & OSX
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

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

35
投票

首先导入系统

 import sys

第二个附加文件夹路径

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

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

  • name-file.py 名称文件夹 __ init __.py name-module.py

四,导入文件夹内的模块

from name-folder import name-module

31
投票

这里的答案缺乏清晰度,这是在Python 3.6上测试的

使用此文件夹结构:

main.py
|
---- myfolder/myfile.py

myfile.py的内容:

def myfunc():
    print('hello')

main.py的进口声明是:

from myfolder.myfile import myfunc
myfunc()

这将打印你好。


31
投票

您的问题是Python正在Python目录中查找此文件而未找到它。您必须指定您正在谈论您所在的目录而不是Python目录。

要做到这一点,你改变这个:

from application.app.folder.file import func_name

对此:

from .application.app.folder.file import func_name

通过添加点,您可以在此文件夹中查找应用程序文件夹,而不是查看Python目录。


28
投票

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


19
投票

考虑将application作为python项目的根目录,在__init__.pyapplicationapp文件夹中创建一个空的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()
© www.soinside.com 2019 - 2024. All rights reserved.