Python: как правильно создавать и уничтожать ресурсы с помощью шаблона дескриптора contextmanager

Я реализую создание и уничтожение ресурсов следующим образом:

import weakref

class Context(object):
    def __init__(self):
        self.resource = object()  # sample resource creation

    def __del__(self):
        self.resource = None  # destroy resource but keep attribute (compare with 'del')

    def get_resource(self):
        """
        return a proxy of the resource so that only this context 
        instance holds a valid instance and can therefore destroy it 
        when it wants to no matter if another 'reference' is hold 
        elsewhere
        """
        return weakref.proxy(self.resource)

class ContextManager(object):
    def __init__(self):
        self._context = None  # create attribute

    def __enter__(self):
        self._context = Context()
        return self._context  # make the context available in the 'with .. as ..' statement

    def __exit__(self, type, value, traceback):
        self._context = None


if __name__ == "__main__":

    with ContextManager() as c:
        print(c.get_resource())  # do something with resource

    """
    although we have left the scope of the with statement this print
    still executes and a check with gc.get_referrers still shows the 
    references in use
    """
    print(c.resource)

Мой вопрос относится к последней строке кода:

Почему контекст и/или ресурс по-прежнему доступны, несмотря на то, что область действия оператора with была оставлена, что должно было вызывать функцию __exit__?


person morph    schedule 12.05.2015    source источник


Ответы (1)


Я был неправ, когда предположил, что поведение области видимости, которое я знаю по C/C++, работает и с python. Решение моей проблемы - вернуть weakref.proxy контекста:

def __enter__(self):
    self._context = Context()
    return weakref.proxy(self._context)
person morph    schedule 12.05.2015