with a statement in Python

Python Methods and Functions

# file handling

# 1) not used with statement

file = open ( 'file_path' , 'w' )

file . write ( 'hello world!' )

file . close ()

# 2) no use with statement

file = open ( 'file_path' , ' w' )

try :

file . write ( 'hello world' )

finally :

file .close ()

# use with statement

with open ( ' file_path' , 'w' ) as file :

file . write ( 'hello world!' )

Note that unlike the first two implementations, there is no need to call file.close () when using the with statement. The with statement itself ensures that resources are acquired and released correctly. An exception during file.write () in the first implementation can prevent the file from closing correctly, which can lead to several errors in the code, i.e. many changes to files do not take effect until the file is properly closed.

The second approach in the above example takes care of all exceptions, but using the with statement makes the code compact and much more readable. Thus, the with statement helps avoid errors and leaks by ensuring that the resource is properly released when the code that uses the resource is fully executed. The with statement is commonly used with file streams as shown above, as well as locks, sockets, subprocesses, telnets, etc.

Support for the "with" statement in custom objects

There is nothing special about open () which makes it usable with the with statement with and the same functionality can be provided in custom objects. Support for with assertions in your objects ensures that you never leave open resources. 
To use the with operator in custom objects, you only need to add the __enter __ () and __exit __ () methods to the object's methods. Consider the following example to clarify further.

# simple file writer


class MessageWriter ( object ):

def __ init __ ( self , file_name):

self . file_name = file_name


def __ enter __ ( self ):

  self . file = open ( self . file_name, ' w' )

return self . file


def __ exit __ ( self ):

self . file . close ()

# use with operator with MessageWriter


with MessageWriter ( 'my_file.txt' ) as xfile:

xfile.write ( 'hello world' )

Let's take a look at the above code. If you notice the with keyword follows the MessageWriter constructor. Once execution enters the with context by asserting a MessageWriter object is created and python then calls the __enter __ () method. In this __enter __ () , initialize the resource you want to use in the object. This __enter __ () should always return a handle to the received resource.

What are resource descriptors?
These are descriptors provided by the operating system to access the requested resources. In the next block of code, file is the file stream resource descriptor.

file = open ( 'hello.txt' )

In the provided MessageWriter example __enter __ () the __enter __ () method creates a file descriptor and returns it. The name xfile is used here to refer to the file descriptor returned by the __enter __ () method. The block of code that uses the resulting resource is placed inside the with statement block. Once the code inside the with block is executed, the __exit __ () method is __exit __ () . All resources received are released in __exit __ () . This is how we use with assertion with user-defined objects.

This method interface is __enter __ () and __exit __ () which provides support for the with statement in custom objects is called Context Manager .

The contextlib module

The class-based context manager, as shown above, is not the only way to support the with statement in custom objects. Module contextlib provides some more abstractions built on the base interface context manager. This is how we can rewrite the context manager for the MessageWriter object using the contextlib module.

from contextlib import contextmanager


class MessageWriter ( object ):

  def __ init __ ( self , filename):

self . file_name = filename


@ contextmanager

def open_file ( self ):

  try :

file = open ( self . file_name, 'w' )

  yield file

finally :

file . close ()

# use

message_writer = MessageWriter ( 'hello.txt' )

with message_writer.open_file () as my_file:

my_file.write ( 'hello world' )

In this code example, because of the statement function generator
When open_file () this open_file () , it creates a handle to a resource named file . This resource descriptor is then passed to the caller and represented here by the my_file variable. After executing the code inside the with block, program control returns back to the open_file () function. The open_file () function resumes its execution and executes the code following the yield statement. This part of the code that appears after the yield statement releases the resulting resources.  @contextmanager here is

Get Solution for free from DataCamp guru