从其他文件夹导入文件


1402

我有以下文件夹结构。

application/app/folder/file.py

我想从位于另一个Python文件中的file.py导入一些功能

application/app2/some_folder/some_file.py

我试过了

from application.app.folder.file import func_name

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



阅读官方文档对我有很大帮助!docs.python.org/3/reference/...
Kavin拉朱小号

Answers:


1436

默认情况下,您不能这样做。导入文件时,Python仅搜索当前目录,入口点脚本运行sys.path所在的目录,并且包括诸如软件包安装目录之类的位置(实际上比这稍微复杂一点,但这涵盖了大多数情况) 。

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

# some_file.py
import sys
# insert at 1, 0 is the script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file

355
sys.path.append('/path/to/application/app/folder')是更清洁的imo
pseudosudo

386
@pseudosudo:是的,但是在开头插入它的好处是可以确保在命名冲突的情况下先搜索其他路径(甚至是内置路径)。
卡梅伦

8
@kreativitea- sys.path返回a list,而不是a deque,将lista 转换为a deque然后返回是很愚蠢的。
ArtOfWarfare 2013年

37
是否将其视为管理文件夹中.py文件的pythonic方法?我想知道...为什么默认情况下不支持它?它没有任何意义,以保持在一个目录下的所有.py文件..
奥菲尔

49
@Ofir:不,这不是一个很好的干净的pythonic解决方案。通常,您应该使用软件包(基于目录树)。这个答案是特定于所提出的问题的,由于某种原因,它继续引起大量的投票。
卡梅隆

707

没错:

from application.app.folder.file import func_name

只要确保folder还包含一个__init__.py,就可以将其作为软件包包含在内。不知道为什么其他答案在谈论PYTHONPATH


47
因为这不包括PYTHONPATH需要修改的情况。假设您在同一级别上有两个文件夹:ABA有一个__init.py__。尝试从B内部导入内容A
msvalkon 2014年

32
什么是内init.py__init__.py文件?
Lorem Ipsum Dolor,2015年

46
@Xinyang可以是空文件。它的存在告诉Python将目录视为一个包。
2015年

9
当然,这个答案假设application并且app已经是软件包(即,您已经__init__.py在两个软件包中都有)。由于__init__.py还添加了folder,结果application.app.folder成为一个(子),您可以从中访问该模块 application.app.folder.filefunc_name现在可以导入该模块的符号
Yibo Yang

29
无论我尝试什么,这都行不通。我想从“同级”目录中导入,所以一上一下。所有人都有__init __.py,包括父母。这是python 3特有的吗?
dasWesen

109

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

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

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

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

24
请注意:只要从导入脚本的包含目录运行导入脚本,此方法就起作用。否则,运行脚本的其他任何目录的父目录都将附加到路径中,并且导入将失败。
卡尔·史密斯

14
为了避免这种情况,我们可以获取文件的父目录sys.path.append(os.path.dirname(os.path.abspath(__file__)))
Rahul

这对我不起作用-我必须在其中添加一个附加的dirname以爬回到父级,以便cli/foo.py从命令行运行能够import cli.bar
RCross

2
@Rahul,您的解决方案不适用于交互式外壳
towi_parallelism

如果从根文件夹(即应用程序文件夹)运行它,则可以使用sys.path.append('.')导入模块from app2.some_folder.some_file import your_function。另外,对我有效的方法是python3 -m app2.another_folder.another_file从根文件夹运行。
沉迷

68

首先在name-file.py中导入sys

 import sys

第二个将文件夹路径附加到name-file.py中

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

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

  • 名称文件
  • 名称包
    • __初始化__.py
    • 名称模块

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

from name-package import name-module

5
由于name-folder位于name-file.py的正下方,即使没有sys.path.insert-command ,它也应该可以工作。这样,即使名称文件夹位于任意位置,该解决方案是否仍有效,答案就成了问题。
巴斯蒂安

55

我认为,一种临时方法是使用文档中所述的环境变量PYTHONPATHPython2Python3

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

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

等一下,我可以用文件名替换myScripts吗?
弗拉基米尔·普京

4
否,目录路径为您的.py文件
Ax3l 2014年

1
不幸的是,如果您使用的是Anaconda,这将无法正常工作,因为PYTHONPATH并不是在内部真正使用的!
information_interchange

有关anaconda的(最近)更改,请参阅此SO,以获取工作流和解决方法的注释:stackoverflow.com/questions/17386880/…通常来说,构建并安装小程序包而不是破解导入目录。
Ax3l

