Yes, you can get this interface. The object that will be entered/exited in context of a with statement is the resolved attribute. So you can go ahead and define context managers as attributes of your context manager:
from contextlib
import ExitStack # pip install contextlib2
from contextlib
import contextmanager
@contextmanager
def lock(name):
print("entering lock {}".format(name))
yield
print("exiting lock {}".format(name))
@contextmanager
def many(contexts):
with ExitStack() as stack:
for cm in contexts:
stack.enter_context(cm)
yield
class SuperLock(object):
def __init__(self, list_of_locks):
self.list_of_locks = list_of_locks
def __enter__(self):
# implement
for entering the `with self.lock:`
use
case
return self
def __exit__(self, exce_type, exc_value, traceback):
pass
@property
def first_half_only(self):
return many(self.list_of_locks[: 4])
@property
def second_half_only(self):
# yo dawg, we herd you like with - statements
return many(self.list_of_locks[4: ])
Example usage:
>>> list_of_locks = [lock(i) for i in range(8)] >>>
super_lock = SuperLock(list_of_locks) >>>
with super_lock.first_half_only:
...print('indented')
...
entering lock 0
entering lock 1
entering lock 2
entering lock 3
indented
exiting lock 3
exiting lock 2
exiting lock 1
exiting lock 0
Edit: class based equivalent of the lock
generator context manager shown above
class lock(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print("entering lock {}".format(self.name))
return self
def __exit__(self, exce_type, exc_value, traceback):
print("exiting lock {}".format(self.name))
# If you want to handle the exception(
if any), you may use the
#
return value of this method to suppress re - raising error on exit
from contextlib
import contextmanager
class A:
@contextmanager
def i_am_lock(self):
print("entering")
yield
print("leaving")
a = A()
with a.i_am_lock():
print("inside")
Output:
entering inside leaving
I'd use a SimpleNamespace
to allow attribute access to different SuperLock
objects, e.g.:
from types import SimpleNamespace self.lock = SimpleNamespace( all = SuperLock(list_of_locks), first_two_locks = SuperLock(list_of_locks[: 2]), other_locks = SuperLock(list_of_locks[2: ]) ) with self.lock.all: # Issue calls to all hardware protected by these locks. with self.lock.first_two_locks: # Issue calls to all hardware protected by these locks. with self.lock.other_locks: # Issue calls to all hardware protected by these locks.
For python 2, you can use this class to achieve a similar behavior:
class SimpleNamespace:
def __init__(self, ** kwargs):
self.__dict__.update(kwargs)
Context managers defined with asynccontextmanager() can be used either as decorators or with async with statements:,ContextDecorator makes it possible to use a context manager in both an ordinary with statement and also as a function decorator.,When used as a decorator, a new generator instance is implicitly created on each function call. This allows the otherwise “one-shot” context managers created by asynccontextmanager() to meet the requirement that context managers support multiple invocations in order to be used as decorators.,Changed in version 3.10: Async context managers created with asynccontextmanager() can be used as decorators.
from contextlib
import contextmanager
@contextmanager
def managed_resource( * args, ** kwds):
# Code to acquire resource, e.g.:
resource = acquire_resource( * args, ** kwds)
try:
yield resource
finally:
# Code to release resource, e.g.:
release_resource(resource)
>>>
with managed_resource(timeout = 3600) as resource:
...# Resource is released at the end of this block,
...# even
if code in the block raises an exception
from contextlib
import asynccontextmanager
@asynccontextmanager
async def get_connection():
conn = await acquire_db_connection()
try:
yield conn
finally:
await release_db_connection(conn)
async def get_all_users():
async with get_connection() as conn:
return conn.query('SELECT ...')
import time
from contextlib
import asynccontextmanager
@asynccontextmanager
async def timeit():
now = time.monotonic()
try:
yield
finally:
print(f 'it took {time.monotonic() - now}s to run')
@timeit()
async def main():
#...async code...
from contextlib
import contextmanager
@contextmanager
def closing(thing):
try:
yield thing
finally:
thing.close()
from contextlib
import closing
from urllib.request
import urlopen
with closing(urlopen('https://www.python.org')) as page:
for line in page:
print(line)
from contextlib
import asynccontextmanager
@asynccontextmanager
async def aclosing(thing):
try:
yield thing
finally:
await thing.aclose()
Last Updated : 15 May, 2022
Output:
Traceback(most recent call last):
File "context.py", line 3, in
OSError: [Errno 24] Too many open files: 'test.txt'
Context managers allow you to allocate and release resources precisely when you want to. The most widely used example of context managers is the with statement. Suppose you have two related operations which you’d like to execute as a pair, with a block of code in between. Context managers allow you to do specifically that. For example:,While comparing it to the first example we can see that a lot of boilerplate code is eliminated just by using with. The main advantage of using a with statement is that it makes sure our file is closed without paying attention to how the nested block exits.,Okay! This way of implementing Context Managers appear to be more intuitive and easy. However, this method requires some knowledge about generators, yield and decorators. In this example we have not caught any exceptions which might occur. It works in mostly the same way as the previous method.,This is not the only way to implement Context Managers. There is another way and we will be looking at it in the next section.
with open('some_file', 'w') as opened_file:
opened_file.write('Hola!')
file = open('some_file', 'w')
try:
file.write('Hola!')
finally:
file.close()
class File(object):
def __init__(self, file_name, method):
self.file_obj = open(file_name, method)
def __enter__(self):
return self.file_obj
def __exit__(self, type, value, traceback):
self.file_obj.close()
with File('demo.txt', 'w') as opened_file:
opened_file.write('Hola!')
with File('demo.txt', 'w') as opened_file:
opened_file.undefined_function('Hola!')
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: 'file' object has no attribute 'undefined_function'
The context manager protocol has the following methods:,Python context managers work based on the context manager protocol.,The following shows a simple implementation of the open() function using the context manager protocol:,implement the __enter__() and __exit__() methods to support the context manager protocol.
The following program reads the data.txt
file, converts its contents to a number, and shows the result to the standard output:
.wp - block - code { border: 0; padding: 0; } .wp - block - code > div { overflow: auto; } .shcb - language { border: 0; clip: rect(1 px, 1 px, 1 px, 1 px); - webkit - clip - path: inset(50 % ); clip - path: inset(50 % ); height: 1 px; margin: -1 px; overflow: hidden; padding: 0; position: absolute; width: 1 px; word - wrap: normal; word - break: normal; } .hljs { box - sizing: border - box; } .hljs.shcb - code - table { display: table; width: 100 % ; } .hljs.shcb - code - table > .shcb - loc { color: inherit; display: table - row; width: 100 % ; } .hljs.shcb - code - table.shcb - loc > span { display: table - cell; } .wp - block - code code.hljs: not(.shcb - wrap - lines) { white - space: pre; } .wp - block - code code.hljs.shcb - wrap - lines { white - space: pre - wrap; } .hljs.shcb - line - numbers { border - spacing: 0; counter - reset: line; } .hljs.shcb - line - numbers > .shcb - loc { counter - increment: line; } .hljs.shcb - line - numbers.shcb - loc > span { padding - left: 0.75 em; } .hljs.shcb - line - numbers.shcb - loc::before { border - right: 1 px solid #ddd; content: counter(line); display: table - cell; padding: 0 0.75 em; text - align: right; - webkit - user - select: none; - moz - user - select: none; - ms - user - select: none; user - select: none; white - space: nowrap; width: 1 % ; } f = open('data.txt') data = f.readlines() # convert the number to integer and display it print(int(data[0])) f.close() Code language: Python(python)
For example, if the data.txt
contains the string '100'
instead of the number 100, you’ll get the following error:
ValueError: invalid literal
for int() with base 10: "'100'"
Code language: Python(python)
To fix this, you may use the try...except...finally
statement:
try:
f = open('data.txt')
data = f.readlines()
# convert the number to integer and display it
print(int(data[0]))
except ValueError as error:
print(error)
finally:
f.close() Code language: Python(python)
Here is the typical syntax of the with
statement:
with context as ctx:
# use the the object
# context is cleaned upCode language: Python(python)
The following shows how to access the f
variable after the with
statement:
with open('data.txt') as f: data = f.readlines() print(int(data[0])) print(f.closed) # TrueCode language: Python(python)
You can open several content managers at the same time:, Introduction to context managers and the with statement , Introduction to context managers and the with statement , Pandas Transform: Preform operations on groups and concatenate the results
You can open several content managers at the same time:
with open(input_path) as input_file, open(output_path, 'w') as output_file: # do something with both files. # e.g.copy the contents of input_file into output_file for line in input_file: output_file.write(line + '\n')
It has the same effect as nesting context managers:
with open(input_path) as input_file:
with open(output_path, 'w') as output_file:
for line in input_file:
output_file.write(line + '\n')
In this tutorial, we will learn about "Context Manager" in Python and how it is helpful in managing resources, files descriptors, and database connections.,In this tutorial, we have discussed content manager in Python, how to create Content Manager, and how it can help in Resources Management, File management, and managing Database connections.,Now, we will apply the above concept for creating the class, which can help in file resource management. The "file_manager" class will help open the file, read or write content, and then close the file.,Now, we will show how to create a simple database connection management system. There is a limit in opening the number of database connections at a time, sane as File descriptors. Therefore, we use context manager, as it is helpful in managing the connections to the database as the user might have forgotten to close the collection.
OSError Traceback(most recent call last)
in
1 file_descriptors = []
2
for Y in range(10000):
-- -- > 3 file_descriptors.append(open('test_file.txt', 'w'))
OSError: [Errno 24] Too many open files: 'test_file.txt'
The 'init'
method is called
The 'enter'
method is called
The 'with'
statement is block
The 'exit'
method is called
True
Test