Repository navigation
Expand file tree
/
Copy pathcontext_managers.py
More file actions
115 lines (77 loc) · 2.48 KB
/
Copy pathcontext_managers.py
File metadata and controls
115 lines (77 loc) · 2.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
'''
What happens behind the scenes:
with calls __enter__ → sets things up
Your code runs inside the block
with calls __exit__ → cleans up (always, even on errors)
Think of it like a sandwich:
`__enter__ → top bread (setup)
your code → filling
__exit__ → bottom bread (cleanup)`
Why it matters for this role: Every time you connect to a database,
call OpenAI API, or open a file in production —
you need guaranteed cleanup. Context managers handle that.
'''
# class DBConnection:
# def __init__(self, host):
# self.host = host
# def __enter__(self):
# print(f"Connected to {self.host}")
# return self # this becomes the 'as' variable
# def __exit__(self, exc_type, exc_val, exc_tb):
# print(f"Disconnected from {self.host}")
# with DBConnection("localhost") as db:
# print("Running query")
# Connected to localhost
# Running query
# Disconnected from localhost
'''
__exit__ gets 3 arguments — error info if something went wrong:
exc_type → error class (e.g., ValueError)
exc_val → error message
exc_tb → traceback
All three are None if no error happened
'''
# Now your exercise: Write APISession class:
# class APISession:
# def __init__(self, api_key):
# self.api_key = api_key
# def __enter__(self):
# print("Session started")
# return self
# def call(self, path):
# print(f"{path} with key {self.api_key}")
# def __exit__(self, exc_type, exc, tb):
# print("Session closed")
# def main():
# with APISession("abc123") as session:
# session.call("/products")
'''
contextlib — Context Managers Without Classes
Instead of writing a full class with __enter__ and __exit__, you can use a decorator:
'''
# from contextlib import contextmanager
# @contextmanager
# def api_session(api_key):
# # __enter__ part — setup
# print("Session started")
# yield api_key # this value goes to 'as' variable
# # __exit__ part — cleanup
# print("Session closed")
# with api_session("abc123") as key:
# print(f"Calling API with {key}")
# Session started
# Calling API with abc123
# Session closed
from contextlib import contextmanager
import time
@contextmanager
def timer(name):
start_time = time.time()
print(f"{name} started")
try:
yield
finally:
print(f"{name} finished in {time.time()-start_time:.3f}s")
def main():
with timer("API call"):
time.sleep(1)