Где определено, что менеджер контекста with вместе с RLock() неявно вызывает метод lock.acquire()? Как изучающим Python понимать подобное самим?

Изучаю Python. Тщательно, с интересом. Долго пытался понять, как же работает пример с сочетанием типа with RLock() без вызова потом в тексте необходимых методов lock.acquire() и lock.release(). В описаниях RLock или with на docs-python.ru/ указаний на это не увидел. В конце концов нагуглил, что "Оператор with в этом случае вызывает lock.acquire() при входе и lock.release() при выходе." (https://digitology.tech/posts/kontekstnye-menedzhery-v-python/) А как изучающие Phyton это должены понять сами (своими мозгами)? Из чего это следует? (Хорошо, если бы ответ затронул и потенциально схожие проблемы)

Пример кода:

    class Example1:
        def __init__(self):
            self.lock = RLock()

        def example_of_method (self):
            with self.lock:
                print ('lock.acquire() was just called somehow')    

Ответы (2 шт):

Автор решения: Roman-Stop RU aggression in UA

Это описано в документации. В разделе про RLock последний абзац:

Reentrant locks also support the context management protocol.

А по ссылке это описано подробно и с примером:

All of the objects provided by this module that have acquire() and release() methods can be used as context managers for a with statement. The acquire() method will be called when the block is entered, and release() will be called when the block is exited. Hence, the following snippet:

with some_lock:
    # do something...

is equivalent to:

some_lock.acquire()
try:
   # do something...
finally:
   some_lock.release()
→ Ссылка
Автор решения: CrazyElf

Ну, ещё это можно понять чисто по логике. При использовании контекстного менеджера with при заходе в блок вызывается метод __enter__, при выходе __exit__. А дальше нужно смотреть - что именно вызывается в этих методах. Можно либо посмотреть исходники библиотеки и увидеть, что там как-раз и вызываются acquire и release, либо можно через dir() посмотреть, какие есть публичные методы у self.lock и увидеть, что их собственно всего два этих метода и один из них должен вызываться при входе в блок, а другой при выходе. Без вариантов в данном случае, у объекта, создаваемого через RLock(), просто нет никаких других публичных методов для вызова.

→ Ссылка