我有这段代码
mainModule
const searchQuery = {
$or: [
{ msg: new RegExp(query, 'i') },
{ name: new RegExp(query, 'i') },
{ 'err.stack': new RegExp(query, 'i') },
{ 'req.statusCode': new RegExp(query, 'i') },
{ 'req.method': new RegExp(query, 'i') },
{ 'req.headers': new RegExp(query, 'i') },
{ 'res.header': new RegExp(query, 'i') },
{ 'res.statusCode': new RegExp(query, 'i') },
{ time: { $gte: gte, $lte: lte } },
],
};
人
from src.comp.mypackage.wait import Wait
from src.comp.mypackage.men import Men, MenItem
""" Code and stuff using Men and MenItem """
if __name__ == '__main__':
MenuTestDrive.main()
util的
from abc import ABCMeta, abstractmethod
from src.comp.mypackage.util import NullUtil, CompUtil
当运行mainModule时,我收到了这个错误:
from src.comp.mypackage.stack import Stack
from src.comp.mypackage.men import Men
""" Code and stuff using Men and MenItem """
我正在使用pyCharm,但命令行中的错误是相同的。
我可以提供更多代码,但我不认为使用类有任何奇特之处,只会分散注意力。
我应该在哪里寻找失败?
答案 0 :(得分:2)
TL; DR: python不允许循环导入,因此如果模块men
导入,则无法从模块util
导入模块util
来自模块men
。
更长的回答:
你必须明白,在Python import
中,class
,def
等实际上是可执行语句,所有(或几乎)都在运行时发生。在给定进程中第一次导入模块时,将按顺序执行所有顶级语句,创建一个module
实例对象,并将所有顶级名称作为属性(请注意class
,def
和import
所有绑定名称)并插入到sys.modules
缓存dict中,因此下一次导入同一模块将直接从缓存中检索它。
在您的情况下,首次导入时,men
模块会尝试导入util
模块,该模块不在sys.modules
中,因此Python运行时会找到util.py(或.pyc)文件并执行它。然后它到达from src.comp.mypackage.men import Men
。此时,men.py
尚未完全执行,因此没有Men
属性。
规范的解决方案是将循环依赖项提取到第三个模块中,或者将两个模块合并为一个模块,这取决于对具体情况有意义的一个(目标一如既往地使模块具有低耦合和高凝聚力)。 FWIW,循环依赖被认为是糟糕的设计,无论语言是什么,即使语言支持它们。
有时候(通常在复杂的框架中为您的代码和特定的导入顺序强加一些特定的结构),您最终会得到更复杂的循环依赖链(如A.funcX取决于By,B取决于依赖于D的C取决于最终依赖于A.funcZ的E和/或以一种有意义的方式非常难以干净地重构。作为最后的手段,您仍然可以在函数内推迟一些import语句(在上面它将在A.funcX
内)。这仍然被认为是一种不好的做法,应该只是作为最后的手段使用。
作为旁注:从您的软件包命名方案中我可以闻到强大的Java影响力。 Python不是Java!并不是说Java有什么问题,只有these are two wildly different languages和wildly different designs, idioms and philosopies。
尝试在Python中强制使用Java成语和习惯将是一种痛苦和挫折的体验(在这里,做到了......),所以我的建议是:忘掉你用Java学到的大部分内容并开始学习Python而不是语法 - 语法实际上只是语言的一部分,而不一定是最重要的语言。在Python中我们倾向于扁平嵌套,并且不要尝试每个类有一个模块,你可以在一个单独的模块中有一个完整的(微)框架,如果没有实际的理由将它拆分成子模块就没问题。