从其他文件夹导入文件

问题:从其他文件夹导入文件

我有以下文件夹结构。

application/app/folder/file.py

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

application/app2/some_folder/some_file.py

我试过了

from application.app.folder.file import func_name

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

I have the following folder structure.

application/app/folder/file.py

and I want to import some functions from file.py in another Python file which resides in

application/app2/some_folder/some_file.py

I’ve tried

from application.app.folder.file import func_name

and some other various attempts but so far I couldn’t manage to import properly. How can I do this?


回答 0

默认情况下,您不能这样做。导入文件时,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

By default, you can’t. When importing a file, Python only searches the current directory, 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
# insert at 1, 0 is the script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file

回答 1

没错:

from application.app.folder.file import func_name

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

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. Not sure why the other answers talk about PYTHONPATH.


回答 2

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

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('../')

回答 3

首先在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

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

回答 4

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

# Linux & OSX
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 & OSX
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

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

回答 5

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

使用此文件夹结构:

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

myfile.py内容在哪里:

def myfunc():
    print('hello')

中的导入语句main.py为:

from myfolder.myfile import myfunc
myfunc()

这将打印你好

The answers here are lacking in clarity, this is tested on Python 3.6

With this folder structure:

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

Where myfile.py has the content:

def myfunc():
    print('hello')

The import statement in main.py is:

from myfolder.myfile import myfunc
myfunc()

and this will print hello.


回答 6

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

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

from application.app.folder.file import func_name

对此:

from .application.app.folder.file import func_name

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

Your problem is that Python is looking in the Python directory for this file and not finding it. You must specify that you are talking about the directory that you are in and not the Python one.

To do this you change this:

from application.app.folder.file import func_name

to this:

from .application.app.folder.file import func_name

By adding the dot you are saying look in this folder for the application folder instead of looking in the Python directory.


回答 7

据我所知,__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.


回答 8

在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.


回答 9

在Linux上的python3中为我工作

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

Worked for me in python3 on linux

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

回答 10

尝试使用Python的相对导入:

from ...app.folder.file import func_name

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


问题?如果这对您不起作用,那么您可能会被很多陷阱的相对进口所困扰。阅读答案和评论以获取更多详细信息: 即使使用__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!


回答 11

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

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

回答 12

考虑到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()

Considering application as the root directory for your python project, create an empty __init__.py file in 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()

回答 13

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

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.


回答 14

这对我在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

回答 15

我很特别:我在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资源管理器中)

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

I just complete information : for both Windows and Linux, both relative and absolute path 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 separator for file names and of course you must double \ into Python strings,
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 \, event if it is less ‘Windows-native’ because it is Linux-compatible and simpler to write and copy to Windows explorer)


回答 16

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

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

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

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 SVC branch working copy which can greatly simplify the development cycle time and reduce failure modes of managing different versions of the module.


回答 17

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

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

回答 18

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

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

编码愉快!

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!


回答 19

我正在研究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的意图。

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.


回答 20

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

from <MySubFolder> import <MyFile>

MyFile在MySubFolder中。

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

from <MySubFolder> import <MyFile>

MyFile is inside the MySubFolder.


回答 21

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

You can refresh the Python shell by pressing f5, or go to Run-> Run Module. This way you don’t have to change the directory to read something from the file. Python will automatically change the directory. But if you want to work with different files from different directory in the Python Shell, then you can change the directory in sys, as Cameron said earlier.


回答 22

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

So I had just right clicked on my IDE, and added a new folder and was wondering why I wasn’t able to import from it. Later I realized I have to right click and create a Python Package, and not a classic file system folder. Or a post-mortem method being adding an __init__.py (which makes python treat the file system folder as a package) as mentioned in other answers. Adding this answer here just in case someone went this route.


回答 23

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

import importlib

scriptName = 'Snake'

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

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

script.Hello()

我已经在Python 3.6中测试过

You can use importlib to import modules where you want to import a module from a folder using a string like so:

import importlib

scriptName = 'Snake'

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

This example has a main.py which is the above code then a folder called Scripts and then you can call whatever you need from this folder by changing the scriptName variable. You can then use script to reference to this module. such as if I have a function called Hello() in the Snake module you can run this function by doing so:

script.Hello()

I have tested this in Python 3.6


回答 24

我已经遇到过这些问题很多次了。我经常来同一页。在上一个问题中,我必须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')

I’ve had these problems a number of times. I’ve come to this same page a lot. In my last problem I had to run the server from a fixed directory, but whenever debugging I wanted to run from different sub-directories.

import sys
sys.insert(1, /path) 

did NOT work for me because at different modules I had to read different *.csv files which were all in the same directory.

In the end, what worked for me was not pythonic, I guess, but:

I used a if __main__ on top of the module I wanted to debug, that is run from a different than usual path.

So:

# On top of the module, instead of on the bottom
import os
if __name__ == '__main__':
    os.chdir('/path/for/the/regularly/run/directory')