Что означает, что "объект с слабосвязанными ссылками больше не существует"?

Я запускаю код Python и получаю следующее сообщение об ошибке:

Exception exceptions.ReferenceError: 'weakly-referenced object no longer exists' in <bound method crawler.__del__ of <searchengine.crawler instance at 0x2b8c1f99ef80>> ignored

Кто-нибудь знает, что это значит?

P.S. Это код, который вызывает ошибку:

import sqlite

class crawler:

  def __init__(self,dbname):
    tmp = sqlite.connect(dbname)
    self.con = tmp.cursor()

  def __del__(self):
    self.con.close()

crawler =  crawler('searchindex.db')

Ответ 1

Нормальная сильная ссылка AKA - это та, которая поддерживает живой объект: в CPython каждый объект хранит количество (нормальных) ссылок на него (известное как "счетчик ссылок" или RC) и уходит как только RC достигнет нуля (случайная метка поколений и прокручивание также собирает "опорные петли" для сбора мусора ").

Если вы не хотите, чтобы объект оставался в живых только потому, что к нему относится другой, тогда вы используете "слабую ссылку", специальную разновидность ссылок, которая не увеличивает RC; Подробнее см. документы. Конечно, поскольку упомянутый объект CAN удаляется, если не упоминается иначе (вся цель слабого ref, а не нормального!), Ссылающийся на объект должен быть предупрежден, если он пытается использовать объект что ушло - и это предупреждение дается именно за исключением того, что вы видите.

В вашем коде...:

  def __init__(self,dbname):
    tmp = sqlite.connect(dbname)
    self.con = tmp.cursor()

  def __del__(self):
    self.con.close()

tmp является нормальной ссылкой на соединение... но это локальная переменная, поэтому она уходит в конце __init__. Указатель (особенно названный;-) cursor self.con остается, но он внутренне реализован, чтобы удерживать WEAK ref для соединения, поэтому соединение исчезает, когда tmp делает. Таким образом, в __del__ вызов .close завершается с ошибкой (поскольку курсор должен использовать соединение, чтобы закрыть его).

Простейшим решением является следующее крошечное изменение:

  def __init__(self,dbname):
    self.con = sqlite.connect(dbname)
    self.cur = self.con.cursor()

  def __del__(self):
    self.cur.close()
    self.con.close()

Я также воспользовался возможностью использовать con для подключения и cur для курсора, но Python не будет возражать, если вы заинтересованы в их замене (вы просто оставите читателей недоумевающими; -).

Ответ 2

Слабые ссылки - это форма ссылки, которая не мешает сборщику мусора распоряжаться ссылочным объектом. Если вы хотите гарантировать, что объект будет продолжать существовать, вы должны использовать сильную (нормальную) ссылку.

В противном случае нет гарантии, что объект будет или не будет существовать после того, как все нормальные ссылки исчезнут из области.

Ответ 3

Код ссылается на экземпляр, который уже был собран мусором. Чтобы избежать циклических ссылок, вы можете использовать слабую ссылку, которой недостаточно для предотвращения сбора мусора. В этом случае существует файл weakref.proxy(http://docs.python.org/library/weakref.html#weakref.proxy) для объекта searchengine.crawler.