With class as contextmanager

This Wiederkehr this.wiederkehr at gmail.com
Wed Jan 25 07:36:34 EST 2017


Thank you for your answers. Very appreciated.

I ended up doing it as follows:

class MetaLock(type):

    def __init__(cls, *args):
        super().__init__(*args)
        cls.lock = Lock()
        cls.instances = []

    def register(cls, instance):
        cls.instances.append(instance)

    def __enter__(cls):
        cls.lock.acquire()


    def __exit__(cls, exc_type, exc_val, exc_tb):
        for instance in cls.instances:
            instance.cleanup()
        cls.instances = []
        cls.lock.release()
        return False


class Klass(metaclass=MetaLock):

    def __init__(self):
        if not self.__class__.lock.locked():
            raise Exception("You have to use the context manager on
the Class Object!")
        self.__class__.register(self)

    def cleaup(self):
        pass

with Klass:
    inst1 = Klass()
    inst2 = Klass()

    # on leaving the context the cleanup of each instance of Klass is called.

Regards

This


2017-01-25 3:21 GMT+01:00 Terry Reedy <tjreedy at udel.edu>:

> On 1/24/2017 4:31 PM, This Wiederkehr wrote:
>
> having a class definition:
>>
>> class Test():
>>
>> @classmethod
>> def __enter__(cls):
>>     pass
>>
>> @classmethod
>> def __exit__(cls, exception_type, execption_value, callback):
>>     pass
>>
>> now using this as a contextmanager does not work, even though Test is an
>> object and has the two required methods __enter__ and __exit__.
>>
>> it fails with:
>> #Attribute Error: __enter__
>>
>>
>> This is not working because behind the scene it does something like:
>> type(Test).__enter__(Test)
>>
>> But isn't this supposed to be working?
>>
>
> No.  Unqualified 'method' means instance method, not class method.
>
> One can simulate instance methods like so:
>
> >>> import types
> >>> def f(self): print('f called')
>
> >>> class C: pass
>
> >>> c = C()
> >>> c.m = types.MethodType(f, c)
> >>> c.m()
> f called
>
> However, this will not work for dunder methods where the lookup for the
> method starts with the class and not the object itself.
>
> >>> def h(self): return 1
>
> >>> c.__hash__ = types.MethodType(h, c)
> >>> hash(c)  # calls type(c).__hash__, not c.__hash__
> -9223371924496369383
>
> --
> Terry Jan Reedy
>
> --
> https://mail.python.org/mailman/listinfo/python-list
>



-- 
This Wiederkehr
Vorgasse 21
5722 Gränichen
079 785 70 75



More information about the Python-list mailing list