Python Error Handling, Generator โІ Iterator

nara_leeยท2025๋…„ 5์›” 7์ผ
1
post-thumbnail

Python expects try to be immediately followed by except, finally, or else, not by other statements.

โŒ Your Code:

try:
    x = 1 / 0
print("testing whether this will be printed or not")
except ZeroDivisionError:
    print("Can't divide by zero.")

๐Ÿงจ What happens?

This code will raise a SyntaxError โ€” specifically:

SyntaxError: expected 'except' or 'finally' block

Because:

  • The line print("testing...") is outside the try block.
  • Python expects try to be immediately followed by except, finally, or else, not by other statements.

FastAPIโ€™s dependency system and Python internals

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"]}

โœ… 1. Why is 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:

๐Ÿ” FastAPIโ€™s execution flow:

@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 the finally is part of the teardown step, after your route finishes responding.


๐Ÿ”ง Analogy: Itโ€™s like a with block

with 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).


โœ… 2. What is a generator in Python?

๐Ÿ‘‰ Definition:

A generator is a special type of function that:

  • uses yield instead of return
  • can pause and resume execution
  • produces values lazily, one at a time

๐Ÿงช Example:

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 last yield.


๐Ÿ” Key features of generators:

FeatureDescription
yieldTemporarily returns a value and pauses the function
next()Resumes execution until next yield
finallyRuns when generator is closed or exhausted
StopIterationRaised when no more yield left

โœ… In FastAPI:

  • yield is used in dependencies to open a resource, and
  • finally is used to clean up the resource after the response

โœ… 3. Generator vs. Iterator

FeatureGeneratorIterator
What is it?A type of iterator built using yieldA general interface with __iter__ and __next__
How to create?With a function using yieldBy defining a class with __iter__ and __next__
Memory usageEfficient โ€” lazy (one item at a time)Can be lazy or not, depends on implementation
SyntaxShort and elegantVerbose โ€” boilerplate required
State handlingHandled automatically by PythonYou 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:


โœ… TL;DR

FeatureGeneratorIterator
What is it?A type of iterator built using yieldA general interface with __iter__ and __next__
How to create?With a function using yieldBy defining a class with __iter__ and __next__
Memory usageEfficient โ€” lazy (one item at a time)Can be lazy or not, depends on implementation
SyntaxShort and elegantVerbose โ€” boilerplate required
State handlingHandled automatically by PythonYou manage state manually
One-time use?Yes (can't restart once exhausted)Usually yes, unless re-implemented

โœ… What is an iterator?

An object is an iterator if it implements:

  • __iter__() โ†’ returns the iterator object itself
  • __next__() โ†’ returns the next value, or raises StopIteration

๐Ÿงช Example:

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

โœ… What is a generator?

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.

๐Ÿงช Same behavior as above with generator:

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.


โœ… Generators are Iterators

This is important:

gen = (x for x in range(3))
print(iter(gen) is gen)  # โœ… True

Generators implement the iterator protocol, so:

  • you can call next() on them
  • they raise StopIteration when done

But not all iterators are generators โ€” for example, class-based iterators.


๋ณธ ํ›„๊ธฐ๋Š” [ํ•œ๊ธ€๊ณผ์ปดํ“จํ„ฐxํ•œ๊ตญ์ƒ์‚ฐ์„ฑ๋ณธ๋ถ€x์Šค๋‚˜์ดํผํŒฉํ† ๋ฆฌ] ํ•œ์ปด AI ์•„์นด๋ฐ๋ฏธ (B-log) ๋ฆฌ๋ทฐ๋กœ ์ž‘์„ฑ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

#ํ•œ์ปดAI์•„์นด๋ฐ๋ฏธ #AI๊ฐœ๋ฐœ์ž #AI๊ฐœ๋ฐœ์ž๊ต์œก #ํ•œ๊ธ€๊ณผ์ปดํ“จํ„ฐ #ํ•œ๊ตญ์ƒ์‚ฐ์„ฑ๋ณธ๋ถ€ #์Šค๋‚˜์ดํผํŒฉํ† ๋ฆฌ #๋ถ€ํŠธ์บ ํ”„ #AI์ „๋ฌธ๊ฐ€์–‘์„ฑ #๊ฐœ๋ฐœ์ž๊ต์œก #๊ฐœ๋ฐœ์ž์ทจ์—…

0๊ฐœ์˜ ๋Œ“๊ธ€