Context Managers

To Recap

  • What is an exception?
  • How do you catch exceptions?
  • How do you understand laziness?
  • Generators
  • Decorators
  • What problems do they solve?

Working with a file

data_fn = open('data.txt', 'r')

for index, row in enumerate(data_fn.readlines()):
    print(f'Row {index + 1}: {row}')

What is missing?

data_fn = open('data.txt', 'r')

for index, row in enumerate(data_fn.readlines()):
    print(f'Row {index + 1}: {row}')
    
data_fn.close()

What if...

data_fn = open('data.txt', 'r')

for index, row in enumerate(data_fn.readlines()):
    manipulate_row(row)
    print(f'Row {index + 1}: {row}')
    
data_fn.close()

Handle exceptions

try:
    data_fn = open('data.txt', 'r')

    for index, row in enumerate(data_fn.readlines()):
        manipulate_row(row)
        print(f'Row {index + 1}: {row}')

    data_fn.close()
except Exception:
    data_fn.close()
try:
    data_fn = open('data.txt', 'r')

    for index, row in enumerate(data_fn.readlines()):
        manipulate_row(row)
        print(f'Row {index + 1}: {row}')
except Exception:
    # re-raise the exception
finally:
    data_fn.close()

What is this?

with open('data.txt', 'r') as data_fn:
    for index, row in enumerate(data_fn.readlines()):
        manipulate_row(row)
        print(f'Row {index + 1}: {row}')

With Statement Context Managers

Objects that define the context within the with block

Custom Context Manager

class FileManager():
    def __init__(self, filename, mode='r'):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_value, exc_traceback):
        self.file.close()

Creating a with-block

with FileManager('demo.py', 'w') as f:
    f.write('print("Marto e bok")')

print(f.closed)

 
╰─Ѫ py playground/context_managers.py 
True

╰─Ѫ cat demo.py 
print("Marto e bok")%

But we are too lazy for this...

from contextlib import contextmanager


@contextmanager
def file_manager(filename, mode='r'):
    try:
        file = open(filename, mode)  # __enter__
        yield file  # __enter__ return value
    except Exception:
        pass
    finally:
        file.close()  # __exit__

What if I want to wrap the whole function?

ContextDecorator

class stopwatch(ContextDecorator):
    def __enter__(self):
        self.start = time.time()
        return self

    def __exit__(self, *args):
        end = time.time()
        print('Finished in: ', end - self.start)


@stopwatch()
def foo():
    time.sleep(1)

    with stopwatch():
        print('in with block')
        time.sleep(1)

    print('outside the with block')

Python 101 9th Context Managers

By Hack Bulgaria

Python 101 9th Context Managers

  • 924