【问题标题】:Class is in sys.modules but cannot be used. Why?类在 sys.modules 中但不能使用。为什么?
【发布时间】:2015-10-19 10:59:27
【问题描述】:

我有一个文件MySQL.py,其中包含一个类MySQL,定义如下:

class MySQL:
    ... all stuff that is not important here

在同一目录中的其他文件 (test.py) 中,我对这个 MySQL 类进行了条件加载。通过这种条件加载,我的意思是我加载它以防它尚未加载。为了检查它,我像这样使用sys.modules

print("MySQL" not in sys.modules)
if "MySQL" not in sys.modules:
    from MySQL import MySQL
    print("Loaded it")
    print("MySQL" not in sys.modules)
return MySQL()

如您所见,我有一些print's 用于调试目的。当我运行这个文件时,这就是我在控制台中得到的:

$ python3 test.py
True
Loaded it
False
Traceback ...
...
UnboundLocalError: local variable 'MySQL' referenced before assignment

这真的很有趣,因为在控制台中我们看到,一开始模块没有加载(print("MySQL" not in sys.modules) => True),然后我们看到它被加载了,但最后因为一些疯狂的原因@987654332 @ 没有看到这个类。 PS。我应该补充一点,如果我在文件的最开始导入(在所有其他代码之前,那么一切正常)。

编辑

我想,我明白了,所有麻烦的全部原因是我做import的方式将我的类放到sys.modules,但同时它把它放到函数的本地命名空间而不是模块的全局命名空间。就是这样。

【问题讨论】:

  • 您为什么不一开始就导入以使一切正常,就像您应该做的那样?
  • test.py 中的代码是否在函数内部?如果是这样,您还没有第二次导入MySQL,因此它不存在于本地或全局命名空间中,从而导致问题。
  • 为什么你在做“条件加载”?如果它已经加载,那么import 就变成了在sys.modules 中的一个简单查找。
  • @Anand S Kumar。是的,该代码在函数内部,返回语句也在该函数内部
  • 很遗憾,您的问题是XY Problem。你已经有了干净、有效的代码——除非/直到有必要,否则不要乱用它。

标签: python


【解决方案1】:

您的代码不起作用,因为如果之前已加载 MySQL 模块,则您没有导入该类,因此在最后一行调用 MySQL() 的尝试不起作用。

更好的方法是简单地无条件导入。 Python 会在模块加载后对其进行缓存(这是sys.modules 的全部目的),因此如果您多次导入它,其中的重量级代码仍然只会运行一次。

也就是说,如果您的模块在顶层做了很多事情,这可能是设计不佳的标志。也许您应该将部分或全部对象创建或函数内的任何内容移动到某处并在适当的时间调用它。

【讨论】:

  • “也许您应该将部分或全部对象创建或函数内的任何内容移动到某处并在适当的时候调用它。” - 这实际上是我在我的工厂类中所做的,它什么都不做,但会创建不同类的实例。但是,如果我们在实例化特定类之前放置 import 语句,您认为这是一个糟糕的设计吗?如果我们在顶部导入所有可能的类,但在运行时只使用一个类,这会是一个好的设计吗?
  • @Jacobian - 正如 PEP8 所说,是的,简单地将您的导入放在顶部是一个很好的设计。
  • 我无法理解这个想法,即“如果 MySQL 模块之前已加载,......,在最后一行调用 MySQL() 的尝试将无法正常工作。”。为什么它不能工作,如果它已经加载了?
  • @TigerhawkT3。我认为应该有另一种好的设计模式,即您应该只加载/导入您将实际使用的代码。
  • @Jacobian:import 语句做了两件事:必要时加载模块(它只会加载一次,然后缓存),并将请求的名称放入您的命名空间。如果你的命名空间中没有MySQL,你就不能调用它。
猜你喜欢
  • 2010-12-29
  • 2012-05-02
  • 1970-01-01
  • 1970-01-01
  • 2018-07-16
  • 2014-01-15
  • 2011-06-08
相关资源
最近更新 更多