现有属性引起的AttributeError

AttributeError caused by existing attribute

有时 在我的 Django 应用程序试图从缓存中获取或存储某些内容时出现以下错误:

    c = cache.get(pk)
  File "/opt/python3/lib/python3.4/site-packages/django/core/cache/__init__.py", line 131, in __getattr__
    return getattr(caches[DEFAULT_CACHE_ALIAS], name)
  File "/opt/python3/lib/python3.4/site-packages/django/core/cache/__init__.py", line 113, in __getitem__
    cache = _create_cache(alias)
  File "/opt/python3/lib/python3.4/site-packages/django/core/cache/__init__.py", line 88, in _create_cache
    return backend_cls(location, params)
  File "/opt/python3/lib/python3.4/site-packages/django/core/cache/backends/memcached.py", line 185, in __init__
    value_not_found_exception=pylibmc.NotFound)
AttributeError: 'module' object has no attribute 'NotFound'

但是为什么呢?模块有这个属性,大部分时间都可以,没有同名文件可以破解,请问哪里找原因?

>>> import pylibmc
>>> pylibmc.NotFound
<class '_pylibmc.NotFound'>
>>>

tl;dr: 尝试在应用程序启动位置导入 pylibmc,例如 uwsgimanage.py 文件。

我的 猜测 是在 PyLibMCCache.__init__ 内的请求线程中导入 pylibmc 时出现多线程问题,而不是在应用程序启动时。 (IMO Django 在那里进行导入,因为并非所有 Django 安装都使用 pylibmc,因此他们不应该将其作为依赖项强加到每个应用程序上)

虽然 我对 importing 工作原理的内部结构不够熟悉,但我怀疑会发生如下情况

  1. 线程 #1 尝试导入 pylibmc
  2. thread #1 在 sys.modules 中为 pylibmc
  3. 放置了一个占位符
  4. 线程 #2 尝试导入 pylibmc -> AttributeError 被引发
  5. 线程 #1 已完成更新 sys.modules,现在 pylibmc.NotFound 可用

一般来说,Python 似乎 discourage runtime loading of modules 而不是启动时加载。

重点是我的

Note: For projects where startup time is critical, this class [importlib.util.LazyLoader] allows for potentially minimizing the cost of loading a module if it is never used. For projects where startup time is not essential then use of this class is heavily discouraged due to error messages created during loading being postponed and thus occurring out of context.