我有这样的文件夹结构:
application
├── app
│ └── folder
│ └── file.py
└── app2
└── some_folder
└── some_file.py
如何从file.py或some_file.py中导入函数?我尝试了:
from application.app.folder.file import func_name
但它不起作用。
我有这样的文件夹结构:
application
├── app
│ └── folder
│ └── file.py
└── app2
└── some_folder
└── some_file.py
如何从file.py或some_file.py中导入函数?我尝试了:
from application.app.folder.file import func_name
但它不起作用。
当前回答
哇,我没想到会花这么多时间在这上面。以下内容对我有用:
操作系统:Windows 10
Python:v3.10.0
注意:由于我是Python v3.10.0,所以我没有使用__init__.py文件,这对我来说无论如何都不起作用。
application
├── app
│ └── folder
│ └── file.py
└── app2
└── some_folder
└── some_file.py
王旭的第一个解决方案对我有效。为了清楚起见,我将其转发了一个绝对的文件参考:
import sys
sys.path.insert(1, 'C:\\Users\\<Your Username>\\application')
import app2.some_folder.some_file
some_file.hello_world()
替代解决方案:然而,这也对我有效:
import sys
sys.path.append( '.' )
import app2.some_folder.some_file
some_file.hello_world()
虽然,我不明白为什么它会起作用。我以为点是对当前目录的引用。但是,当打印出当前文件夹的路径时,当前目录已列在顶部:
for path in sys.path:
print(path)
希望有人能在评论中澄清为什么这样做有效。尽管如此,我也希望它能帮助一些人。
其他回答
下面的代码以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
我在psutils.test.__init__.py的第1042行psutils代码库中发现了这一点(最新提交时间为2020年10月9日)。
用法示例:
script = "/home/username/Documents/some_script.py"
some_module = import_module_by_path(script)
print(some_module.foo())
重要警告:该模块将被视为顶级模块;从父包中的任何相对导入都将失败。
将应用程序移动到其他环境时,使用带有绝对路径的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文档。
还值得注意的是,使用包时,处理多个文件夹更容易,因为可以使用虚线模块名称。
这里的答案不够清晰,这是在Python 3.6上测试的
使用此文件夹结构:
main.py
|
---- myfolder/myfile.py
其中myfile.py包含内容:
def myfunc():
print('hello')
main.py中的import语句是:
from myfolder.myfile import myfunc
myfunc()
这将打印hello。
据我所知,直接在要导入的函数的文件夹中添加__init__.py文件即可完成此任务。
没有问题:
from application.app.folder.file import func_name
只需确保文件夹还包含__init__.py,这允许它作为包包含。不知道为什么其他答案都提到了巨蟒。