从不同的文件夹导入文件

时间:2010-12-08 02:07:15

标签: python importerror python-import

我有以下文件夹结构。

application/app/folder/file.py

我想从另一个位于

的Python文件中的 file.py 中导入一些函数

application/app2/some_folder/some_file.py

我试过

from application.app.folder.file import func_name

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

32 个答案:

答案 0 :(得分:1068)

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

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

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

import file

答案 1 :(得分:535)

没有错:

from application.app.folder.file import func_name

只需确保folder还包含__init__.py,这样就可以将其作为一个包附加。不确定为什么其他答案谈论PYTHONPATH

答案 2 :(得分:70)

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

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

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

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

答案 3 :(得分:45)

我认为临时方式是使用文档中描述的the environment variable PYTHONPATHPython2Python3

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

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

答案 4 :(得分:32)

首先导入sys

 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

答案 5 :(得分:31)

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

要执行此操作,请更改此项:

from application.app.folder.file import func_name

到此:

from .application.app.folder.file import func_name

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

答案 6 :(得分:31)

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

上测试的

使用此文件夹结构:

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

其中myfile.py的内容为:

def myfunc():
    print('hello')

main.py中的import语句是:

from myfolder.myfile import myfunc
myfunc()

这将打印 hello

答案 7 :(得分:27)

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

答案 8 :(得分:18)

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

答案 9 :(得分:17)

在linux上的python3中为我工作

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

答案 10 :(得分:14)

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

http://api.linkedin.com/v1/people/~:(firstName,lastName,headline,positions:(company,title,summary,startDate,endDate,isCurrent),industry,location:(name,country:(code)),pictureUrl,publicProfileUrl,emailAddress)?format=json

答案 11 :(得分:12)

这适用于Windows

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

import some_file

