AttributeError: __enter__ in context manager implementation

0

I'm trying to understand the workings of Python's gerenciadores de contexto , implementing one based on contextmanager . Here is the script:

class contextmanager(object):

    def __init__(self, func):
        self._func = func

    def __call__(self, *args, **kwargs):
        print('__call__')
        self._gen = self._func(*args, **kwargs)
        return self.__enter__()

    def __enter__(self):
        print('__enter__')
        return next(self._gen)

    def __exit__(self, exc_type, exc_value, exc_tb):
        print('__exit__')
        next(self._gen)


import os

@contextmanager
def changepath(path):
    actual = os.getcwd()
    os.chdir(path)
    yield
    os.chdir(actual)


with changepath('downloads') as path:
    print(os.getcwd())
print(os.getcwd())

But the output is:

__call__
__enter__
Traceback (most recent call last):
  File "C:\Users\Thiaguinho\AppData\Local\Programs\Python\Python36-32\Code\NIGHT\_eigth_asyncio.py", line 99, in <module>
    with changepath('downloads') as path:
AttributeError: __enter__

Can anyone tell me where the error is?

    
asked by anonymous 30.06.2018 / 22:41

1 answer

2
  

Can anyone tell me where the error is?

Yes.

In this line within __call__ :

    return self.__enter__()

The object that with will use must have a __enter__ method. It is automatically called by the language, in the execution of the with command. That is, this line should simply return self . The __enter__ method of the object will be called soon after by the language. When you call __enter__ directly, the code will execute the decorated function up to yield and return, as value of __next__ , the value sent by yield - which, as blank, is None . Next, Python tries to call __enter__ at this value None , and then its error occurs.

As a rule, all methods that are signaled by the two underscores at the beginning and end (called " dunder methods ") are called by language, not explicitly by the programmer.

In addition, for those who are trying to "understand the with " command, you are reimplementing a function that exists in contextlib of the default library and that makes a very advanced use of generator properties to allow them to be implemented with the syntax of a function - I do not know if it is the most didactic way of understanding with . The simple use is with a class that has the methods __enter__ and __exit__ that do directly what you intend to enter and exit with .

    
02.07.2018 / 15:33