Действительно ли нормально делать закрытие / удаление объектов в __del__? - PullRequest
7 голосов
/ 10 июля 2009

Я думал о том, как писать классы на Python. Более конкретно, как реализован конструктор и как объект должен быть уничтожен. Я не хочу полагаться на подсчет ссылок CPython для очистки объекта. Это в основном говорит мне, что я должен использовать с операторами для управления временем жизни моего объекта и что мне нужен явный метод закрытия / удаления (этот метод может вызываться из __exit__, если объект также является менеджером контекста).

class Foo(object):
    def __init__(self):
        pass
    def close(self):
        pass

Теперь, если все мои объекты ведут себя таким образом, и весь мой код использует операторы или явные вызовы close() (или dispose()), я не вижу необходимости помещать какой-либо код в __del__. Должны ли мы действительно использовать __del__, чтобы избавиться от наших объектов?

Ответы [ 3 ]

13 голосов
/ 11 июля 2009

Краткий ответ: Нет.

Длинный ответ: использовать __del__ сложно, главным образом потому, что не гарантируется, что он будет вызван. Это означает, что вы не можете делать там вещи, которые абсолютно необходимо сделать. Это, в свою очередь, означает, что __del__ в основном может использоваться только для очистки, которая рано или поздно произойдет, например, для очистки ресурсов, которые будут очищены при выходе из процесса, поэтому не имеет значения, если __del__ не позвонить. Конечно, это в целом то же самое, что Python сделает для вас. Так что это делает __del__ бесполезным.

Кроме того, __del__ вызывается, когда Python собирает мусор, и вы не хотите ждать сборки мусора Pythons, а это значит, что вы не можете использовать __del__ в любом случае.

Итак, не используйте __del__. Вместо этого используйте __enter__/__exit__.

К вашему сведению: Вот пример некруглой ситуации, когда деструктор не вызывался:

class A(object):
    def __init__(self):
        print('Constructing A')

    def __del__(self):
        print('Destructing A')

class B(object):
    a = A()

ОК, так что это атрибут класса. Очевидно, это особый случай. Но это говорит о том, что вызов __del__ не так прост. Я почти уверен, что видел больше некруглых ситуаций, когда __del__ не вызывается.

8 голосов
/ 10 июля 2009

Не обязательно. Вы столкнетесь с проблемами, когда у вас есть циклические ссылки. Эли Бендерский хорошо объясняет это в своем блоге:

0 голосов
/ 11 июля 2009

Если вы уверены, что не будете использовать циклические ссылки, тогда используйте __del__ в порядке: как только счетчик ссылок станет равным нулю, виртуальная машина CPython вызовет этот метод и уничтожит объект.

Если вы планируете использовать циклические ссылки - подумайте об этом очень тщательно и проверьте, могут ли помочь слабые ссылки; во многих случаях циклические ссылки являются первым признаком плохого дизайна.

Если у вас нет контроля над тем, как будет использоваться ваш объект, то использование __del__ может быть небезопасным.

Если вы планируете использовать JPython или IronPython, __del__ вообще ненадежен, потому что окончательное уничтожение объекта произойдет при сборке мусора, и это то, что вы не можете контролировать.

В целом, на мой взгляд, __del__ обычно совершенно безопасен и хорош; однако во многих ситуациях может быть лучше сделать шаг назад и попытаться взглянуть на проблему с другой точки зрения; хорошее использование try / исключением и контекстов может быть более питонным решением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...