contextmanager
./code/context_manager/main.py
1#!/usr/bin/env python3
2
3import contextlib
4from contextlib import contextmanager
5
6number = 10
7
8
9def get_number():
10 return number
11
12
13def set_number(n):
14 global number
15 number = n
16
17
18@contextmanager
19def process(new_n):
20 old_n = get_number()
21 set_number(new_n)
22 try:
23 yield
24 finally:
25 set_number(old_n)
26
27
28print(process(1)) # <contextlib._GeneratorContextManager object at 0x108a2ccd0>
29print(type(process(1))) # <class 'contextlib._GeneratorContextManager'>
30assert isinstance(process(1), contextlib._GeneratorContextManager), type(process(1))
31
32with process(100):
33 # inside this block ,number is changed to 100
34 assert number == 100, number
35
36# outside of the above block, number is reset to its original value
37assert number == 10, number
38
39
40class MyProcess:
41 def __init__(self, new_n):
42 self.new_n = new_n
43
44 def __enter__(self):
45 self.old_n = get_number()
46 set_number(self.new_n)
47
48 def __exit__(self, type, value, traceback):
49 set_number(self.old_n)
50
51
52with MyProcess(-1):
53 assert number == -1, number
54
55assert number == 10, number
See also https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager
To manipulate a lock:
@contextmanager
def locked(lock):
lock.acquire()
try:
yield
finally:
lock.release()
with locked(lock):
pass
Or use a class:
class locked:
def __init__(self, lock):
self.lock = lock
def __enter__(self):
self.lock.acquire()
def __exit__(self, type, value, traceback):
self.lock.release()