Nano Hash - криптовалюты, майнинг, программирование

Python создает избыточную ссылку на класс

Я наблюдаю странное поведение с Python 2.7.12 и Python 3.5.2:

import sys

class Foo:
    def __init__(self):
        self.b = self.bar
    def bar(self):
        pass

f = Foo()
print(sys.getrefcount(f) - 1) # subtract the extra reference created by
                              # passing a reference to sys.getrefcount.

Когда я запускаю код в python, я получаю 2, что означает, что есть две ссылки на объект Foo. Единственное решение — удалить self.b = self.bar. Кажется, создается ссылка на цикл.

Кто-нибудь может объяснить поведение?

ОБНОВЛЕНИЕ: вот результаты запуска:

class Foo:
    def __init__(self):
        self.b = self.bar

    def bar(self):
        pass

    def __del__(self):
        print "deleted"

def test_function():
    f = Foo()
    print f

if __name__ == "__main__":
    for i in xrange(5):
        test_function()
    print "finished"

python ./test.py
<__main__.Foo instance at 0x104797e60>
<__main__.Foo instance at 0x104797ef0>
<__main__.Foo instance at 0x104797f38>
<__main__.Foo instance at 0x104797f80>
<__main__.Foo instance at 0x104797fc8>
finished

Как видите, на каждой итерации python создает новый экземпляр класса Foo, но никогда их не выпускает!

ОБНОВЛЕНИЕ 2 И ПРИЧИНА

Объекты, имеющие методы del() и являющиеся частью ссылочного цикла, делают весь ссылочный цикл недоступным для сбора, включая объекты, не обязательно находящиеся в цикле, но доступные только из него. https://docs.python.org/2/library/gc.html#gc.garbage

Экземпляр класса Foo имеет как метод __del__, так и связанный метод self.b = self.bar, что означает, что он определенно является частью эталонного цикла. Таким образом, согласно документации py, экземпляр не подлежит сбору!


  • Ты хочешь сказать, что Фу никогда не собирают? Можете ли вы предоставить код, демонстрирующий, что это так? Просто напечатать счетчик ссылок неубедительно, потому что объекты с ненулевым счетчиком ссылок все равно могут быть собраны. 14.06.2018
  • @Kevin, пожалуйста, найди результаты в обновлении. 19.06.2018
  • @fsqirrel хорошо, что функция __del__ не удаляет, что она должна вызывать super().__del__ или вы просто делаете del, не на 100% уверен, но стоит попробовать 19.06.2018
  • Спасибо, что опубликовали свои результаты. Я получаю тот же вывод, что и вы, когда запускаю ваш код в 2.7, но когда я переношу его в 3.X (изменяя операторы печати на функции и xrange на диапазон), удаленные сообщения появляются после завершения. Я бы не стал полагаться на то, что это всегда происходит даже в 3.X, поскольку в документах говорится, что не гарантируется, что методы __del__() вызываются для объектов, которые все еще существуют, когда интерпретатор выходит. Я собирался предложить вызвать gc.collect() вручную непосредственно перед окончанием вашей программы, но, как ни странно, это не повлияло на результат в версии 2.7. 19.06.2018

Ответы:


1

Дополнительная ссылка скрыта в связанном методе, хранящемся в f.b.

print(f.b.__self__) # <__main__.Foo object at 0x000001CD147FEF98>

При сохранении self.b = self.bar вы создаете связанный метод. Связанный метод отслеживает экземпляр, к которому он привязан. Это то, что позволяет ему неявно передавать self.

То же самое произошло бы, если бы вы вручную создали связанный метод.

import sys

class Foo:
    def bar(self):
        pass

f = Foo()
print(sys.getrefcount(f) - 1) # 1

bound_method = f.bar

print(sys.getrefcount(f) - 1) # 2

Итак, вы правы: создание связанного метода создает ссылочный цикл f -> f.b -> f. Хотя это не проблема, поскольку Python обрабатывает циклические ссылки, поскольку версия 2.0.

14.06.2018
  • Спасибо за оперативный ответ и подробное объяснение! 14.06.2018
  • @fsquirrel, вы, кажется, упомянули в другом комментарии, что ваш экземпляр Foo не собран? Это помогло решить проблему? А если нет, используете ли вы расширение c или реализуете какой-то пользовательский метод `__del__``? 14.06.2018
  • Насколько я знаю, у нас нет расширений. Но у класса есть собственный метод __del__. Он звонит os.fdclose. Это мешает сборке мусора? Да, ваше решение решает проблему :) 19.06.2018
  • Пожалуйста, ознакомьтесь с результатами тестового прогона в обновлении. 19.06.2018
  • Новые материалы

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

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..