Introduction
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.
Implementaion
In the below example we will implement a program to open the file and read its contents using two methods.
Method 1
An object can be a Context Manager if we add __enter__ and __exit__ methods.

Method 2
Can create a Context Manager using @contextmanager decorator 1.
The function being decorated must return a generator-iterator when called.
