我有以下文件夹结构。
application/app/folder/file.py
我想从位于另一个Python文件中的file.py导入一些功能
application/app2/some_folder/some_file.py
我试过了
from application.app.folder.file import func_name
和其他一些尝试,但到目前为止,我无法正确导入。我怎样才能做到这一点?
我有以下文件夹结构。
application/app/folder/file.py
我想从位于另一个Python文件中的file.py导入一些功能
application/app2/some_folder/some_file.py
我试过了
from application.app.folder.file import func_name
和其他一些尝试,但到目前为止,我无法正确导入。我怎样才能做到这一点?
Answers:
默认情况下,您不能这样做。导入文件时,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
sys.path.append('/path/to/application/app/folder')
是更清洁的imo
sys.path
返回a list
,而不是a deque
,将list
a 转换为a deque
然后返回是很愚蠢的。
没错:
from application.app.folder.file import func_name
只要确保folder
还包含一个__init__.py
,就可以将其作为软件包包含在内。不知道为什么其他答案在谈论PYTHONPATH
。
PYTHONPATH
需要修改的情况。假设您在同一级别上有两个文件夹:A
和B
。A
有一个__init.py__
。尝试从B
内部导入内容A
。
init.py
或__init__.py
文件?
application
并且app
已经是软件包(即,您已经__init__.py
在两个软件包中都有)。由于__init__.py
还添加了folder
,结果application.app.folder
成为一个(子)包,您可以从中访问该模块 application.app.folder.file
,func_name
现在可以导入该模块的符号
当模块处于并行位置时,如下所示:
application/app2/some_folder/some_file.py
application/app2/another_folder/another_file.py
该简写使一个模块对另一模块可见:
import sys
sys.path.append('../')
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
cli/foo.py
从命令行运行能够import cli.bar
sys.path.append('.')
导入模块from app2.some_folder.some_file import your_function
。另外,对我有效的方法是python3 -m app2.another_folder.another_file
从根文件夹运行。
首先在name-file.py中导入sys
import sys
第二个将文件夹路径附加到name-file.py中
sys.path.insert(0, '/the/folder/path/name-package/')
第三步在子目录中创建一个名为__ init __.py的空白文件(这告诉Python它是一个包)
第四次将模块导入name-file.py文件夹内
from name-package import name-module
sys.path.insert
-command ,它也应该可以工作。这样,即使名称文件夹位于任意位置,该解决方案是否仍有效,答案就成了问题。
我认为,一种临时方法是使用文档中所述的环境变量PYTHONPATH
:Python2,Python3
# Linux & OSX
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH
# Windows
set PYTHONPATH=C:\path\to\dirWithScripts\;%PYTHONPATH%
这里的答案不够明确,已在Python 3.6上进行了测试
使用此文件夹结构:
main.py
|
---- myfolder/myfile.py
myfile.py
内容在哪里:
def myfunc():
print('hello')
中的导入语句main.py
为:
from myfolder.myfile import myfunc
myfunc()
这将打印你好。
__init__.py
?
__init__.py
对我不起作用。我使用PY 3.6.5在Ubuntu 18.它适用于Pycharm而不是从终端
在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中引入了以编程方式导入模块的功能,使您可以更好地控制模块的导入方式。有关更多信息,请参考文档。
尝试使用Python的相对导入:
from ...app.folder.file import func_name
从当前目录开始,每个前导点都是层次结构中的另一个更高级别。
问题?如果这对您不起作用,那么您可能会被很多陷阱的相对进口所困扰。阅读答案和评论以获取更多详细信息: 即使使用__init__.py,也如何解决“尝试以非软件包方式进行相对导入”
提示:__init__.py
在每个目录级别都有。您可能需要python -m application.app2.some_folder.some_file
从顶层目录运行(或删除.py),或者在PYTHONPATH中具有该顶层目录。!
我面临着同样的挑战,尤其是在导入多个文件时,这就是我设法克服的方式。
import os, sys
from os.path import dirname, join, abspath
sys.path.insert(0, abspath(join(dirname(__file__), '..')))
from root_folder import file_name
考虑到application
作为根目录为你的Python项目,创建一个空__init__.py
文件application
,app
和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()
将应用程序移至其他环境时,将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文档。
我很特别:我在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资源管理器中)
我几次遇到相同的问题,所以我想分享我的解决方案。
以下解决方案适用于使用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
,我想进口类A
中file_a.py
的文件夹下。
无需像您当前正在开发新项目那样安装软件包
使用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")
一旦安装了应用程序(本文中不包含安装教程)
你可以简单地
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")
编码愉快!
我正在研究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的意图。
您可以使用importlib来导入模块,在该模块中,您可以使用如下所示的字符串从文件夹中导入模块:
import importlib
scriptName = 'Snake'
script = importlib.import_module('Scripts\\.%s' % scriptName)
这个示例有一个main.py,上面的代码是一个代码,然后是一个名为Scripts的文件夹,然后您可以通过更改scriptName
变量从此文件夹中调用所需的任何内容。然后,您可以script
用来引用该模块。例如,如果我Hello()
在Snake模块中调用了一个函数,则可以通过以下方式运行此函数:
script.Hello()
我已经在Python 3.6中测试过
我已经遇到过这些问题很多次了。我经常来同一页。在上一个问题中,我必须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')