Context Managers
Definition
Context managers
allow users to perform operations within a certain overarching context, be it in the form of a time counter a database connection, or the use of a file. They manage to do it by implementing a runtime context. In this context, the specified operation is first performed and then, the context automatically gets closed. This prevents the users from the hassle of closing it manually.
Regardless of the many different use cases that context managers can be used for, the context manager protocol always articulates four functionalities:
- Opening the resource
- Implementing the runtime context
- Handling the possible exceptions
- Closing the resource
Once the runtime context is started, the user input finds its place.
File Manipulation
The open()
function is the standard context manager for opening, performing operations on, and closing files:
# Printing the first four lines of the poem "L'albatros"with open('albatros.txt', 'r') as poem:for i in range(4):print(poem.readline())
The above code produces the following output:
Souvent, pour s'amuser, les hommes d'équipagePrennent des albatros, vastes oiseaux des mers,Qui suivent, indolents compagnons de voyage,Le navire glissant sur les gouffres amers.
Customized Context Managers
While open()
is at the core of using context managers with files, it is still possible to implement context managers with additional capabilities, e.g., personalizing files written using them. It can be done via two approaches:
Class-Based Approach
The class-based approach rests on three class methods:
__init__()
__enter__()
__exit__()
The context manager is invoked using the _with...as_
syntax and an instantiation of the class with needed parameters. The instantiation mobilizes a file thanks to the __open__()
method and the file is in turn handled by the __enter__()
method, allowing the operations indented in the _with_
block to be performed. Whatever the __enter__()
method does a _return_
can then be referred to in the indented block. Lastly, the __exit__()
method puts the final touch by closing the file and handling any potential exceptions.
Note:
_return True_
allows the users to close the file and go ahead in the script even if an exception occurs.
The below code exemplifies the class-based approach applied to an HR department sending automated yearly bonus notifications to employees. Here, the context manager prepares all the letters by looping through a dictionary that contains records for all employees:
class bonus:def __init__(self, employee_first,employee_id, salary, percentage):self.first = employee_firstself.id = employee_idself.salary = salaryself.pct = percentageself.letter = open(str(self.id)+'_bonus_notice.txt','w')self.thanks_message = open('thanks_message.txt', 'r')self.conclusion = open('conclusion.txt','r')def __enter__(self):self.letter.write('Dear '+self.first +'!\n\n')self.letter.write(self.thanks_message.read())self.letter.write('\nYou will receive in addition to your December salary a yearly bonus that amounts to $'\+str(round(self.salary*(self.pct/100)))+'.\n')def __exit__(self,*exc):self.letter.write(self.conclusion.read())self.thanks_message.close()self.conclusion.close()self.letter.close()return Truewith bonus('John',3789,100000,5) as john_smith_bonus:print('Letter printed!')
The output for the above code is as follows:
Dear John!We value all our employees and are committed to their growth and well-being. We would like to thank you for your amazing work throughout this whole year.You will receive in addition to your December salary a yearly bonus that amounts to $5000.Again, allow us to thank you for all your efforts and to wish you all the best, for you and your family.Sincerely yours,Your HR department
Decorator-Based Approach
In decorator-based approach, a generator function (i.e., a function performing a _yield_
and not a _return_
) is defined rather than a class. This function is decorated using @contextmanager
from the built-in module contextlib
:
from contextlib import contextmanager
A decorator-based context manager also uses the user input in the form of parameters provided at the instantiation. It follows the syntax _try-except-finally_
, where _try_
is the part where the _yield_
statement is and the core operations are done, _except_
being the part where the exceptions are handled and _finally_
being the part where the resources are closed.
The below code shows an implementation of a decorator-based context manager thanks to which interview proposals are sent to pre-selected candidates. It is also possible (but not mandatory) to introduce some personalized elements in the indented block. Doing so places this element just before the timeslot proposal:
@contextmanagerdef interview_proposal(title_name, position, date, time):proposal_letter = open(title_name+'_interview_proposal.txt','w')try:proposal_letter.write('Dear '+title_name + ',\n\nThanks a lot for being interested in working with us! \We reviewed your application for the '+position+ ' role and we want to schedule a first-visit interview with you.')yield proposal_letterexcept:print('Exception handled!')finally:proposal_letter.write('Would you be available on '+date+ ' at '+time+'?\\n\nWe look forward to hearing from you again! \nThe HR dept.')proposal_letter.close()with interview_proposal('Mr. Smith', 'Software Developer', 'Monday the 10th of June', '2 pm') as proposal_smith:proposal_smith.write(' We are especially interested by your latest experience as a project leader \for wealth management software. ')
Here is the output:
Dear Mr. Smith,Thanks a lot for being interested in working with us! We reviewed your application for the Software Developer role and we want to schedule a first-visit interview with you. We are especially interested in your latest experience as a project leader for wealth management software. Would you be available on Monday the 10th of June at 2 pm?We look forward to hearing from you again!The HR dept.
All contributors
- Anonymous contributor
- Anonymous contributor
Contribute to Docs
- Learn more about how to get involved.
- Edit this page on GitHub to fix an error or make an improvement.
- Submit feedback to let us know how we can improve Docs.