答案 12 :(得分: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文档。

答案 13 :(得分:12)

尝试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中具有该顶级目录。 呼<!/ em>的

答案 14 :(得分: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资源管理器)

答案 15 :(得分:7)

在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中引入了以编程方式导入模块,使您可以更好地控制模块的导入方式。有关更多信息,请参考文档。

答案 16 :(得分:7)

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

Python版本:3.X

以下解决方案适用于因为Python 2 is not supported since Jan/1/2020而使用Python 3.X版开发应用程序的人。

项目结构

在python 3中,由于Implicit Namespace Packages,您在项目子目录中不需要__init__.py。参见Is init.py not required for packages in Python 3.3+

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

问题陈述

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

解决方案

#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")

祝您编程愉快!

答案 17 :(得分:6)

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

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

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

答案 18 :(得分:5)

创建软件包的最佳做法是运行并从最高级别目录中的main_module.py之类的模块访问其他模块。

此结构演示您可以通过使用顶级目录文件main_module.py使用和访问子包,父包或同级包和模块。

创建并运行以下文件和文件夹以进行测试:

 package/
    |
    |----- __init__.py (Empty file)
    |------- main_module.py (Contains: import subpackage_1.module_1)        
    |------- module_0.py (Contains: print('module_0 at parent directory, is imported'))
    |           
    |
    |------- subpackage_1/
    |           |
    |           |----- __init__.py (Empty file)
    |           |----- module_1.py (Contains: print('importing other modules from module_1...')
    |           |                             import module_0
    |           |                             import subpackage_2.module_2
    |           |                             import subpackage_1.sub_subpackage_3.module_3)
    |           |----- photo.png
    |           |
    |           |
    |           |----- sub_subpackage_3/
    |                        |
    |                        |----- __init__.py (Empty file)
    |                        |----- module_3.py (Contains: print('module_3 at sub directory, is imported')) 
    |
    |------- subpackage_2/
    |           |
    |           |----- __init__.py (Empty file)
    |           |----- module_2.py (Contains: print('module_2 at same level directory, is imported'))

现在运行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'

打开图片和文件注释:

在包结构中,如果要访问照片,请使用最高目录中的绝对目录。

假设您正在运行main_module.py,并且想在photo.png内打开module_1.py

module_1.py必须包含的内容是:

正确:

image_path = 'subpackage_1/photo.png'
cv2.imread(image_path)

错误:

image_path = 'photo.png'
cv2.imread(image_path)

尽管module_1.pyphoto.png位于同一目录。

答案 19 :(得分:3)

执行此操作,而不是仅执行import ...

from <MySubFolder> import <MyFile>

MyFile位于MySubFolder中。

答案 20 :(得分:3)

我通常创建一个指向要导入模块的符号链接。该符号链接可确保Python解释器可以在当前目录内找到该模块(要将其他模块导入到的脚本中);稍后工作结束时,您可以删除符号链接。另外,您应该忽略.gitignore中的符号链接,以免意外将符号链接的模块提交到您的仓库中。这种方法甚至可以让您成功地使用与正在执行的脚本平行的模块。

ln -s ~/path/to/original/module/my_module ~/symlink/inside/the/destination/directory/my_module

答案 21 :(得分:2)

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

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

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

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

答案 22 :(得分:2)

我遇到了很多问题。我经常来同一页。 在上一个问题中,我必须从固定目录运行 def empty_queue(q: asyncio.Queue): for _ in range(q.qsize()): # Depending on your program, you may want to # catch QueueEmpty q.get_nowait() q.task_done() ,但是每当调试时,我都希望从不同的子目录运行。

server

对我有用,因为在不同的模块上,我必须读取不同的 *。csv 文件,这些文件都位于同一目录中。

最后,我认为对我有用的不是pythonic,而是:

我在要调试的模块顶部使用了import sys sys.insert(1, /path) ,该模块的运行路径不同于通常的路径。

所以:

if __main__

答案 23 :(得分:2)

如果您有多个文件夹和子文件夹,则始终可以从主目录中导入任何类或模块。

例如:项目的树形结构

optionsBuilder.UseInternalServiceProvider(serviceProvider).UseSqlServer()

现在,如果要从 main.py 文件中的user_model.py导入“ UserModel” 类,则可以使用以下方法进行操作:

Project 
├── main.py
├── .gitignore
|
├── src
     ├────model
     |    └── user_model.py
     |────controller
          └── user_controller.py

此外,您可以使用同一行在 user_controller.py 文件中导入相同的类:

from src.model.user_model.py import UserModel

总体而言,您可以引用主项目目录,以将类和文件导入 Project 目录内的任何python文件中。

答案 24 :(得分:1)

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

答案 25 :(得分:1)

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

答案 26 :(得分:1)

├───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

答案 27 :(得分:0)

我正在研究项目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,a.b.dogs确实等于1。

答案 28 :(得分:0)

您可以使用importlib来导入模块,该模块要使用如下所示的字符串从文件夹中导入模块:

import importlib

scriptName = 'Snake'

script = importlib.import_module('Scripts\\.%s' % scriptName)

此示例具有main.py,即上面的代码,然后是一个名为Scripts的文件夹,然后您可以通过更改scriptName变量从该文件夹中调用所需的任何内容。然后,您可以使用script来引用此模块。例如,如果我在Snake模块中有一个名为Hello()的函数,则可以通过以下方式运行此函数:

script.Hello()

我已经在Python 3.6中对此进行了测试

答案 29 :(得分:0)

只需使用os模块中的change dir功能:

os.chdir("Here new director")

比您可以正常导入 More Info

答案 30 :(得分:0)

下面的代码以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

此代码不是我编写的;我在psutilspsutils.test.__init__.py的代码库中找到了它(第1042行;永久链接到2020年9月10日的最新提交)。

用法示例:

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

注意事项:该模块将被视为顶级模块。如果它是更大项目的子模块,则从父包的相对导入将失败。

答案 31 :(得分:0)

以防有人仍在寻找解决方案。这对我有用。

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路径,然后可以通过非相对导入来访问类。