关于python:从不同文件夹导入文件

Importing files from different folder

我有以下文件夹结构。

application/app/folder/file.py

我想从另一个python文件中的file.py导入一些函数,该文件位于

application/app2/some_folder/some_file.py

我试过了

from application.app.folder.file import func_name

还有其他各种各样的尝试,但到目前为止,我还无法正确导入。我该怎么做?


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

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

1
2
3
4
5
# some_file.py
import sys
sys.path.insert(0, '/path/to/application/app/folder')

import file


没有问题:

1
from application.app.folder.file import func_name

只要确保folder也包含一个__init__.py,这就允许它作为一个包包含。不知道为什么其他答案会提到PYTHONPATH


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

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

此速记使一个模块对另一个模块可见:

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


我认为一种特别的方法是使用环境变量PYTHONPATH,如文档中所述:python2,python3

1
2
3
4
5
# Linux & OSX
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

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


这里的答案不够清晰,这是在Python3.6上测试的。

使用此文件夹结构:

1
2
3
main.py
|
---- myfolder/myfile.py

其中,myfile.py具有以下内容:

1
2
def myfunc():
    print('hello')

main.py中的进口报表为:

1
2
from myfolder.myfile import myfunc
myfunc()

这将打印"你好"。


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

要执行此操作,请更改:

from application.app.folder.file import func_name

对此:

1
from .application.app.folder.file import func_name

通过添加点,您将在这个文件夹中查找应用程序文件夹,而不是在python目录中查找。


第一个导入系统

1
 import sys

第二个附加文件夹路径

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

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

  • NAME-FIL.PY
    • 名称文件夹
      • γ-π
      • 名称模块

第四,导入文件夹中的模块

1
from name-folder import name-module


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


application作为python项目的根目录,在applicationappfolder文件夹中创建一个空的__init__.py文件。然后在您的some_file.py中进行如下修改,得到func_名称的定义:

1
2
3
4
5
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()


在Linux上的python3为我工作

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


尝试python的相对导入:

1
from ...app.folder.file import func_name

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

问题?如果这对你不起作用,那么你可能会被很多gotcha的相对进口产品所咬。阅读答案和评论了解更多详细信息:如何修复"尝试在非包中进行相对导入",即使使用uu init_uuy.py

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


这在Windows上对我有效

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

import some_file

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

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

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

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

1
2
3
4
5
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变量。

要了解这是如何工作的,请查看此交互式会话示例:

1
2
3
4
5
6
7
8
9
10
>>> 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文档。


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

1
2
3
4
5
6
import os, sys

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

from root_folder import file_name


我很特别:我在Windows中使用python!

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

当使用windows时,\/都可以用作文件名的分隔符,当然您必须将\加倍为python字符串,一些有效的例子:

1
2
3
4
sys.path.append('c:\\tools\\mydir')
sys.path.append('..\\mytools')
sys.path.append('c:/tools/mydir')
sys.path.append('../mytools')

(注:我认为/\更方便,如果它不是"Windows本机"的话,事件是因为它与Linux兼容,并且写和复制到Windows资源管理器更简单)


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

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

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


在Python3.4及更高版本中,可以直接从源文件导入(链接到文档)。这不是最简单的解决方案,但为了完整性,我要包含这个答案。

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

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

导入上述文件的代码受到文档中示例的强烈启发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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()

输出:

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

注意变量名、模块名和文件名不需要匹配。此代码仍然有效:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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()

输出:

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

python 3.1中引入了以编程方式导入模块,使您能够更好地控制模块的导入方式。有关更多信息,请参阅文档。


您可以按F5刷新python shell,或者转到run->run模块。这样就不必更改目录来读取文件中的内容。python将自动更改目录。但是,如果您想在python shell中处理来自不同目录的不同文件,那么您可以在sys中更改目录,如Cameron前面所说。


在我的例子中,我有一个类要导入。我的文件如下:

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

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

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


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


1
sys.path.insert(0, '/path/to/application/app/folder')