__init__ vs __enter__ in context managers
<p>As far as I understand, <code>__init__()</code> and <code>__enter__()</code> methods of the context manager are called exactly once each, one after another, leaving no chance for any other code to be executed in between. What is the purpose of separating them into two methods, and what should I put into each?</p>

<p>Edit: sorry, wasn't paying attention to the docs.</p>

<p>Edit 2: actually, the reason I got confused is because I was thinking of <code>@contextmanager</code> decorator. A context manager created using <code>@contextmananger</code> can only be used once (the generator will be exhausted after the first use), so often they are written with the constructor call inside <code>with</code> statement; and if that was the only way to use <code>with</code> statement, my question would have made sense. Of course, in reality, context managers are more general than what <code>@contextmanager</code> can create; in particular context managers can, in general, be reused. I hope I got it right this time?</p>

<blockquote>
  <p>As far as I understand, <code>__init__()</code> and <code>__enter__()</code> methods of the context manager are called exactly once each, one after another, leaving no chance for any other code to be executed in between.</p>
</blockquote>

<p>And your understanding is incorrect.  <code>__init__</code> is called when the object is created, <code>__enter__</code> when it is entered with <code>with</code> statement, and these are 2 quite distinct things. Often it is so that the constructor is directly called in <code>with</code> initialization, with no intervening code, but this doesn't have to be the case.</p>

<p>Consider this example:</p>

<pre><code>class Foo:
    def __init__(self):
        print('__init__ called')
    def __enter__(self):
        print('__enter__ called')
        return self
    def __exit__(self, *a):
        print('__exit__ called')

myobj = Foo()

print('\nabout to enter with 1')
with myobj:
    print('in with 1')

print('\nabout to enter with 2')
with myobj:
    print('in with 2')
</code></pre>

<p><code>myobj</code> can be initialized separately and entered in multiple <code>with</code> blocks:</p>

<p>Output:</p>

<pre><code>__init__ called

about to enter with 1
__enter__ called
in with 1
__exit__ called

about to enter with 2
__enter__ called
in with 2
__exit__ called
</code></pre>

<p>Furthermore if <code>__init__</code> and <code>__enter__</code> weren't separated, it wouldn't be possible to even use the following:</p>

<pre><code>def open_etc_file(name):
    return open(os.path.join('/etc', name))

with open_etc('passwd'):
    ...
</code></pre>

<p>since the initialization (within <code>open</code>) is clearly separate from <code>with</code> entry.</p>

<hr>

<p>The managers created by <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" rel="nofollow"><code>contextlib.manager</code></a> are single-entrant, but they again can be constructed outside the <code>with</code> block. Take the example:</p>

<pre><code>from contextlib import contextmanager

@contextmanager
def tag(name):
    print("&lt;%s&gt;" % name)
    yield
    print("&lt;/%s&gt;" % name)
</code></pre>

<p>you can use this as:</p>

<pre><code>def heading(level=1):
    return tag('h{}'.format(level))

my_heading = heading()
print('Below be my heading')
with my_heading:
     print('Here be dragons')
</code></pre>

<p>output:</p>

<pre><code>Below be my heading
&lt;h1&gt;
Here be dragons
&lt;/h1&gt;
</code></pre>

<p>However, if you try to reuse the returned object h` block, you will get</p>

<pre><code>RuntimeError: generator didn't yield
</code></pre>

python python-3.x contextmanager