As far as I understand,
__init__()
and__enter__()
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?Edit: sorry, wasn't paying attention to the docs.
Edit 2: actually, the reason I got confused is because I was thinking of
@contextmanager
decorator. A context manager created using@contextmananger
can only be used once (the generator will be exhausted after the first use), so often they are written with the constructor call insidewith
statement; and if that was the only way to usewith
statement, my question would have made sense. Of course, in reality, context managers are more general than what@contextmanager
can create; in particular context managers can, in general, be reused. I hope I got it right this time?
score:85
As far as I understand,
__init__()
and__enter__()
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.
And your understanding is incorrect. __init__
is called when the object is created, __enter__
when it is entered with with
statement, and these are 2 quite distinct things. Often it is so that the constructor is directly called in with
initialization, with no intervening code, but this doesn't have to be the case.
Consider this example:
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')
myobj
can be initialized separately and entered in multiple with
blocks:
Output:
__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
Furthermore if __init__
and __enter__
weren't separated, it wouldn't be possible to even use the following:
def open_etc_file(name):
return open(os.path.join('/etc', name))
with open_etc_file('passwd'):
...
since the initialization (within open
) is clearly separate from with
entry.
The managers created by contextlib.manager
are single-entrant, but they again can be constructed outside the with
block. Take the example:
from contextlib import contextmanager
@contextmanager
def tag(name):
print("<%s>" % name)
yield
print("</%s>" % name)
you can use this as:
def heading(level=1):
return tag('h{}'.format(level))
my_heading = heading()
print('Below be my heading')
with my_heading:
print('Here be dragons')
output:
Below be my heading
<h1>
Here be dragons
</h1>
However, if you try to reuse my_heading
(and, consequently, tag
), you will get
RuntimeError: generator didn't yield
score:16
Antti Haapalas answer is perfectly fine. I just wanted to elaborate a bit on the usage of arguments (like myClass(* args)
) since that was somewhat unclear to me (retrospective I ask myself why....)
Using arguments for initialising your class in a with
statement is not different from using the class the usual way.
The calls will happen in the following order:
__init__
(allocation of the class)__enter__
(enter context)__exit__
(leaving context)
Simple Example:
class Foo:
def __init__(self, i):
print('__init__ called: {}'.format(i))
self.i = i
def __enter__(self):
print('__enter__ called')
return self
def do_something(self):
print('do something with {}'.format(self.i))
def __exit__(self, *a):
print('__exit__ called')
with Foo(42) as bar:
bar.do_something()
Output:
__init__ called: 42
__enter__ called
do something with 42
__exit__ called
If you want to make sure that your calls can (almost) only be used in a context (e.g. to force the call to __exit__
), see the stackoverflow post here. In the comments you will also find a answer to the question how to use arguments even then.
Credit To: stackoverflow.com
Related Query
- __init__ vs __enter__ in context managers
- Chain dynamic iterable of context managers to a single with statement
- Using different context managers depending on condition
- Parenthesized context managers
- Parenthesized context managers work in python 3.9 but not 3.8
- Friendly usage of a Python iterable over a sequence of context managers
- Hints for nested context managers in a Python 2.6- / Python 3-neutral way?
- spark magic - enter sql context as string
- Understand python3 nested context managers
- Using aiobotocore with context managers
- Fails to perform keys down and hit enter in context menu python selenium
- How do I bind the enter key to a function in tkinter?
- Detecting enter on a QLineEdit or QPushButton
- Multiprocessing with "fork" context blocks on Linux/Intel Xeon with Python 3.6.1?
- Context variables in Python
- Pygame catching Enter Button
- Python 3 Decimal rounding half down with ROUND_HALF_UP context
- C Python: Running Python code within a context
- Returning value when exiting python context manager
- Copy flask request/app context to another process
- Python context manager for temporary variable assignment
- Adding records into table while running the db init
- How to use webdriver as context manager
- Difference between "grid" and "pack" geometry managers
- Python 3 urlopen context manager mocking
- Python: GIL context - switching
- Can you use self.assertRaises as an async context manager?
- Error pickling a `matlab` object in joblib `Parallel` context
- python3 context manager force early exit
- ThreadPoolExecutor with Context Manager "cannot schedule new futures after shutdown"
- How can I prevent context switching when calling an async function?
- Getting tkinter StringVar() error on init
- How can I change this code to use context managers?
- How to access Flask app's context from within embedded Dash app when using app factory pattern?
- Use a class in the context of a different module
- How can I suppress a given exception in a Context Manager?
- How to access flask config variables outside application context according to my project structure?
- The real solution for multiple inheritance with different init parameters
- Why can't add file handler with the form of self.fh in the init method?
- Python 3.6+: Nested multiprocessing managers cause FileNotFoundError
- Context Manager for Popen
- Opening two files simultaneously on a "with" context
- Why can't a module be a context manager (to a 'with' statement)?
- boolean context of a python object
- Creating a hotkey to enter text using python, running in background waiting for key-press
- When I init a dag with a Variable param, it raises an Exception
- Context manager for optionally redirected I/O
- Using Context Manager for Control Flow
- How to check if the Enter key was pressed while using the Walrus operator in Python?
- Use default init values of other classes
More Query from same tag
- Exception Handling Python TypeError: 'NoneType' object is not callable
- How can I append a something from within the parent if it is not in the child?
- Issue with 'google.cloud.storage'. module has no attribute 'Client'
- fastai - plot validation and training accuracy
- How to dump json-like string without quoting keys?
- Python script didn't show nodemcu data on raspberry pi (raspberry role is mqtt broker)
- Function with "for" loop
- python see the code and try to help me friends
- How to add a table to dictionary from a given text file using Python?
- Is there a convention for JSON serialization of Python objects?
- how to split a list into multiple lists with certain ranges?
- Python-3.x: Passing live data between user defined classes
- Can't change instance attribute of my class?
- Extracting specific information from data
- For-loop skipping a term when searching for list of substrings within a list of strings
- Can't save a video in opencv
- Pygame error: No module named 'pygame.base'
- What does eval(dir()[0]) do in python
- Single executable with Python and React.js
- Rounding floats so that they sum to precisely 1
- Tkinter doesn't want to work when using discord.py
- Unresolved reference when using list conprehension?
- how to install pyHook on windows 10
- Python Dictionary in Dictionary
- Button has no ID and no Name, python Selenium
- gcc cant find Python.h
- How to make predictions based on a trained Tensorflow Model?
- Consume Kafka messages from a different container in python
- How to disallow empty parameters in FastAPI?
- Python 3 development and distribution challenges
- SQLAlchemy ForeignKey with dynamic PostgreSQL Schema
- Mining a Dataframe for a Count of Unique Words
- Tkinter modal window doesn't let main window to be maximized
- FastText 0.9.2 - why is recall 'nan'?
- How to get a list of modules imported by a python module