与目录同名的Python导入类[重复]
Posted
技术标签:
【中文标题】与目录同名的Python导入类[重复]【英文标题】:Python Import Class With Same Name as Directory [duplicate] 【发布时间】:2013-04-21 03:20:48 【问题描述】:假设我有以下 python 源文件布局:
lib/foo.py
lib/foo/bar.py
然后在我的源代码中:
from foo import gaz
我收到一个导入错误:
ImportError: No module named foo
我怎样才能拥有一个 .py 文件和一个同名的目录,以便我可以执行以下操作:
from foo import gaz
from foo.bar import wakawaka
提前致谢!
【问题讨论】:
***.com/questions/279237/… @Moj 不一样。那篇文章是关于相对进口的。我试图弄清楚的问题是如何拥有一个与目录同名的 .py 文件在同一目录中,然后从 .py 导入 【参考方案1】:使用单个导入时您遇到的实际问题是由于 packages 优先于模块:
请注意,当使用
from package import item
时,该项目可以是 包的子模块(或子包),或定义的其他名称 在包中,如函数、类或变量。import
语句首先测试该项目是否在包中定义;如果 不是,它假定它是一个模块并尝试加载它。如果未能 找到它,会引发ImportError
异常。
无论如何,我强烈建议重命名文件或目录,因为您不能导入多个具有给定名称的模块。出现问题是因为每个模块/包对象都存储在sys.modules
中,这是一个简单的dict
,因此它不能包含多个相等的键。
特别是,假设foo.py
和foo
目录位于不同的目录中(如果不是,您仍然无法导入foo.py
),那么:
from foo import gaz
它将加载foo.py
并将模块放入sys.modules
,然后尝试这样做:
from foo.bar import wakaka
将失败,因为导入尝试使用模块 foo.py
而不是包。
如果您首先导入foo.bar
,则会发生相反的情况;导入将使用包而不是模块。
【讨论】:
我尝试执行的唯一导入语句是from foo import gaz
,其中gaz
类在foo.py 中定义。你是说不可能有 foo.py 和 foo/bar.py 然后从 foo.py 导入一个函数?
@DavidWilliams 我已经更新了。您看到的错误是由于导入顺序引起的,尽管当您处理具有相同名称的模块/包时我的第一个答案仍然相关。
我认为实际上我们讨论的内容可能略有不同。试试这个:touch foo.py && mkdir foo && touch foo/__init__.py && touch foo/bar.py
在 foo.py 中创建一个名为 Foo 的类,在 bar.py 中创建一个名为 Bar 的类。然后尝试导入$ python -c "from foo import Foo" Traceback (most recent call last): File "<string>", line 1, in <module> ImportError: cannot import name Foo
@DavidWilliams 您评论中的代码只是证实了我在回答中所说的内容。 foo
包已加载,然后找不到名称 Foo
。您的问题的答案是,您不能在同一目录中拥有 foo.py
和 foo/__init__.py
并且拥有有效的 import
。
嗯,我理解并接受。有点像 Python 上的疣。在 许多 OO 语言中,为了命名空间的目的而设置此文件和目录是很常见的,但没关系。【参考方案2】:
我很确定这不是你应该做的事情,但你可以强制 Python 使用 imp 将特定文件作为模块导入:
import imp
with open("foo.py") as source:
foo = imp.load_module("foo", source, "./", ('', '', imp.PY_SOURCE))
现在你可以这样做了:
gaz_instance = foo.gaz()
【讨论】:
这仅在工作目录与foo.py
相同的情况下有效,但这可能不是真的,因为在某些情况下,OP 的lib
目录可能已添加到sys.path
大大地。要获取目录,您应该调用imp.find_module('foo')
并提取文件的路径。我没有将此添加到我的答案中,因为它是 import
工作方式的一个重大变化,并且仅应在需要时使用(例如,在运行时动态加载插件/扩展)。
imp.find_module('foo')
将返回 /foo/ 目录中的包信息(假设 foo.py 和 /foo/ 在同一个目录中)以上是关于与目录同名的Python导入类[重复]的主要内容,如果未能解决你的问题,请参考以下文章
与 sys.path 顺序无关的与 SDK 包导入同名的 python 站点包
Python:列出子目录中的导入选项,然后导入其中一个[重复]