В Python, как вы можете выгрузить сгенерированные классы - PullRequest
1 голос
/ 28 мая 2009

Я работаю над библиотекой, которая загружает файлы (hfd5 - pytables) в структуру объекта. Фактические классы, используемые для структуры, загружаются в виде строки из файла hdf5, а затем загружен таким образом:

class NamespaceHolder(dict):
    # stmt is the source code holding all the class defs
    def execute(self, stmt):
        exec stmt in self

Проблема заключается в том, что при загрузке нескольких классов, подобных этому, объекты появляются в не подлежащей сбору сборке мусора, а именно в реальных определениях классов. Я также могу загрузить это в глобальный словарь, но проблема остается от осиротевших классов. Есть ли способ выгрузить классы?

Основная проблема - это атрибут class. mro , который содержит ссылку на сам класс, вызывая циклические ссылки, которые не может обрабатывать сборщик мусора.

Вот небольшой тестовый пример, чтобы убедиться в этом:

import gc

if __name__ == "__main__":
    gc.enable()
    gc.set_debug(gc.DEBUG_LEAK)

    code = """
class DummyA(object):
    pass
"""
    context = {}

    exec code in context
    exec code in context

    gc.collect()
    print len(gc.garbage)

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

Ответы [ 2 ]

1 голос
/ 28 мая 2009

gc.set_debug (gc.DEBUG_LEAK) вызывает утечку. Попробуйте это:

import gc

def foo():                              
    code = """
class DummyA(object):
    pass             
"""
    context = {}
    exec code in context
    exec code in context

    gc.collect()
    print len(gc.garbage), len(gc.get_objects())

gc.enable()
foo(); foo() # amount of objects doesn't increase
gc.set_debug(gc.DEBUG_LEAK)
foo() # leaks
1 голос
/ 28 мая 2009

Я думаю, что GC может справиться с циклическими ссылками, однако вам нужно будет удалить ссылку из глобальных () dict:

try:
    del globals()['DummyA']
except KeyError:
    pass

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

...