AttributeError вызван существующим атрибутом

Иногда я получаю следующие ошибки, когда мое приложение 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'>
>>>

1 ответ

Решение

tl;dr: попробуйте импортировать pylibmc в месте запуска приложения, например uwsgi или же manage.py файл.

Я думаю, что это проблема многопоточности при импорте pylibmc в ветке запроса внутри PyLibMCCache.__init__ в отличие от при запуске приложения. (IMO Django выполняет там импорт, потому что не все установки Django используют pylibmc и, следовательно, они не должны навязывать это каждому приложению как зависимость)

Пока я недостаточно знаком с внутренностями того, как import работает, я подозреваю, что происходит что-то вроде ниже

  1. поток № 1 пытается импортировать pylibmc
  2. поток #1 помещает заполнитель в sys.modules за pylibmc
  3. поток № 2 пытается импортировать pylibmc-> AttributeError Поднялся
  4. поток #1 закончил обновление sys.modules и сейчас pylibmc.NotFound доступен

В целом, Python препятствует загрузке модулей во время выполнения, а не к загрузке во время запуска.

акцент мой

Примечание. Для проектов, в которых время запуска является критическим, этот класс [ importlib.util.LazyLoader ] позволяет потенциально минимизировать стоимость загрузки модуля, если он никогда не используется. Для проектов, в которых время запуска не является обязательным, использование этого класса крайне нежелательно из-за того, что сообщения об ошибках, создаваемые во время загрузки, откладываются и, следовательно, происходят вне контекста.

Другие вопросы по тегам