[{"data":1,"prerenderedAt":70},["ShallowReactive",2],{"qa-\u002Fpython\u002Fiteration\u002Fgenerators":3},{"page":4,"siblings":54,"blog":67},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"related":45,"seo":46,"seoDescription":47,"stem":48,"subtopic":49,"topic":50,"topicSlug":51,"updated":52,"__hash__":53},"qa\u002Fpython\u002Fiteration\u002Fgenerators.md","Generators",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","Python","python",{},true,1,"\u002Fpython\u002Fiteration\u002Fgenerators",[23,28,32,36,40],{"id":24,"difficulty":25,"q":26,"a":27},"what-is-generator","easy","What is a generator and what does the yield keyword do?","A **generator** is a function that produces a **lazy sequence** of values one at\na time. Any function containing **`yield`** becomes a generator function: calling\nit doesn't run the body — it returns a **generator object** (an iterator). Each\ntime you call `next()` (or iterate), the body runs until the next `yield`, hands\nback that value, and **pauses**, preserving all local state.\n\n```python\ndef counter():\n    print(\"start\")\n    yield 1\n    yield 2          # execution pauses here between next() calls\n    yield 3\n\ng = counter()        # nothing printed yet — body hasn't run\nnext(g)              # prints \"start\", returns 1\nnext(g)              # returns 2 (resumes after first yield)\n```\n\nWhen the function returns (or falls off the end), a **`StopIteration`** is\nraised to signal exhaustion. Generators are the simplest way to write a custom\n**iterator** without manually implementing `__iter__`\u002F`__next__`.\n",{"id":29,"difficulty":14,"q":30,"a":31},"generator-vs-list-memory","How does a generator save memory compared to a list?","A list **materializes every element in memory at once**, so its footprint grows\nwith the number of items. A generator holds only its **current state** and\ncomputes each value **on demand**, so its memory use is roughly **constant**\nregardless of how many values it ultimately yields.\n\n```python\nimport sys\nnums = [n * n for n in range(1_000_000)]   # ~8 MB list, built eagerly\ngen  = (n * n for n in range(1_000_000))   # lazy — tiny, fixed size\n\nsys.getsizeof(nums)   # large\nsys.getsizeof(gen)    # ~100 bytes, regardless of range\n```\n\nThis makes generators ideal for **large or streaming data** — reading a\nmulti-gigabyte file line by line, or a pipeline of transformations — where you'd\nnever want the whole dataset in RAM. The trade-off: you can only iterate a\ngenerator **once**, and you can't index or `len()` it.\n",{"id":33,"difficulty":14,"q":34,"a":35},"genexp-vs-listcomp","What is the difference between a generator expression and a list comprehension?","They share syntax but differ in their brackets and behaviour. A **list\ncomprehension** uses `[...]` and builds the **entire list eagerly**. A\n**generator expression** uses `(...)` and produces a **lazy iterator** that\nyields values one at a time, computing nothing until consumed.\n\n```python\nlc = [x * 2 for x in range(5)]   # [0, 2, 4, 6, 8] — built now\nge = (x * 2 for x in range(5))   # \u003Cgenerator object> — built on demand\n\n# parentheses are optional when it's the sole argument:\ntotal = sum(x * 2 for x in range(5))   # streams — no temp list\n```\n\nPrefer a **generator expression** when feeding an aggregator like `sum`, `max`,\n`any`, or `join` over a large source — it avoids creating a throwaway list. Use a\n**list comprehension** when you need the full result repeatedly, want to index\nit, or need `len()`.\n",{"id":37,"difficulty":14,"q":38,"a":39},"yield-from","What does yield from do?","**`yield from \u003Citerable>`** **delegates** to a sub-iterator: it yields every\nvalue from the iterable as if you'd written a loop of `yield`s, but also\ntransparently forwards **`send`**, **`throw`**, and the sub-generator's\n**return value**. It's the clean way to **compose** or **flatten** generators.\n\n```python\ndef chain(*iterables):\n    for it in iterables:\n        yield from it          # vs: for x in it: yield x\n\nlist(chain([1, 2], (3, 4)))    # [1, 2, 3, 4]\n\ndef sub():\n    yield 1\n    return 99                  # captured by the delegator\ndef main():\n    result = yield from sub()  # result == 99\n```\n\nBeyond saving a loop, `yield from` is what makes generator **delegation** and\ncoroutine composition possible. Rule of thumb: use it whenever you want one\ngenerator to **fully drain another**.\n",{"id":41,"difficulty":42,"q":43,"a":44},"infinite-generators","hard","How can a generator be infinite, and why doesn't it hang?","Because generators are **lazy**, the body only advances when a value is\nrequested — so an **unbounded loop** is fine: it never tries to produce all\nvalues at once. You control termination from the **consumer** side, by stopping\niteration whenever you've taken enough.\n\n```python\ndef naturals():\n    n = 0\n    while True:        # infinite — but harmless\n        yield n\n        n += 1\n\nfrom itertools import islice\nlist(islice(naturals(), 5))   # [0, 1, 2, 3, 4] — take just 5\n```\n\nThis underpins `itertools.count`, `cycle`, and `repeat`, and lets you model\nstreams elegantly. The danger is forgetting to bound the consumer:\n`list(naturals())` or `for x in naturals(): print(x)` **will** run forever — pair\ninfinite generators with `islice`, a `break`, or `takewhile`.\n",null,{"description":11},"Python interview questions on generators and yield, lazy evaluation, generator expressions vs list comprehensions, yield from, and infinite generators.","python\u002Fiteration\u002Fgenerators","Generators & yield","Comprehensions & Iteration","iteration","2026-06-18","8cOk8zKE2hYNCWFPkpf54--NW0VVil4L10uT-XTtKR0",[55,56,59,63],{"subtopic":49,"path":21,"order":20},{"subtopic":57,"path":58,"order":12},"List, Dict & Set Comprehensions","\u002Fpython\u002Fiteration\u002Fcomprehensions",{"subtopic":60,"path":61,"order":62},"Iterators & the Iterator Protocol","\u002Fpython\u002Fiteration\u002Fiterators",3,{"subtopic":64,"path":65,"order":66},"enumerate, zip & Unpacking","\u002Fpython\u002Fiteration\u002Fenumerate-zip",4,{"path":68,"title":69},"\u002Fblog\u002Fpython-generators-yield-explained","Python Generators and yield Explained — Lazy Iteration and Memory",1781808676443]