try
to be immediately followed by except
, finally
, or else
, not by other statements.try:
x = 1 / 0
print("testing whether this will be printed or not")
except ZeroDivisionError:
print("Can't divide by zero.")
This code will raise a SyntaxError
โ specifically:
SyntaxError: expected 'except' or 'finally' block
Because:
print("testing...")
is outside the try
block.try
to be immediately followed by except
, finally
, or else
, not by other statements.def get_db():
db = {"name": "fake_db"}
try:
yield db
finally:
print("Closing database connection...")
@app.get("/blacklist")
async def get_blacklist(db: dict = Depends(get_db)):
return {"db_name": db["name"]}
finally
executed after the response is sent back?In FastAPI, when you use a Depends(...)
function that includes a yield
, FastAPI treats it as a generator dependency โ meaning:
@app.get("/something")
def handler(resource = Depends(get_resource)):
# Step 1: FastAPI calls get_resource() up to yield
# Step 2: It passes yielded value to the route
# Step 3: Route handler runs and response is returned
# Step 4: FastAPI resumes get_resource(), runs finally
In short:
FastAPI doesn't call your dependency like a regular function.
It uses your generator like a context manager, and thefinally
is part of the teardown step, after your route finishes responding.
with
blockwith open("file.txt") as f:
data = f.read()
# after this, file is automatically closed
Similarly, FastAPI handles your generator-dependency with:
try:
db = yield fake_db
finally:
db.close()
It makes sure to wait until your route is finished before running the cleanup (finally
).
A generator is a special type of function that:
yield
instead of return
def count_up_to(n):
i = 1
while i <= n:
yield i # pause here and return i
i += 1
c = count_up_to(3)
print(next(c)) # โ 1
print(next(c)) # โ 2
print(next(c)) # โ 3
Output:
1
2
3
Each call to
next()
resumes the generator right after the lastyield
.
Feature | Description |
---|---|
yield | Temporarily returns a value and pauses the function |
next() | Resumes execution until next yield |
finally | Runs when generator is closed or exhausted |
StopIteration | Raised when no more yield left |
yield
is used in dependencies to open a resource, andfinally
is used to clean up the resource after the responseFeature | Generator | Iterator |
---|---|---|
What is it? | A type of iterator built using yield | A general interface with __iter__ and __next__ |
How to create? | With a function using yield | By defining a class with __iter__ and __next__ |
Memory usage | Efficient โ lazy (one item at a time) | Can be lazy or not, depends on implementation |
Syntax | Short and elegant | Verbose โ boilerplate required |
State handling | Handled automatically by Python | You manage state manually |
One-time use? | Yes (can't restart once exhausted) | Usually yes, unless re-implemented |
Great observation โ you're absolutely right! Generators and iterators are closely related, but they are not the same. Let's compare them thoroughly:
Feature | Generator | Iterator |
---|---|---|
What is it? | A type of iterator built using yield | A general interface with __iter__ and __next__ |
How to create? | With a function using yield | By defining a class with __iter__ and __next__ |
Memory usage | Efficient โ lazy (one item at a time) | Can be lazy or not, depends on implementation |
Syntax | Short and elegant | Verbose โ boilerplate required |
State handling | Handled automatically by Python | You manage state manually |
One-time use? | Yes (can't restart once exhausted) | Usually yes, unless re-implemented |
An object is an iterator if it implements:
__iter__()
โ returns the iterator object itself__next__()
โ returns the next value, or raises StopIteration
class Counter:
def __init__(self, max):
self.max = max
self.current = 1
def __iter__(self):
return self
def __next__(self):
if self.current > self.max:
raise StopIteration
value = self.current
self.current += 1
return value
c = Counter(3)
for i in c:
print(i)
Output:
1
2
3
A generator is a function that automatically builds an iterator by using yield
. Python takes care of the internal state and iterator protocol for you.
def counter(max):
current = 1
while current <= max:
yield current
current += 1
c = counter(3)
for i in c:
print(i)
Output:
1
2
3
Same result, but with much simpler syntax.
This is important:
gen = (x for x in range(3))
print(iter(gen) is gen) # โ
True
Generators implement the iterator protocol, so:
next()
on themStopIteration
when doneBut not all iterators are generators โ for example, class-based iterators.
๋ณธ ํ๊ธฐ๋ [ํ๊ธ๊ณผ์ปดํจํฐxํ๊ตญ์์ฐ์ฑ๋ณธ๋ถx์ค๋์ดํผํฉํ ๋ฆฌ] ํ์ปด AI ์์นด๋ฐ๋ฏธ (B-log) ๋ฆฌ๋ทฐ๋ก ์์ฑ ๋์์ต๋๋ค.
#ํ์ปดAI์์นด๋ฐ๋ฏธ #AI๊ฐ๋ฐ์ #AI๊ฐ๋ฐ์๊ต์ก #ํ๊ธ๊ณผ์ปดํจํฐ #ํ๊ตญ์์ฐ์ฑ๋ณธ๋ถ #์ค๋์ดํผํฉํ ๋ฆฌ #๋ถํธ์บ ํ #AI์ ๋ฌธ๊ฐ์์ฑ #๊ฐ๋ฐ์๊ต์ก #๊ฐ๋ฐ์์ทจ์