45

这里的答案不够明确,已在Python 3.6上进行了测试

使用此文件夹结构:

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

myfile.py内容在哪里:

def myfunc():
    print('hello')

中的导入语句main.py为:

from myfolder.myfile import myfunc
myfunc()

这将打印你好


9
增加一个初始化的.py在MyFolder文件(空)配置文件为我工作在Linux(Y)
文森特

7
@Vincent是什么意思__init__.py
mrgloom

2
@mrgloom确实是
Vincent

3
由于某种原因,添加__init__.py对我不起作用。我使用PY 3.6.5在Ubuntu 18.它适用于Pycharm而不是从终端
创世ROTAR

9
这与询问从文件树的不同于当前工作目录的另一个分支导入文件的问题完全无关。
亚历山大·罗萨

44

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

为此,您可以更改以下内容:

from application.app.folder.file import func_name

对此:

from .application.app.folder.file import func_name

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


2
这就是解决我的问题
Phi

32

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


7
仅当想要包含该其他目录的脚本已经在sys.path中时
Ax3l

2
sys.path.append(tools_dir)在Windows上使用过,不需要添加__init__.py' file in my directory tools_dir`
herve-

24

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


11
我不知道是否有人试图理解这一点,但是我认为它太复杂了。

23

在Linux上的python3中为我工作

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

6
sys.path.append("/home/linux/folder/")—确保不要使用快捷方式,例如"~/folder/"
daGo

22

尝试使用Python的相对导入:

from ...app.folder.file import func_name

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


问题?如果这对您不起作用,那么您可能会被很多陷阱的相对进口所困扰。阅读答案和评论以获取更多详细信息: 即使使用__init__.py,也如何解决“尝试以非软件包方式进行相对导入”

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


22

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

import os, sys

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

from root_folder import file_name

2
如果您能解释一下它与普通导入有什么不同,您的回答将更有帮助。
not2qubit

1
我有/path/dir1/__init__.py和/path/dir1/mod.py。对于dir1.mod中的/path/some.py,导入功能起作用。在/path/dir2/some.py中时,它仅在我将上述答案复制并粘贴到文件顶部后才起作用。不想编辑我的路径,因为不是我拥有的每个python项目都在/ path /中。
jwal

19

考虑到application作为根目录为你的Python项目,创建一个空__init__.py文件applicationappfolder文件夹。然后在您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()

应该是:sys.path.insert(0,r'/ from / root / directory')
Bolaka,2016年

18

将应用程序移至其他环境时,将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文档。


13

这对我在Windows上有效

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

import some_file

10

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

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

而且,当同时使用Windows \和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资源管理器中)


4
os.path.join('tools','mydir')
Corey Goldberg,

7

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

我在Linux上进行了测试,但是它可以在任何支持符号链接的现代操作系统中使用。

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


7

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

# /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

1
答案中未导入@ not2qubit sys。
沃尔特

6

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

Python版本:3.X

以下解决方案适用于使用Python 3.X版开发您的应用程序的人,因为自从Jan / 1/2020开始不支持Python 2

项目结构

在python 3中,__init__.py由于隐式命名空间包,您不需要在项目子目录中。见的init的.py不需要在Python包3.3+

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

问题陈述

file_b.py,我想进口类Afile_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")

编码愉快!



3

我正在研究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/*'],
  },
)

清单

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的意图。


2

而不是只做一个import ...,这样做:

from <MySubFolder> import <MyFile>

MyFile在MySubFolder中。


1

您可以通过按f5刷新Python Shell,或转到“运行”->“运行模块”。这样,您无需更改目录即可从文件中读取内容。Python将自动更改目录。但是,如果您想使用Python Shell中不同目录中的不同文件,则可以像Cameron先前所说的那样在sys中更改目录。


1

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


1

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

import importlib

scriptName = 'Snake'

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

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

script.Hello()

我已经在Python 3.6中测试过


0

我已经遇到过这些问题很多次了。我经常来同一页。在上一个问题中,我必须server从固定目录运行,但是每次调试时,我都希望从不同的子目录运行。

import sys
sys.insert(1, /path) 

确实不是因为不同的模块,在为我工作,我不得不读不同*的.csv这都在同一个目录中的文件。

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

在要调试的模块上使用了if __main__ 是从不同于通常的路径运行的。

所以:

# On top of the module, instead of on the bottom
import os
if __name__ == '__main__':
    os.chdir('/path/for/the/regularly/run/directory')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.