[{"data":1,"prerenderedAt":3905},["ShallowReactive",2],{"page-\u002Fpython\u002F09-comprehensions-and-generators":3},{"id":4,"title":5,"body":6,"description":27,"extension":3899,"meta":3900,"navigation":57,"path":3901,"seo":3902,"stem":3903,"__hash__":3904},"content\u002Fpython\u002F09-comprehensions-and-generators.md","09 — Comprehensions & Generators",{"type":7,"value":8,"toc":3876},"minimark",[9,13,18,574,962,966,1270,1284,1291,1304,1472,1475,1480,1587,1590,1664,1671,1765,1781,1918,1922,2033,2039,2286,2293,2728,2736,2905,2909,3055,3062,3075,3232,3253,3257,3361,3365,3479,3483,3486,3680,3816,3820,3872],[10,11,5],"h1",{"id":12},"_09-comprehensions-generators",[14,15,17],"h2",{"id":16},"production-data-pipeline-lazy-evaluation-end-to-end","Production Data Pipeline — Lazy Evaluation End-to-End",[19,20,22],"code-wrapper",{"language":21},"python",[23,24,28],"pre",{"className":25,"code":26,"language":21,"meta":27,"style":27},"language-python shiki shiki-themes github-light github-dark","# ── A production-grade log processing pipeline ──\n# Each stage is a generator — no intermediate lists, O(1) memory regardless of file size.\n# This pattern processes multi-GB log files with constant memory.\n\nimport re\nfrom collections.abc import Iterator\n\n# Stage 1: lazy line reader — yields one line at a time, never loads the whole file\ndef read_lines(path: str) -> Iterator[str]:\n    \"\"\"Yield lines from a file — the `open` file object IS a line iterator.\"\"\"\n    with open(path, encoding=\"utf-8\", errors=\"replace\") as f:\n        yield from f   # delegates to the file's own __iter__ — zero boilerplate\n\n# Stage 2: filter — only lines matching a regex (still lazy, one at a time)\nLOG_RE = re.compile(r\"(\\d{4}-\\d{2}-\\d{2}) \\[(\\w+)\\] (.+)\")\ndef parse_entries(lines: Iterator[str]) -> Iterator[tuple[str, str, str]]:\n    \"\"\"Parse log lines into (date, level, message) tuples — skips unparseable lines.\"\"\"\n    for line in lines:\n        if match := LOG_RE.match(line.strip()):\n            yield match.groups()   # walrus: assign + test in one expression\n\n# Stage 3: transform — extract structured data from parsed entries\ndef errors_only(entries: Iterator) -> Iterator[dict]:\n    \"\"\"Filter to ERROR level, yield structured dicts.\"\"\"\n    for date, level, message in entries:\n        if level == \"ERROR\":\n            yield {\"date\": date, \"message\": message, \"length\": len(message)}\n\n# Stage 4: aggregate — consume the pipeline, produce final result\ndef count_errors(path: str) -> dict[str, int]:\n    \"\"\"Count errors by date — the ENTIRE pipeline is consumed here, at the end.\"\"\"\n    counts: dict[str, int] = {}\n    for entry in errors_only(parse_entries(read_lines(path))):\n        counts[entry[\"date\"]] = counts.get(entry[\"date\"], 0) + 1\n    return counts\n\n# The pipeline: read_lines → parse_entries → errors_only → count_errors\n# Each stage pulls from the previous on-demand — only ONE line is in memory at any moment.\n# No intermediate list of all lines, all entries, or all errors is ever materialized.\n","",[29,30,31,40,46,52,59,70,84,89,95,120,127,169,181,186,192,262,291,297,312,330,342,347,353,369,375,388,405,437,442,448,472,478,498,511,542,551,556,562,568],"code",{"__ignoreMap":27},[32,33,36],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sdCPZ","# ── A production-grade log processing pipeline ──\n",[32,41,43],{"class":34,"line":42},2,[32,44,45],{"class":38},"# Each stage is a generator — no intermediate lists, O(1) memory regardless of file size.\n",[32,47,49],{"class":34,"line":48},3,[32,50,51],{"class":38},"# This pattern processes multi-GB log files with constant memory.\n",[32,53,55],{"class":34,"line":54},4,[32,56,58],{"emptyLinePlaceholder":57},true,"\n",[32,60,62,66],{"class":34,"line":61},5,[32,63,65],{"class":64},"svdQ7","import",[32,67,69],{"class":68},"ssxIu"," re\n",[32,71,73,76,79,81],{"class":34,"line":72},6,[32,74,75],{"class":64},"from",[32,77,78],{"class":68}," collections.abc ",[32,80,65],{"class":64},[32,82,83],{"class":68}," Iterator\n",[32,85,87],{"class":34,"line":86},7,[32,88,58],{"emptyLinePlaceholder":57},[32,90,92],{"class":34,"line":91},8,[32,93,94],{"class":38},"# Stage 1: lazy line reader — yields one line at a time, never loads the whole file\n",[32,96,98,101,105,108,112,115,117],{"class":34,"line":97},9,[32,99,100],{"class":64},"def",[32,102,104],{"class":103},"sIsaT"," read_lines",[32,106,107],{"class":68},"(path: ",[32,109,111],{"class":110},"snvgF","str",[32,113,114],{"class":68},") -> Iterator[",[32,116,111],{"class":110},[32,118,119],{"class":68},"]:\n",[32,121,123],{"class":34,"line":122},10,[32,124,126],{"class":125},"sJ6F3","    \"\"\"Yield lines from a file — the `open` file object IS a line iterator.\"\"\"\n",[32,128,130,133,136,139,143,146,149,152,155,157,160,163,166],{"class":34,"line":129},11,[32,131,132],{"class":64},"    with",[32,134,135],{"class":110}," open",[32,137,138],{"class":68},"(path, ",[32,140,142],{"class":141},"sCrzJ","encoding",[32,144,145],{"class":64},"=",[32,147,148],{"class":125},"\"utf-8\"",[32,150,151],{"class":68},", ",[32,153,154],{"class":141},"errors",[32,156,145],{"class":64},[32,158,159],{"class":125},"\"replace\"",[32,161,162],{"class":68},") ",[32,164,165],{"class":64},"as",[32,167,168],{"class":68}," f:\n",[32,170,172,175,178],{"class":34,"line":171},12,[32,173,174],{"class":64},"        yield from",[32,176,177],{"class":68}," f   ",[32,179,180],{"class":38},"# delegates to the file's own __iter__ — zero boilerplate\n",[32,182,184],{"class":34,"line":183},13,[32,185,58],{"emptyLinePlaceholder":57},[32,187,189],{"class":34,"line":188},14,[32,190,191],{"class":38},"# Stage 2: filter — only lines matching a regex (still lazy, one at a time)\n",[32,193,195,198,201,204,207,210,213,216,220,223,226,228,230,232,235,239,242,245,247,250,253,255,257,259],{"class":34,"line":194},15,[32,196,197],{"class":110},"LOG_RE",[32,199,200],{"class":64}," =",[32,202,203],{"class":68}," re.compile(",[32,205,206],{"class":64},"r",[32,208,209],{"class":125},"\"",[32,211,212],{"class":110},"(\\d",[32,214,215],{"class":64},"{4}",[32,217,219],{"class":218},"svAP2","-",[32,221,222],{"class":110},"\\d",[32,224,225],{"class":64},"{2}",[32,227,219],{"class":218},[32,229,222],{"class":110},[32,231,225],{"class":64},[32,233,234],{"class":110},")",[32,236,238],{"class":237},"snRuI"," \\[",[32,240,241],{"class":110},"(\\w",[32,243,244],{"class":64},"+",[32,246,234],{"class":110},[32,248,249],{"class":237},"\\]",[32,251,252],{"class":110}," (.",[32,254,244],{"class":64},[32,256,234],{"class":110},[32,258,209],{"class":125},[32,260,261],{"class":68},")\n",[32,263,265,267,270,273,275,278,280,282,284,286,288],{"class":34,"line":264},16,[32,266,100],{"class":64},[32,268,269],{"class":103}," parse_entries",[32,271,272],{"class":68},"(lines: Iterator[",[32,274,111],{"class":110},[32,276,277],{"class":68},"]) -> Iterator[tuple[",[32,279,111],{"class":110},[32,281,151],{"class":68},[32,283,111],{"class":110},[32,285,151],{"class":68},[32,287,111],{"class":110},[32,289,290],{"class":68},"]]:\n",[32,292,294],{"class":34,"line":293},17,[32,295,296],{"class":125},"    \"\"\"Parse log lines into (date, level, message) tuples — skips unparseable lines.\"\"\"\n",[32,298,300,303,306,309],{"class":34,"line":299},18,[32,301,302],{"class":64},"    for",[32,304,305],{"class":68}," line ",[32,307,308],{"class":64},"in",[32,310,311],{"class":68}," lines:\n",[32,313,315,318,321,324,327],{"class":34,"line":314},19,[32,316,317],{"class":64},"        if",[32,319,320],{"class":68}," match ",[32,322,323],{"class":64},":=",[32,325,326],{"class":110}," LOG_RE",[32,328,329],{"class":68},".match(line.strip()):\n",[32,331,333,336,339],{"class":34,"line":332},20,[32,334,335],{"class":64},"            yield",[32,337,338],{"class":68}," match.groups()   ",[32,340,341],{"class":38},"# walrus: assign + test in one expression\n",[32,343,345],{"class":34,"line":344},21,[32,346,58],{"emptyLinePlaceholder":57},[32,348,350],{"class":34,"line":349},22,[32,351,352],{"class":38},"# Stage 3: transform — extract structured data from parsed entries\n",[32,354,356,358,361,364,367],{"class":34,"line":355},23,[32,357,100],{"class":64},[32,359,360],{"class":103}," errors_only",[32,362,363],{"class":68},"(entries: Iterator) -> Iterator[",[32,365,366],{"class":110},"dict",[32,368,119],{"class":68},[32,370,372],{"class":34,"line":371},24,[32,373,374],{"class":125},"    \"\"\"Filter to ERROR level, yield structured dicts.\"\"\"\n",[32,376,378,380,383,385],{"class":34,"line":377},25,[32,379,302],{"class":64},[32,381,382],{"class":68}," date, level, message ",[32,384,308],{"class":64},[32,386,387],{"class":68}," entries:\n",[32,389,391,393,396,399,402],{"class":34,"line":390},26,[32,392,317],{"class":64},[32,394,395],{"class":68}," level ",[32,397,398],{"class":64},"==",[32,400,401],{"class":125}," \"ERROR\"",[32,403,404],{"class":68},":\n",[32,406,408,410,413,416,419,422,425,428,431,434],{"class":34,"line":407},27,[32,409,335],{"class":64},[32,411,412],{"class":68}," {",[32,414,415],{"class":125},"\"date\"",[32,417,418],{"class":68},": date, ",[32,420,421],{"class":125},"\"message\"",[32,423,424],{"class":68},": message, ",[32,426,427],{"class":125},"\"length\"",[32,429,430],{"class":68},": ",[32,432,433],{"class":110},"len",[32,435,436],{"class":68},"(message)}\n",[32,438,440],{"class":34,"line":439},28,[32,441,58],{"emptyLinePlaceholder":57},[32,443,445],{"class":34,"line":444},29,[32,446,447],{"class":38},"# Stage 4: aggregate — consume the pipeline, produce final result\n",[32,449,451,453,456,458,460,463,465,467,470],{"class":34,"line":450},30,[32,452,100],{"class":64},[32,454,455],{"class":103}," count_errors",[32,457,107],{"class":68},[32,459,111],{"class":110},[32,461,462],{"class":68},") -> dict[",[32,464,111],{"class":110},[32,466,151],{"class":68},[32,468,469],{"class":110},"int",[32,471,119],{"class":68},[32,473,475],{"class":34,"line":474},31,[32,476,477],{"class":125},"    \"\"\"Count errors by date — the ENTIRE pipeline is consumed here, at the end.\"\"\"\n",[32,479,481,484,486,488,490,493,495],{"class":34,"line":480},32,[32,482,483],{"class":68},"    counts: dict[",[32,485,111],{"class":110},[32,487,151],{"class":68},[32,489,469],{"class":110},[32,491,492],{"class":68},"] ",[32,494,145],{"class":64},[32,496,497],{"class":68}," {}\n",[32,499,501,503,506,508],{"class":34,"line":500},33,[32,502,302],{"class":64},[32,504,505],{"class":68}," entry ",[32,507,308],{"class":64},[32,509,510],{"class":68}," errors_only(parse_entries(read_lines(path))):\n",[32,512,514,517,519,522,524,527,529,532,535,537,539],{"class":34,"line":513},34,[32,515,516],{"class":68},"        counts[entry[",[32,518,415],{"class":125},[32,520,521],{"class":68},"]] ",[32,523,145],{"class":64},[32,525,526],{"class":68}," counts.get(entry[",[32,528,415],{"class":125},[32,530,531],{"class":68},"], ",[32,533,534],{"class":110},"0",[32,536,162],{"class":68},[32,538,244],{"class":64},[32,540,541],{"class":110}," 1\n",[32,543,545,548],{"class":34,"line":544},35,[32,546,547],{"class":64},"    return",[32,549,550],{"class":68}," counts\n",[32,552,554],{"class":34,"line":553},36,[32,555,58],{"emptyLinePlaceholder":57},[32,557,559],{"class":34,"line":558},37,[32,560,561],{"class":38},"# The pipeline: read_lines → parse_entries → errors_only → count_errors\n",[32,563,565],{"class":34,"line":564},38,[32,566,567],{"class":38},"# Each stage pulls from the previous on-demand — only ONE line is in memory at any moment.\n",[32,569,571],{"class":34,"line":570},39,[32,572,573],{"class":38},"# No intermediate list of all lines, all entries, or all errors is ever materialized.\n",[19,575,576],{"language":21},[23,577,579],{"className":25,"code":578,"language":21,"meta":27,"style":27},"# ── Generator-based coroutine: two-way communication via send() ──\n# Before async\u002Fawait, generators were Python's coroutine primitive.\n# send() pushes a value INTO the generator at the yield point — still useful\n# for stateful streaming parsers and co-routine-style data pumps.\n\ndef streaming_average():\n    \"\"\"Consume values via .send(), yields the running average after each input.\n    The FIRST .send() must be None (or use next() to prime) — there's no yield\n    expression yet to receive a value at the start.\"\"\"\n    total = 0\n    count = 0\n    average = None\n    while True:\n        # yield returns the current average to the caller\n        # .send(value) resumes here, assigning `value` to the left side\n        value = yield average\n        total += value\n        count += 1\n        average = total \u002F count\n\n# Prime the coroutine — advance to the first yield before sending\ncoro = streaming_average()\nnext(coro)              # prime: advances to `value = yield average`, returns None\nprint(coro.send(10))    # 10.0 — total=10, count=1\nprint(coro.send(20))    # 15.0 — total=30, count=2\nprint(coro.send(30))    # 20.0 — total=60, count=3\n\n# ── Generator exhaustion: the silent failure mode ──\n# ANTI-PATTERN: reusing a generator across multiple consumption passes\ngen = (x * 2 for x in range(5))\nprint(sum(gen))   # 0+2+4+6+8 = 20\nprint(sum(gen))   # 0! — exhausted, silently produces 0, NOT an error\n\n# CORRECT: materialize to a list if multiple passes are needed\ndata = [x * 2 for x in range(5)]   # list — reusable, indexable, len()-able\nprint(sum(data))   # 20\nprint(sum(data))   # 20 — still works\nprint(len(data))   # 5 — generators have no len()\n",[29,580,581,586,591,596,601,605,615,620,625,630,640,649,659,669,674,679,692,703,712,728,732,737,747,758,775,789,803,807,812,817,853,868,881,885,890,922,936,949],{"__ignoreMap":27},[32,582,583],{"class":34,"line":35},[32,584,585],{"class":38},"# ── Generator-based coroutine: two-way communication via send() ──\n",[32,587,588],{"class":34,"line":42},[32,589,590],{"class":38},"# Before async\u002Fawait, generators were Python's coroutine primitive.\n",[32,592,593],{"class":34,"line":48},[32,594,595],{"class":38},"# send() pushes a value INTO the generator at the yield point — still useful\n",[32,597,598],{"class":34,"line":54},[32,599,600],{"class":38},"# for stateful streaming parsers and co-routine-style data pumps.\n",[32,602,603],{"class":34,"line":61},[32,604,58],{"emptyLinePlaceholder":57},[32,606,607,609,612],{"class":34,"line":72},[32,608,100],{"class":64},[32,610,611],{"class":103}," streaming_average",[32,613,614],{"class":68},"():\n",[32,616,617],{"class":34,"line":86},[32,618,619],{"class":125},"    \"\"\"Consume values via .send(), yields the running average after each input.\n",[32,621,622],{"class":34,"line":91},[32,623,624],{"class":125},"    The FIRST .send() must be None (or use next() to prime) — there's no yield\n",[32,626,627],{"class":34,"line":97},[32,628,629],{"class":125},"    expression yet to receive a value at the start.\"\"\"\n",[32,631,632,635,637],{"class":34,"line":122},[32,633,634],{"class":68},"    total ",[32,636,145],{"class":64},[32,638,639],{"class":110}," 0\n",[32,641,642,645,647],{"class":34,"line":129},[32,643,644],{"class":68},"    count ",[32,646,145],{"class":64},[32,648,639],{"class":110},[32,650,651,654,656],{"class":34,"line":171},[32,652,653],{"class":68},"    average ",[32,655,145],{"class":64},[32,657,658],{"class":110}," None\n",[32,660,661,664,667],{"class":34,"line":183},[32,662,663],{"class":64},"    while",[32,665,666],{"class":110}," True",[32,668,404],{"class":68},[32,670,671],{"class":34,"line":188},[32,672,673],{"class":38},"        # yield returns the current average to the caller\n",[32,675,676],{"class":34,"line":194},[32,677,678],{"class":38},"        # .send(value) resumes here, assigning `value` to the left side\n",[32,680,681,684,686,689],{"class":34,"line":264},[32,682,683],{"class":68},"        value ",[32,685,145],{"class":64},[32,687,688],{"class":64}," yield",[32,690,691],{"class":68}," average\n",[32,693,694,697,700],{"class":34,"line":293},[32,695,696],{"class":68},"        total ",[32,698,699],{"class":64},"+=",[32,701,702],{"class":68}," value\n",[32,704,705,708,710],{"class":34,"line":299},[32,706,707],{"class":68},"        count ",[32,709,699],{"class":64},[32,711,541],{"class":110},[32,713,714,717,719,722,725],{"class":34,"line":314},[32,715,716],{"class":68},"        average ",[32,718,145],{"class":64},[32,720,721],{"class":68}," total ",[32,723,724],{"class":64},"\u002F",[32,726,727],{"class":68}," count\n",[32,729,730],{"class":34,"line":332},[32,731,58],{"emptyLinePlaceholder":57},[32,733,734],{"class":34,"line":344},[32,735,736],{"class":38},"# Prime the coroutine — advance to the first yield before sending\n",[32,738,739,742,744],{"class":34,"line":349},[32,740,741],{"class":68},"coro ",[32,743,145],{"class":64},[32,745,746],{"class":68}," streaming_average()\n",[32,748,749,752,755],{"class":34,"line":355},[32,750,751],{"class":110},"next",[32,753,754],{"class":68},"(coro)              ",[32,756,757],{"class":38},"# prime: advances to `value = yield average`, returns None\n",[32,759,760,763,766,769,772],{"class":34,"line":371},[32,761,762],{"class":110},"print",[32,764,765],{"class":68},"(coro.send(",[32,767,768],{"class":110},"10",[32,770,771],{"class":68},"))    ",[32,773,774],{"class":38},"# 10.0 — total=10, count=1\n",[32,776,777,779,781,784,786],{"class":34,"line":377},[32,778,762],{"class":110},[32,780,765],{"class":68},[32,782,783],{"class":110},"20",[32,785,771],{"class":68},[32,787,788],{"class":38},"# 15.0 — total=30, count=2\n",[32,790,791,793,795,798,800],{"class":34,"line":390},[32,792,762],{"class":110},[32,794,765],{"class":68},[32,796,797],{"class":110},"30",[32,799,771],{"class":68},[32,801,802],{"class":38},"# 20.0 — total=60, count=3\n",[32,804,805],{"class":34,"line":407},[32,806,58],{"emptyLinePlaceholder":57},[32,808,809],{"class":34,"line":439},[32,810,811],{"class":38},"# ── Generator exhaustion: the silent failure mode ──\n",[32,813,814],{"class":34,"line":444},[32,815,816],{"class":38},"# ANTI-PATTERN: reusing a generator across multiple consumption passes\n",[32,818,819,822,824,827,830,833,836,839,841,844,847,850],{"class":34,"line":450},[32,820,821],{"class":68},"gen ",[32,823,145],{"class":64},[32,825,826],{"class":68}," (x ",[32,828,829],{"class":64},"*",[32,831,832],{"class":110}," 2",[32,834,835],{"class":64}," for",[32,837,838],{"class":68}," x ",[32,840,308],{"class":64},[32,842,843],{"class":110}," range",[32,845,846],{"class":68},"(",[32,848,849],{"class":110},"5",[32,851,852],{"class":68},"))\n",[32,854,855,857,859,862,865],{"class":34,"line":474},[32,856,762],{"class":110},[32,858,846],{"class":68},[32,860,861],{"class":110},"sum",[32,863,864],{"class":68},"(gen))   ",[32,866,867],{"class":38},"# 0+2+4+6+8 = 20\n",[32,869,870,872,874,876,878],{"class":34,"line":480},[32,871,762],{"class":110},[32,873,846],{"class":68},[32,875,861],{"class":110},[32,877,864],{"class":68},[32,879,880],{"class":38},"# 0! — exhausted, silently produces 0, NOT an error\n",[32,882,883],{"class":34,"line":500},[32,884,58],{"emptyLinePlaceholder":57},[32,886,887],{"class":34,"line":513},[32,888,889],{"class":38},"# CORRECT: materialize to a list if multiple passes are needed\n",[32,891,892,895,897,900,902,904,906,908,910,912,914,916,919],{"class":34,"line":544},[32,893,894],{"class":68},"data ",[32,896,145],{"class":64},[32,898,899],{"class":68}," [x ",[32,901,829],{"class":64},[32,903,832],{"class":110},[32,905,835],{"class":64},[32,907,838],{"class":68},[32,909,308],{"class":64},[32,911,843],{"class":110},[32,913,846],{"class":68},[32,915,849],{"class":110},[32,917,918],{"class":68},")]   ",[32,920,921],{"class":38},"# list — reusable, indexable, len()-able\n",[32,923,924,926,928,930,933],{"class":34,"line":553},[32,925,762],{"class":110},[32,927,846],{"class":68},[32,929,861],{"class":110},[32,931,932],{"class":68},"(data))   ",[32,934,935],{"class":38},"# 20\n",[32,937,938,940,942,944,946],{"class":34,"line":558},[32,939,762],{"class":110},[32,941,846],{"class":68},[32,943,861],{"class":110},[32,945,932],{"class":68},[32,947,948],{"class":38},"# 20 — still works\n",[32,950,951,953,955,957,959],{"class":34,"line":564},[32,952,762],{"class":110},[32,954,846],{"class":68},[32,956,433],{"class":110},[32,958,932],{"class":68},[32,960,961],{"class":38},"# 5 — generators have no len()\n",[14,963,965],{"id":964},"nested-comprehensions-and-multiple-clauses","Nested Comprehensions and Multiple Clauses",[19,967,968],{"language":21},[23,969,971],{"className":25,"code":970,"language":21,"meta":27,"style":27},"# Multiple `for` clauses — equivalent to nested loops, left-to-right\npairs = [(x, y) for x in range(3) for y in range(2)]\nprint(pairs)   # [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]\n\n# Equivalent nested-loop form, for comparison:\npairs_manual = []\nfor x in range(3):\n    for y in range(2):\n        pairs_manual.append((x, y))\nassert pairs == pairs_manual\n\n# Multiple `if` clauses — combined with implicit AND\nfiltered = [x for x in range(50) if x % 2 == 0 if x % 3 == 0]\nprint(filtered)   # [0, 6, 12, 18, 24, 30, 36, 42, 48] — divisible by BOTH 2 and 3\n\n# A truly nested comprehension (comprehension INSIDE a comprehension)\nmatrix = [[1, 2, 3], [4, 5, 6]]\ntransposed = [[row[i] for row in matrix] for i in range(3)]\nprint(transposed)   # [[1, 4], [2, 5], [3, 6]]\n",[29,972,973,978,1021,1031,1035,1040,1050,1067,1083,1088,1101,1105,1110,1167,1177,1181,1186,1225,1260],{"__ignoreMap":27},[32,974,975],{"class":34,"line":35},[32,976,977],{"class":38},"# Multiple `for` clauses — equivalent to nested loops, left-to-right\n",[32,979,980,983,985,988,991,993,995,997,999,1002,1004,1006,1009,1011,1013,1015,1018],{"class":34,"line":42},[32,981,982],{"class":68},"pairs ",[32,984,145],{"class":64},[32,986,987],{"class":68}," [(x, y) ",[32,989,990],{"class":64},"for",[32,992,838],{"class":68},[32,994,308],{"class":64},[32,996,843],{"class":110},[32,998,846],{"class":68},[32,1000,1001],{"class":110},"3",[32,1003,162],{"class":68},[32,1005,990],{"class":64},[32,1007,1008],{"class":68}," y ",[32,1010,308],{"class":64},[32,1012,843],{"class":110},[32,1014,846],{"class":68},[32,1016,1017],{"class":110},"2",[32,1019,1020],{"class":68},")]\n",[32,1022,1023,1025,1028],{"class":34,"line":48},[32,1024,762],{"class":110},[32,1026,1027],{"class":68},"(pairs)   ",[32,1029,1030],{"class":38},"# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]\n",[32,1032,1033],{"class":34,"line":54},[32,1034,58],{"emptyLinePlaceholder":57},[32,1036,1037],{"class":34,"line":61},[32,1038,1039],{"class":38},"# Equivalent nested-loop form, for comparison:\n",[32,1041,1042,1045,1047],{"class":34,"line":72},[32,1043,1044],{"class":68},"pairs_manual ",[32,1046,145],{"class":64},[32,1048,1049],{"class":68}," []\n",[32,1051,1052,1054,1056,1058,1060,1062,1064],{"class":34,"line":86},[32,1053,990],{"class":64},[32,1055,838],{"class":68},[32,1057,308],{"class":64},[32,1059,843],{"class":110},[32,1061,846],{"class":68},[32,1063,1001],{"class":110},[32,1065,1066],{"class":68},"):\n",[32,1068,1069,1071,1073,1075,1077,1079,1081],{"class":34,"line":91},[32,1070,302],{"class":64},[32,1072,1008],{"class":68},[32,1074,308],{"class":64},[32,1076,843],{"class":110},[32,1078,846],{"class":68},[32,1080,1017],{"class":110},[32,1082,1066],{"class":68},[32,1084,1085],{"class":34,"line":97},[32,1086,1087],{"class":68},"        pairs_manual.append((x, y))\n",[32,1089,1090,1093,1096,1098],{"class":34,"line":122},[32,1091,1092],{"class":64},"assert",[32,1094,1095],{"class":68}," pairs ",[32,1097,398],{"class":64},[32,1099,1100],{"class":68}," pairs_manual\n",[32,1102,1103],{"class":34,"line":129},[32,1104,58],{"emptyLinePlaceholder":57},[32,1106,1107],{"class":34,"line":171},[32,1108,1109],{"class":38},"# Multiple `if` clauses — combined with implicit AND\n",[32,1111,1112,1115,1117,1119,1121,1123,1125,1127,1129,1132,1134,1137,1139,1142,1144,1147,1150,1153,1155,1157,1160,1162,1164],{"class":34,"line":183},[32,1113,1114],{"class":68},"filtered ",[32,1116,145],{"class":64},[32,1118,899],{"class":68},[32,1120,990],{"class":64},[32,1122,838],{"class":68},[32,1124,308],{"class":64},[32,1126,843],{"class":110},[32,1128,846],{"class":68},[32,1130,1131],{"class":110},"50",[32,1133,162],{"class":68},[32,1135,1136],{"class":64},"if",[32,1138,838],{"class":68},[32,1140,1141],{"class":64},"%",[32,1143,832],{"class":110},[32,1145,1146],{"class":64}," ==",[32,1148,1149],{"class":110}," 0",[32,1151,1152],{"class":64}," if",[32,1154,838],{"class":68},[32,1156,1141],{"class":64},[32,1158,1159],{"class":110}," 3",[32,1161,1146],{"class":64},[32,1163,1149],{"class":110},[32,1165,1166],{"class":68},"]\n",[32,1168,1169,1171,1174],{"class":34,"line":188},[32,1170,762],{"class":110},[32,1172,1173],{"class":68},"(filtered)   ",[32,1175,1176],{"class":38},"# [0, 6, 12, 18, 24, 30, 36, 42, 48] — divisible by BOTH 2 and 3\n",[32,1178,1179],{"class":34,"line":194},[32,1180,58],{"emptyLinePlaceholder":57},[32,1182,1183],{"class":34,"line":264},[32,1184,1185],{"class":38},"# A truly nested comprehension (comprehension INSIDE a comprehension)\n",[32,1187,1188,1191,1193,1196,1199,1201,1203,1205,1207,1210,1213,1215,1217,1219,1222],{"class":34,"line":293},[32,1189,1190],{"class":68},"matrix ",[32,1192,145],{"class":64},[32,1194,1195],{"class":68}," [[",[32,1197,1198],{"class":110},"1",[32,1200,151],{"class":68},[32,1202,1017],{"class":110},[32,1204,151],{"class":68},[32,1206,1001],{"class":110},[32,1208,1209],{"class":68},"], [",[32,1211,1212],{"class":110},"4",[32,1214,151],{"class":68},[32,1216,849],{"class":110},[32,1218,151],{"class":68},[32,1220,1221],{"class":110},"6",[32,1223,1224],{"class":68},"]]\n",[32,1226,1227,1230,1232,1235,1237,1240,1242,1245,1247,1250,1252,1254,1256,1258],{"class":34,"line":299},[32,1228,1229],{"class":68},"transposed ",[32,1231,145],{"class":64},[32,1233,1234],{"class":68}," [[row[i] ",[32,1236,990],{"class":64},[32,1238,1239],{"class":68}," row ",[32,1241,308],{"class":64},[32,1243,1244],{"class":68}," matrix] ",[32,1246,990],{"class":64},[32,1248,1249],{"class":68}," i ",[32,1251,308],{"class":64},[32,1253,843],{"class":110},[32,1255,846],{"class":68},[32,1257,1001],{"class":110},[32,1259,1020],{"class":68},[32,1261,1262,1264,1267],{"class":34,"line":314},[32,1263,762],{"class":110},[32,1265,1266],{"class":68},"(transposed)   ",[32,1268,1269],{"class":38},"# [[1, 4], [2, 5], [3, 6]]\n",[1271,1272,1273,1277,1278,1280,1281,1283],"p",{},[1274,1275,1276],"strong",{},"Best practice",": comprehensions with more than 2 ",[29,1279,990],{}," clauses or nested conditionals rapidly become unreadable — at that point, a plain ",[29,1282,990],{}," loop (or breaking into a named helper function) is more maintainable than cramming logic into one expression. Comprehensions are for clarity, not for code-golf.",[14,1285,1287,1288],{"id":1286},"generator-functions-and-yield","Generator Functions and ",[29,1289,1290],{},"yield",[1271,1292,1293,1294,1296,1297,1300,1301,1303],{},"A function containing ",[29,1295,1290],{}," becomes a ",[1274,1298,1299],{},"generator function"," — calling it doesn't run the body; it returns a generator object. Execution happens lazily, one ",[29,1302,1290],{}," at a time, pausing and resuming state between calls.",[19,1305,1306],{"language":21},[23,1307,1309],{"className":25,"code":1308,"language":21,"meta":27,"style":27},"def count_up_to(n):\n    print(\"starting\")\n    i = 1\n    while i \u003C= n:\n        yield i          # pauses here, returns i, resumes on next()\n        i += 1\n    print(\"finished\")\n\ngen = count_up_to(3)\nprint(gen)                 # \u003Cgenerator object count_up_to at 0x...> — NOTHING printed yet!\n\nprint(next(gen))             # prints \"starting\", then returns 1\nprint(next(gen))               # returns 2 (resumes right after the yield)\nprint(next(gen))                 # returns 3\nprint(next(gen))                   # prints \"finished\", then raises StopIteration\n",[29,1310,1311,1321,1333,1342,1354,1365,1374,1385,1389,1402,1412,1416,1430,1444,1458],{"__ignoreMap":27},[32,1312,1313,1315,1318],{"class":34,"line":35},[32,1314,100],{"class":64},[32,1316,1317],{"class":103}," count_up_to",[32,1319,1320],{"class":68},"(n):\n",[32,1322,1323,1326,1328,1331],{"class":34,"line":42},[32,1324,1325],{"class":110},"    print",[32,1327,846],{"class":68},[32,1329,1330],{"class":125},"\"starting\"",[32,1332,261],{"class":68},[32,1334,1335,1338,1340],{"class":34,"line":48},[32,1336,1337],{"class":68},"    i ",[32,1339,145],{"class":64},[32,1341,541],{"class":110},[32,1343,1344,1346,1348,1351],{"class":34,"line":54},[32,1345,663],{"class":64},[32,1347,1249],{"class":68},[32,1349,1350],{"class":64},"\u003C=",[32,1352,1353],{"class":68}," n:\n",[32,1355,1356,1359,1362],{"class":34,"line":61},[32,1357,1358],{"class":64},"        yield",[32,1360,1361],{"class":68}," i          ",[32,1363,1364],{"class":38},"# pauses here, returns i, resumes on next()\n",[32,1366,1367,1370,1372],{"class":34,"line":72},[32,1368,1369],{"class":68},"        i ",[32,1371,699],{"class":64},[32,1373,541],{"class":110},[32,1375,1376,1378,1380,1383],{"class":34,"line":86},[32,1377,1325],{"class":110},[32,1379,846],{"class":68},[32,1381,1382],{"class":125},"\"finished\"",[32,1384,261],{"class":68},[32,1386,1387],{"class":34,"line":91},[32,1388,58],{"emptyLinePlaceholder":57},[32,1390,1391,1393,1395,1398,1400],{"class":34,"line":97},[32,1392,821],{"class":68},[32,1394,145],{"class":64},[32,1396,1397],{"class":68}," count_up_to(",[32,1399,1001],{"class":110},[32,1401,261],{"class":68},[32,1403,1404,1406,1409],{"class":34,"line":122},[32,1405,762],{"class":110},[32,1407,1408],{"class":68},"(gen)                 ",[32,1410,1411],{"class":38},"# \u003Cgenerator object count_up_to at 0x...> — NOTHING printed yet!\n",[32,1413,1414],{"class":34,"line":129},[32,1415,58],{"emptyLinePlaceholder":57},[32,1417,1418,1420,1422,1424,1427],{"class":34,"line":171},[32,1419,762],{"class":110},[32,1421,846],{"class":68},[32,1423,751],{"class":110},[32,1425,1426],{"class":68},"(gen))             ",[32,1428,1429],{"class":38},"# prints \"starting\", then returns 1\n",[32,1431,1432,1434,1436,1438,1441],{"class":34,"line":183},[32,1433,762],{"class":110},[32,1435,846],{"class":68},[32,1437,751],{"class":110},[32,1439,1440],{"class":68},"(gen))               ",[32,1442,1443],{"class":38},"# returns 2 (resumes right after the yield)\n",[32,1445,1446,1448,1450,1452,1455],{"class":34,"line":188},[32,1447,762],{"class":110},[32,1449,846],{"class":68},[32,1451,751],{"class":110},[32,1453,1454],{"class":68},"(gen))                 ",[32,1456,1457],{"class":38},"# returns 3\n",[32,1459,1460,1462,1464,1466,1469],{"class":34,"line":194},[32,1461,762],{"class":110},[32,1463,846],{"class":68},[32,1465,751],{"class":110},[32,1467,1468],{"class":68},"(gen))                   ",[32,1470,1471],{"class":38},"# prints \"finished\", then raises StopIteration\n",[1271,1473,1474],{},"This lazy, resumable execution is fundamentally different from a normal function, which runs top-to-bottom in one shot and has no persistent state between calls.",[1476,1477,1479],"h3",{"id":1478},"real-world-use-processing-data-too-large-to-fit-in-memory","Real-world use: processing data too large to fit in memory",[19,1481,1482],{"language":21},[23,1483,1485],{"className":25,"code":1484,"language":21,"meta":27,"style":27},"def read_large_log(path):\n    \"\"\"Yield one parsed line at a time — never loads the whole file into memory.\"\"\"\n    with open(path, encoding=\"utf-8\") as f:\n        for line in f:\n            if \"ERROR\" in line:\n                yield line.strip()\n\n# Even a 50GB log file works fine — only one line is in memory at a time\nfor error_line in read_large_log(\"app.log\"):\n    print(error_line)\n",[29,1486,1487,1497,1502,1522,1533,1546,1554,1558,1563,1580],{"__ignoreMap":27},[32,1488,1489,1491,1494],{"class":34,"line":35},[32,1490,100],{"class":64},[32,1492,1493],{"class":103}," read_large_log",[32,1495,1496],{"class":68},"(path):\n",[32,1498,1499],{"class":34,"line":42},[32,1500,1501],{"class":125},"    \"\"\"Yield one parsed line at a time — never loads the whole file into memory.\"\"\"\n",[32,1503,1504,1506,1508,1510,1512,1514,1516,1518,1520],{"class":34,"line":48},[32,1505,132],{"class":64},[32,1507,135],{"class":110},[32,1509,138],{"class":68},[32,1511,142],{"class":141},[32,1513,145],{"class":64},[32,1515,148],{"class":125},[32,1517,162],{"class":68},[32,1519,165],{"class":64},[32,1521,168],{"class":68},[32,1523,1524,1527,1529,1531],{"class":34,"line":54},[32,1525,1526],{"class":64},"        for",[32,1528,305],{"class":68},[32,1530,308],{"class":64},[32,1532,168],{"class":68},[32,1534,1535,1538,1540,1543],{"class":34,"line":61},[32,1536,1537],{"class":64},"            if",[32,1539,401],{"class":125},[32,1541,1542],{"class":64}," in",[32,1544,1545],{"class":68}," line:\n",[32,1547,1548,1551],{"class":34,"line":72},[32,1549,1550],{"class":64},"                yield",[32,1552,1553],{"class":68}," line.strip()\n",[32,1555,1556],{"class":34,"line":86},[32,1557,58],{"emptyLinePlaceholder":57},[32,1559,1560],{"class":34,"line":91},[32,1561,1562],{"class":38},"# Even a 50GB log file works fine — only one line is in memory at a time\n",[32,1564,1565,1567,1570,1572,1575,1578],{"class":34,"line":97},[32,1566,990],{"class":64},[32,1568,1569],{"class":68}," error_line ",[32,1571,308],{"class":64},[32,1573,1574],{"class":68}," read_large_log(",[32,1576,1577],{"class":125},"\"app.log\"",[32,1579,1066],{"class":68},[32,1581,1582,1584],{"class":34,"line":122},[32,1583,1325],{"class":110},[32,1585,1586],{"class":68},"(error_line)\n",[1271,1588,1589],{},"Compare to the eager alternative, which would load the entire file into a list before processing anything:",[19,1591,1592],{"language":21},[23,1593,1595],{"className":25,"code":1594,"language":21,"meta":27,"style":27},"def read_large_log_eager(path):\n    with open(path, encoding=\"utf-8\") as f:\n        lines = f.readlines()          # ENTIRE file in memory at once\n    return [line.strip() for line in lines if \"ERROR\" in line]\n",[29,1596,1597,1606,1626,1639],{"__ignoreMap":27},[32,1598,1599,1601,1604],{"class":34,"line":35},[32,1600,100],{"class":64},[32,1602,1603],{"class":103}," read_large_log_eager",[32,1605,1496],{"class":68},[32,1607,1608,1610,1612,1614,1616,1618,1620,1622,1624],{"class":34,"line":42},[32,1609,132],{"class":64},[32,1611,135],{"class":110},[32,1613,138],{"class":68},[32,1615,142],{"class":141},[32,1617,145],{"class":64},[32,1619,148],{"class":125},[32,1621,162],{"class":68},[32,1623,165],{"class":64},[32,1625,168],{"class":68},[32,1627,1628,1631,1633,1636],{"class":34,"line":48},[32,1629,1630],{"class":68},"        lines ",[32,1632,145],{"class":64},[32,1634,1635],{"class":68}," f.readlines()          ",[32,1637,1638],{"class":38},"# ENTIRE file in memory at once\n",[32,1640,1641,1643,1646,1648,1650,1652,1655,1657,1659,1661],{"class":34,"line":54},[32,1642,547],{"class":64},[32,1644,1645],{"class":68}," [line.strip() ",[32,1647,990],{"class":64},[32,1649,305],{"class":68},[32,1651,308],{"class":64},[32,1653,1654],{"class":68}," lines ",[32,1656,1136],{"class":64},[32,1658,401],{"class":125},[32,1660,1542],{"class":64},[32,1662,1663],{"class":68}," line]\n",[14,1665,1667,1670],{"id":1666},"yield-from-delegating-to-a-sub-generator",[29,1668,1669],{},"yield from"," — Delegating to a Sub-Generator",[19,1672,1673],{"language":21},[23,1674,1676],{"className":25,"code":1675,"language":21,"meta":27,"style":27},"def inner():\n    yield 1\n    yield 2\n    yield 3\n\ndef outer():\n    yield \"start\"\n    yield from inner()     # delegates — yields 1, 2, 3 as if outer produced them directly\n    yield \"end\"\n\nprint(list(outer()))   # ['start', 1, 2, 3, 'end']\n",[29,1677,1678,1687,1694,1701,1708,1712,1721,1728,1739,1746,1750],{"__ignoreMap":27},[32,1679,1680,1682,1685],{"class":34,"line":35},[32,1681,100],{"class":64},[32,1683,1684],{"class":103}," inner",[32,1686,614],{"class":68},[32,1688,1689,1692],{"class":34,"line":42},[32,1690,1691],{"class":64},"    yield",[32,1693,541],{"class":110},[32,1695,1696,1698],{"class":34,"line":48},[32,1697,1691],{"class":64},[32,1699,1700],{"class":110}," 2\n",[32,1702,1703,1705],{"class":34,"line":54},[32,1704,1691],{"class":64},[32,1706,1707],{"class":110}," 3\n",[32,1709,1710],{"class":34,"line":61},[32,1711,58],{"emptyLinePlaceholder":57},[32,1713,1714,1716,1719],{"class":34,"line":72},[32,1715,100],{"class":64},[32,1717,1718],{"class":103}," outer",[32,1720,614],{"class":68},[32,1722,1723,1725],{"class":34,"line":86},[32,1724,1691],{"class":64},[32,1726,1727],{"class":125}," \"start\"\n",[32,1729,1730,1733,1736],{"class":34,"line":91},[32,1731,1732],{"class":64},"    yield from",[32,1734,1735],{"class":68}," inner()     ",[32,1737,1738],{"class":38},"# delegates — yields 1, 2, 3 as if outer produced them directly\n",[32,1740,1741,1743],{"class":34,"line":97},[32,1742,1691],{"class":64},[32,1744,1745],{"class":125}," \"end\"\n",[32,1747,1748],{"class":34,"line":122},[32,1749,58],{"emptyLinePlaceholder":57},[32,1751,1752,1754,1756,1759,1762],{"class":34,"line":129},[32,1753,762],{"class":110},[32,1755,846],{"class":68},[32,1757,1758],{"class":110},"list",[32,1760,1761],{"class":68},"(outer()))   ",[32,1763,1764],{"class":38},"# ['start', 1, 2, 3, 'end']\n",[1271,1766,1767,1769,1770,151,1773,1776,1777,1780],{},[29,1768,1669],{}," is more than sugar for a manual loop — it also correctly forwards ",[29,1771,1772],{},".send()",[29,1774,1775],{},".throw()",", and the sub-generator's return value, which a naive ",[29,1778,1779],{},"for x in inner(): yield x"," does not.",[19,1782,1783],{"language":21},[23,1784,1786],{"className":25,"code":1785,"language":21,"meta":27,"style":27},"def flatten(nested):\n    for item in nested:\n        if isinstance(item, list):\n            yield from flatten(item)    # recursive delegation\n        else:\n            yield item\n\ndata = [1, [2, 3, [4, 5]], 6, [7, [8, [9]]]]\nprint(list(flatten(data)))   # [1, 2, 3, 4, 5, 6, 7, 8, 9]\n",[29,1787,1788,1798,1810,1824,1835,1842,1849,1853,1904],{"__ignoreMap":27},[32,1789,1790,1792,1795],{"class":34,"line":35},[32,1791,100],{"class":64},[32,1793,1794],{"class":103}," flatten",[32,1796,1797],{"class":68},"(nested):\n",[32,1799,1800,1802,1805,1807],{"class":34,"line":42},[32,1801,302],{"class":64},[32,1803,1804],{"class":68}," item ",[32,1806,308],{"class":64},[32,1808,1809],{"class":68}," nested:\n",[32,1811,1812,1814,1817,1820,1822],{"class":34,"line":48},[32,1813,317],{"class":64},[32,1815,1816],{"class":110}," isinstance",[32,1818,1819],{"class":68},"(item, ",[32,1821,1758],{"class":110},[32,1823,1066],{"class":68},[32,1825,1826,1829,1832],{"class":34,"line":54},[32,1827,1828],{"class":64},"            yield from",[32,1830,1831],{"class":68}," flatten(item)    ",[32,1833,1834],{"class":38},"# recursive delegation\n",[32,1836,1837,1840],{"class":34,"line":61},[32,1838,1839],{"class":64},"        else",[32,1841,404],{"class":68},[32,1843,1844,1846],{"class":34,"line":72},[32,1845,335],{"class":64},[32,1847,1848],{"class":68}," item\n",[32,1850,1851],{"class":34,"line":86},[32,1852,58],{"emptyLinePlaceholder":57},[32,1854,1855,1857,1859,1862,1864,1867,1869,1871,1873,1875,1877,1879,1881,1884,1886,1888,1891,1893,1896,1898,1901],{"class":34,"line":91},[32,1856,894],{"class":68},[32,1858,145],{"class":64},[32,1860,1861],{"class":68}," [",[32,1863,1198],{"class":110},[32,1865,1866],{"class":68},", [",[32,1868,1017],{"class":110},[32,1870,151],{"class":68},[32,1872,1001],{"class":110},[32,1874,1866],{"class":68},[32,1876,1212],{"class":110},[32,1878,151],{"class":68},[32,1880,849],{"class":110},[32,1882,1883],{"class":68},"]], ",[32,1885,1221],{"class":110},[32,1887,1866],{"class":68},[32,1889,1890],{"class":110},"7",[32,1892,1866],{"class":68},[32,1894,1895],{"class":110},"8",[32,1897,1866],{"class":68},[32,1899,1900],{"class":110},"9",[32,1902,1903],{"class":68},"]]]]\n",[32,1905,1906,1908,1910,1912,1915],{"class":34,"line":97},[32,1907,762],{"class":110},[32,1909,846],{"class":68},[32,1911,1758],{"class":110},[32,1913,1914],{"class":68},"(flatten(data)))   ",[32,1916,1917],{"class":38},"# [1, 2, 3, 4, 5, 6, 7, 8, 9]\n",[14,1919,1921],{"id":1920},"generators-are-single-use-the-trap","Generators Are Single-Use — The Trap",[19,1923,1924],{"language":21},[23,1925,1927],{"className":25,"code":1926,"language":21,"meta":27,"style":27},"def get_evens(n):\n    for i in range(n):\n        if i % 2 == 0:\n            yield i\n\nevens = get_evens(10)\nprint(sum(evens))     # 20  (0+2+4+6+8)\nprint(sum(evens))       # 0  — ALREADY EXHAUSTED! Not an error, just silently empty.\nprint(list(evens))        # []\n",[29,1928,1929,1938,1950,1966,1973,1977,1991,2005,2019],{"__ignoreMap":27},[32,1930,1931,1933,1936],{"class":34,"line":35},[32,1932,100],{"class":64},[32,1934,1935],{"class":103}," get_evens",[32,1937,1320],{"class":68},[32,1939,1940,1942,1944,1946,1948],{"class":34,"line":42},[32,1941,302],{"class":64},[32,1943,1249],{"class":68},[32,1945,308],{"class":64},[32,1947,843],{"class":110},[32,1949,1320],{"class":68},[32,1951,1952,1954,1956,1958,1960,1962,1964],{"class":34,"line":48},[32,1953,317],{"class":64},[32,1955,1249],{"class":68},[32,1957,1141],{"class":64},[32,1959,832],{"class":110},[32,1961,1146],{"class":64},[32,1963,1149],{"class":110},[32,1965,404],{"class":68},[32,1967,1968,1970],{"class":34,"line":54},[32,1969,335],{"class":64},[32,1971,1972],{"class":68}," i\n",[32,1974,1975],{"class":34,"line":61},[32,1976,58],{"emptyLinePlaceholder":57},[32,1978,1979,1982,1984,1987,1989],{"class":34,"line":72},[32,1980,1981],{"class":68},"evens ",[32,1983,145],{"class":64},[32,1985,1986],{"class":68}," get_evens(",[32,1988,768],{"class":110},[32,1990,261],{"class":68},[32,1992,1993,1995,1997,1999,2002],{"class":34,"line":86},[32,1994,762],{"class":110},[32,1996,846],{"class":68},[32,1998,861],{"class":110},[32,2000,2001],{"class":68},"(evens))     ",[32,2003,2004],{"class":38},"# 20  (0+2+4+6+8)\n",[32,2006,2007,2009,2011,2013,2016],{"class":34,"line":91},[32,2008,762],{"class":110},[32,2010,846],{"class":68},[32,2012,861],{"class":110},[32,2014,2015],{"class":68},"(evens))       ",[32,2017,2018],{"class":38},"# 0  — ALREADY EXHAUSTED! Not an error, just silently empty.\n",[32,2020,2021,2023,2025,2027,2030],{"class":34,"line":97},[32,2022,762],{"class":110},[32,2024,846],{"class":68},[32,2026,1758],{"class":110},[32,2028,2029],{"class":68},"(evens))        ",[32,2031,2032],{"class":38},"# []\n",[1271,2034,2035,2038],{},[1274,2036,2037],{},"This is a genuinely dangerous trap",": iterating an exhausted generator raises no error and no warning — it simply produces zero items, silently. Code that assumes a generator can be iterated multiple times (like a list) will not crash; it will quietly compute wrong results (sums of zero, empty result sets) that can slip through code review and testing if the test only checks the first consumption.",[19,2040,2041],{"language":21},[23,2042,2044],{"className":25,"code":2043,"language":21,"meta":27,"style":27},"# WRONG — reuses a generator expression across two consumptions\ndef process(data):\n    filtered = (x for x in data if x > 0)\n    total = sum(filtered)\n    count = sum(1 for _ in filtered)   # filtered is ALREADY exhausted — count is always 0!\n    return total, count\n\nprint(process([1, -2, 3, -4, 5]))   # (9, 0)  — count is wrong!\n\n# RIGHT — materialize once if you need multiple passes, or recompute\ndef process_fixed(data):\n    filtered = [x for x in data if x > 0]   # a LIST — reusable\n    total = sum(filtered)\n    count = len(filtered)\n    return total, count\n\nprint(process_fixed([1, -2, 3, -4, 5]))   # (9, 3) — correct\n",[29,2045,2046,2051,2061,2090,2102,2127,2134,2138,2173,2177,2182,2191,2221,2231,2242,2248,2252],{"__ignoreMap":27},[32,2047,2048],{"class":34,"line":35},[32,2049,2050],{"class":38},"# WRONG — reuses a generator expression across two consumptions\n",[32,2052,2053,2055,2058],{"class":34,"line":42},[32,2054,100],{"class":64},[32,2056,2057],{"class":103}," process",[32,2059,2060],{"class":68},"(data):\n",[32,2062,2063,2066,2068,2070,2072,2074,2076,2079,2081,2083,2086,2088],{"class":34,"line":48},[32,2064,2065],{"class":68},"    filtered ",[32,2067,145],{"class":64},[32,2069,826],{"class":68},[32,2071,990],{"class":64},[32,2073,838],{"class":68},[32,2075,308],{"class":64},[32,2077,2078],{"class":68}," data ",[32,2080,1136],{"class":64},[32,2082,838],{"class":68},[32,2084,2085],{"class":64},">",[32,2087,1149],{"class":110},[32,2089,261],{"class":68},[32,2091,2092,2094,2096,2099],{"class":34,"line":54},[32,2093,634],{"class":68},[32,2095,145],{"class":64},[32,2097,2098],{"class":110}," sum",[32,2100,2101],{"class":68},"(filtered)\n",[32,2103,2104,2106,2108,2110,2112,2114,2116,2119,2121,2124],{"class":34,"line":61},[32,2105,644],{"class":68},[32,2107,145],{"class":64},[32,2109,2098],{"class":110},[32,2111,846],{"class":68},[32,2113,1198],{"class":110},[32,2115,835],{"class":64},[32,2117,2118],{"class":68}," _ ",[32,2120,308],{"class":64},[32,2122,2123],{"class":68}," filtered)   ",[32,2125,2126],{"class":38},"# filtered is ALREADY exhausted — count is always 0!\n",[32,2128,2129,2131],{"class":34,"line":72},[32,2130,547],{"class":64},[32,2132,2133],{"class":68}," total, count\n",[32,2135,2136],{"class":34,"line":86},[32,2137,58],{"emptyLinePlaceholder":57},[32,2139,2140,2142,2145,2147,2149,2151,2153,2155,2157,2159,2161,2163,2165,2167,2170],{"class":34,"line":91},[32,2141,762],{"class":110},[32,2143,2144],{"class":68},"(process([",[32,2146,1198],{"class":110},[32,2148,151],{"class":68},[32,2150,219],{"class":64},[32,2152,1017],{"class":110},[32,2154,151],{"class":68},[32,2156,1001],{"class":110},[32,2158,151],{"class":68},[32,2160,219],{"class":64},[32,2162,1212],{"class":110},[32,2164,151],{"class":68},[32,2166,849],{"class":110},[32,2168,2169],{"class":68},"]))   ",[32,2171,2172],{"class":38},"# (9, 0)  — count is wrong!\n",[32,2174,2175],{"class":34,"line":97},[32,2176,58],{"emptyLinePlaceholder":57},[32,2178,2179],{"class":34,"line":122},[32,2180,2181],{"class":38},"# RIGHT — materialize once if you need multiple passes, or recompute\n",[32,2183,2184,2186,2189],{"class":34,"line":129},[32,2185,100],{"class":64},[32,2187,2188],{"class":103}," process_fixed",[32,2190,2060],{"class":68},[32,2192,2193,2195,2197,2199,2201,2203,2205,2207,2209,2211,2213,2215,2218],{"class":34,"line":171},[32,2194,2065],{"class":68},[32,2196,145],{"class":64},[32,2198,899],{"class":68},[32,2200,990],{"class":64},[32,2202,838],{"class":68},[32,2204,308],{"class":64},[32,2206,2078],{"class":68},[32,2208,1136],{"class":64},[32,2210,838],{"class":68},[32,2212,2085],{"class":64},[32,2214,1149],{"class":110},[32,2216,2217],{"class":68},"]   ",[32,2219,2220],{"class":38},"# a LIST — reusable\n",[32,2222,2223,2225,2227,2229],{"class":34,"line":183},[32,2224,634],{"class":68},[32,2226,145],{"class":64},[32,2228,2098],{"class":110},[32,2230,2101],{"class":68},[32,2232,2233,2235,2237,2240],{"class":34,"line":188},[32,2234,644],{"class":68},[32,2236,145],{"class":64},[32,2238,2239],{"class":110}," len",[32,2241,2101],{"class":68},[32,2243,2244,2246],{"class":34,"line":194},[32,2245,547],{"class":64},[32,2247,2133],{"class":68},[32,2249,2250],{"class":34,"line":264},[32,2251,58],{"emptyLinePlaceholder":57},[32,2253,2254,2256,2259,2261,2263,2265,2267,2269,2271,2273,2275,2277,2279,2281,2283],{"class":34,"line":293},[32,2255,762],{"class":110},[32,2257,2258],{"class":68},"(process_fixed([",[32,2260,1198],{"class":110},[32,2262,151],{"class":68},[32,2264,219],{"class":64},[32,2266,1017],{"class":110},[32,2268,151],{"class":68},[32,2270,1001],{"class":110},[32,2272,151],{"class":68},[32,2274,219],{"class":64},[32,2276,1212],{"class":110},[32,2278,151],{"class":68},[32,2280,849],{"class":110},[32,2282,2169],{"class":68},[32,2284,2285],{"class":38},"# (9, 3) — correct\n",[14,2287,2289,2292],{"id":2288},"itertools-the-standard-librarys-generator-toolkit",[29,2290,2291],{},"itertools"," — The Standard Library's Generator Toolkit",[19,2294,2295],{"language":21},[23,2296,2298],{"className":25,"code":2297,"language":21,"meta":27,"style":27},"import itertools\n\n# chain — iterate multiple iterables as one, without concatenating them\nfor x in itertools.chain([1, 2], [3, 4], [5]):\n    print(x, end=\" \")   # 1 2 3 4 5\nprint()\n\n# islice — slice a generator\u002Fiterator (regular slicing doesn't work on generators!)\ngen = (x ** 2 for x in range(100))\nfirst_five = list(itertools.islice(gen, 5))\nprint(first_five)   # [0, 1, 4, 9, 16]\n\n# groupby — group CONSECUTIVE equal elements (requires pre-sorted input!)\ndata = [(\"fruit\", \"apple\"), (\"fruit\", \"banana\"), (\"veg\", \"carrot\")]\nfor key, group in itertools.groupby(data, key=lambda x: x[0]):\n    print(key, list(group))\n# fruit [('fruit', 'apple'), ('fruit', 'banana')]\n# veg [('veg', 'carrot')]\n\n# product — cartesian product, replaces nested for loops\nfor combo in itertools.product([1, 2], [\"a\", \"b\"]):\n    print(combo, end=\" \")   # (1, 'a') (1, 'b') (2, 'a') (2, 'b')\nprint()\n\n# permutations \u002F combinations\nprint(list(itertools.permutations([1, 2, 3], 2)))\n# [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]\nprint(list(itertools.combinations([1, 2, 3], 2)))\n# [(1, 2), (1, 3), (2, 3)]\n\n# count, cycle, repeat — INFINITE iterators, always pair with islice\u002Fbreak\u002Fzip\ncounter = itertools.count(start=10, step=5)\nprint(list(itertools.islice(counter, 4)))   # [10, 15, 20, 25]\n",[29,2299,2300,2307,2311,2316,2348,2369,2376,2380,2385,2413,2430,2440,2444,2449,2488,2513,2525,2530,2535,2539,2544,2574,2592,2598,2602,2607,2635,2640,2667,2672,2676,2681,2709],{"__ignoreMap":27},[32,2301,2302,2304],{"class":34,"line":35},[32,2303,65],{"class":64},[32,2305,2306],{"class":68}," itertools\n",[32,2308,2309],{"class":34,"line":42},[32,2310,58],{"emptyLinePlaceholder":57},[32,2312,2313],{"class":34,"line":48},[32,2314,2315],{"class":38},"# chain — iterate multiple iterables as one, without concatenating them\n",[32,2317,2318,2320,2322,2324,2327,2329,2331,2333,2335,2337,2339,2341,2343,2345],{"class":34,"line":54},[32,2319,990],{"class":64},[32,2321,838],{"class":68},[32,2323,308],{"class":64},[32,2325,2326],{"class":68}," itertools.chain([",[32,2328,1198],{"class":110},[32,2330,151],{"class":68},[32,2332,1017],{"class":110},[32,2334,1209],{"class":68},[32,2336,1001],{"class":110},[32,2338,151],{"class":68},[32,2340,1212],{"class":110},[32,2342,1209],{"class":68},[32,2344,849],{"class":110},[32,2346,2347],{"class":68},"]):\n",[32,2349,2350,2352,2355,2358,2360,2363,2366],{"class":34,"line":61},[32,2351,1325],{"class":110},[32,2353,2354],{"class":68},"(x, ",[32,2356,2357],{"class":141},"end",[32,2359,145],{"class":64},[32,2361,2362],{"class":125},"\" \"",[32,2364,2365],{"class":68},")   ",[32,2367,2368],{"class":38},"# 1 2 3 4 5\n",[32,2370,2371,2373],{"class":34,"line":72},[32,2372,762],{"class":110},[32,2374,2375],{"class":68},"()\n",[32,2377,2378],{"class":34,"line":86},[32,2379,58],{"emptyLinePlaceholder":57},[32,2381,2382],{"class":34,"line":91},[32,2383,2384],{"class":38},"# islice — slice a generator\u002Fiterator (regular slicing doesn't work on generators!)\n",[32,2386,2387,2389,2391,2393,2396,2398,2400,2402,2404,2406,2408,2411],{"class":34,"line":97},[32,2388,821],{"class":68},[32,2390,145],{"class":64},[32,2392,826],{"class":68},[32,2394,2395],{"class":64},"**",[32,2397,832],{"class":110},[32,2399,835],{"class":64},[32,2401,838],{"class":68},[32,2403,308],{"class":64},[32,2405,843],{"class":110},[32,2407,846],{"class":68},[32,2409,2410],{"class":110},"100",[32,2412,852],{"class":68},[32,2414,2415,2418,2420,2423,2426,2428],{"class":34,"line":122},[32,2416,2417],{"class":68},"first_five ",[32,2419,145],{"class":64},[32,2421,2422],{"class":110}," list",[32,2424,2425],{"class":68},"(itertools.islice(gen, ",[32,2427,849],{"class":110},[32,2429,852],{"class":68},[32,2431,2432,2434,2437],{"class":34,"line":129},[32,2433,762],{"class":110},[32,2435,2436],{"class":68},"(first_five)   ",[32,2438,2439],{"class":38},"# [0, 1, 4, 9, 16]\n",[32,2441,2442],{"class":34,"line":171},[32,2443,58],{"emptyLinePlaceholder":57},[32,2445,2446],{"class":34,"line":183},[32,2447,2448],{"class":38},"# groupby — group CONSECUTIVE equal elements (requires pre-sorted input!)\n",[32,2450,2451,2453,2455,2458,2461,2463,2466,2469,2471,2473,2476,2478,2481,2483,2486],{"class":34,"line":188},[32,2452,894],{"class":68},[32,2454,145],{"class":64},[32,2456,2457],{"class":68}," [(",[32,2459,2460],{"class":125},"\"fruit\"",[32,2462,151],{"class":68},[32,2464,2465],{"class":125},"\"apple\"",[32,2467,2468],{"class":68},"), (",[32,2470,2460],{"class":125},[32,2472,151],{"class":68},[32,2474,2475],{"class":125},"\"banana\"",[32,2477,2468],{"class":68},[32,2479,2480],{"class":125},"\"veg\"",[32,2482,151],{"class":68},[32,2484,2485],{"class":125},"\"carrot\"",[32,2487,1020],{"class":68},[32,2489,2490,2492,2495,2497,2500,2503,2506,2509,2511],{"class":34,"line":194},[32,2491,990],{"class":64},[32,2493,2494],{"class":68}," key, group ",[32,2496,308],{"class":64},[32,2498,2499],{"class":68}," itertools.groupby(data, ",[32,2501,2502],{"class":141},"key",[32,2504,2505],{"class":64},"=lambda",[32,2507,2508],{"class":68}," x: x[",[32,2510,534],{"class":110},[32,2512,2347],{"class":68},[32,2514,2515,2517,2520,2522],{"class":34,"line":264},[32,2516,1325],{"class":110},[32,2518,2519],{"class":68},"(key, ",[32,2521,1758],{"class":110},[32,2523,2524],{"class":68},"(group))\n",[32,2526,2527],{"class":34,"line":293},[32,2528,2529],{"class":38},"# fruit [('fruit', 'apple'), ('fruit', 'banana')]\n",[32,2531,2532],{"class":34,"line":299},[32,2533,2534],{"class":38},"# veg [('veg', 'carrot')]\n",[32,2536,2537],{"class":34,"line":314},[32,2538,58],{"emptyLinePlaceholder":57},[32,2540,2541],{"class":34,"line":332},[32,2542,2543],{"class":38},"# product — cartesian product, replaces nested for loops\n",[32,2545,2546,2548,2551,2553,2556,2558,2560,2562,2564,2567,2569,2572],{"class":34,"line":344},[32,2547,990],{"class":64},[32,2549,2550],{"class":68}," combo ",[32,2552,308],{"class":64},[32,2554,2555],{"class":68}," itertools.product([",[32,2557,1198],{"class":110},[32,2559,151],{"class":68},[32,2561,1017],{"class":110},[32,2563,1209],{"class":68},[32,2565,2566],{"class":125},"\"a\"",[32,2568,151],{"class":68},[32,2570,2571],{"class":125},"\"b\"",[32,2573,2347],{"class":68},[32,2575,2576,2578,2581,2583,2585,2587,2589],{"class":34,"line":349},[32,2577,1325],{"class":110},[32,2579,2580],{"class":68},"(combo, ",[32,2582,2357],{"class":141},[32,2584,145],{"class":64},[32,2586,2362],{"class":125},[32,2588,2365],{"class":68},[32,2590,2591],{"class":38},"# (1, 'a') (1, 'b') (2, 'a') (2, 'b')\n",[32,2593,2594,2596],{"class":34,"line":355},[32,2595,762],{"class":110},[32,2597,2375],{"class":68},[32,2599,2600],{"class":34,"line":371},[32,2601,58],{"emptyLinePlaceholder":57},[32,2603,2604],{"class":34,"line":377},[32,2605,2606],{"class":38},"# permutations \u002F combinations\n",[32,2608,2609,2611,2613,2615,2618,2620,2622,2624,2626,2628,2630,2632],{"class":34,"line":390},[32,2610,762],{"class":110},[32,2612,846],{"class":68},[32,2614,1758],{"class":110},[32,2616,2617],{"class":68},"(itertools.permutations([",[32,2619,1198],{"class":110},[32,2621,151],{"class":68},[32,2623,1017],{"class":110},[32,2625,151],{"class":68},[32,2627,1001],{"class":110},[32,2629,531],{"class":68},[32,2631,1017],{"class":110},[32,2633,2634],{"class":68},")))\n",[32,2636,2637],{"class":34,"line":407},[32,2638,2639],{"class":38},"# [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]\n",[32,2641,2642,2644,2646,2648,2651,2653,2655,2657,2659,2661,2663,2665],{"class":34,"line":439},[32,2643,762],{"class":110},[32,2645,846],{"class":68},[32,2647,1758],{"class":110},[32,2649,2650],{"class":68},"(itertools.combinations([",[32,2652,1198],{"class":110},[32,2654,151],{"class":68},[32,2656,1017],{"class":110},[32,2658,151],{"class":68},[32,2660,1001],{"class":110},[32,2662,531],{"class":68},[32,2664,1017],{"class":110},[32,2666,2634],{"class":68},[32,2668,2669],{"class":34,"line":444},[32,2670,2671],{"class":38},"# [(1, 2), (1, 3), (2, 3)]\n",[32,2673,2674],{"class":34,"line":450},[32,2675,58],{"emptyLinePlaceholder":57},[32,2677,2678],{"class":34,"line":474},[32,2679,2680],{"class":38},"# count, cycle, repeat — INFINITE iterators, always pair with islice\u002Fbreak\u002Fzip\n",[32,2682,2683,2686,2688,2691,2694,2696,2698,2700,2703,2705,2707],{"class":34,"line":480},[32,2684,2685],{"class":68},"counter ",[32,2687,145],{"class":64},[32,2689,2690],{"class":68}," itertools.count(",[32,2692,2693],{"class":141},"start",[32,2695,145],{"class":64},[32,2697,768],{"class":110},[32,2699,151],{"class":68},[32,2701,2702],{"class":141},"step",[32,2704,145],{"class":64},[32,2706,849],{"class":110},[32,2708,261],{"class":68},[32,2710,2711,2713,2715,2717,2720,2722,2725],{"class":34,"line":500},[32,2712,762],{"class":110},[32,2714,846],{"class":68},[32,2716,1758],{"class":110},[32,2718,2719],{"class":68},"(itertools.islice(counter, ",[32,2721,1212],{"class":110},[32,2723,2724],{"class":68},")))   ",[32,2726,2727],{"class":38},"# [10, 15, 20, 25]\n",[1476,2729,2731,2732,2735],{"id":2730},"the-groupby-gotcha-it-only-groups-adjacent-elements","The ",[29,2733,2734],{},"groupby"," gotcha: it only groups adjacent elements",[19,2737,2738],{"language":21},[23,2739,2741],{"className":25,"code":2740,"language":21,"meta":27,"style":27},"import itertools\n\n# WRONG assumption: groupby groups ALL matching elements, like SQL GROUP BY\ndata = [\"apple\", \"banana\", \"avocado\", \"blueberry\"]   # NOT sorted by first letter!\nfor key, group in itertools.groupby(data, key=lambda w: w[0]):\n    print(key, list(group))\n# a ['apple']\n# b ['banana']\n# a ['avocado']       \u003C- a NEW \"a\" group, because it's not adjacent to the first!\n# b ['blueberry']\n\n# RIGHT — sort first if you want true \"all items with this key\" grouping\nfor key, group in itertools.groupby(sorted(data, key=lambda w: w[0]), key=lambda w: w[0]):\n    print(key, list(group))\n# a ['apple', 'avocado']\n# b ['banana', 'blueberry']\n",[29,2742,2743,2749,2753,2758,2787,2808,2818,2823,2828,2833,2838,2842,2847,2885,2895,2900],{"__ignoreMap":27},[32,2744,2745,2747],{"class":34,"line":35},[32,2746,65],{"class":64},[32,2748,2306],{"class":68},[32,2750,2751],{"class":34,"line":42},[32,2752,58],{"emptyLinePlaceholder":57},[32,2754,2755],{"class":34,"line":48},[32,2756,2757],{"class":38},"# WRONG assumption: groupby groups ALL matching elements, like SQL GROUP BY\n",[32,2759,2760,2762,2764,2766,2768,2770,2772,2774,2777,2779,2782,2784],{"class":34,"line":54},[32,2761,894],{"class":68},[32,2763,145],{"class":64},[32,2765,1861],{"class":68},[32,2767,2465],{"class":125},[32,2769,151],{"class":68},[32,2771,2475],{"class":125},[32,2773,151],{"class":68},[32,2775,2776],{"class":125},"\"avocado\"",[32,2778,151],{"class":68},[32,2780,2781],{"class":125},"\"blueberry\"",[32,2783,2217],{"class":68},[32,2785,2786],{"class":38},"# NOT sorted by first letter!\n",[32,2788,2789,2791,2793,2795,2797,2799,2801,2804,2806],{"class":34,"line":61},[32,2790,990],{"class":64},[32,2792,2494],{"class":68},[32,2794,308],{"class":64},[32,2796,2499],{"class":68},[32,2798,2502],{"class":141},[32,2800,2505],{"class":64},[32,2802,2803],{"class":68}," w: w[",[32,2805,534],{"class":110},[32,2807,2347],{"class":68},[32,2809,2810,2812,2814,2816],{"class":34,"line":72},[32,2811,1325],{"class":110},[32,2813,2519],{"class":68},[32,2815,1758],{"class":110},[32,2817,2524],{"class":68},[32,2819,2820],{"class":34,"line":86},[32,2821,2822],{"class":38},"# a ['apple']\n",[32,2824,2825],{"class":34,"line":91},[32,2826,2827],{"class":38},"# b ['banana']\n",[32,2829,2830],{"class":34,"line":97},[32,2831,2832],{"class":38},"# a ['avocado']       \u003C- a NEW \"a\" group, because it's not adjacent to the first!\n",[32,2834,2835],{"class":34,"line":122},[32,2836,2837],{"class":38},"# b ['blueberry']\n",[32,2839,2840],{"class":34,"line":129},[32,2841,58],{"emptyLinePlaceholder":57},[32,2843,2844],{"class":34,"line":171},[32,2845,2846],{"class":38},"# RIGHT — sort first if you want true \"all items with this key\" grouping\n",[32,2848,2849,2851,2853,2855,2858,2861,2864,2866,2868,2870,2872,2875,2877,2879,2881,2883],{"class":34,"line":183},[32,2850,990],{"class":64},[32,2852,2494],{"class":68},[32,2854,308],{"class":64},[32,2856,2857],{"class":68}," itertools.groupby(",[32,2859,2860],{"class":110},"sorted",[32,2862,2863],{"class":68},"(data, ",[32,2865,2502],{"class":141},[32,2867,2505],{"class":64},[32,2869,2803],{"class":68},[32,2871,534],{"class":110},[32,2873,2874],{"class":68},"]), ",[32,2876,2502],{"class":141},[32,2878,2505],{"class":64},[32,2880,2803],{"class":68},[32,2882,534],{"class":110},[32,2884,2347],{"class":68},[32,2886,2887,2889,2891,2893],{"class":34,"line":188},[32,2888,1325],{"class":110},[32,2890,2519],{"class":68},[32,2892,1758],{"class":110},[32,2894,2524],{"class":68},[32,2896,2897],{"class":34,"line":194},[32,2898,2899],{"class":38},"# a ['apple', 'avocado']\n",[32,2901,2902],{"class":34,"line":264},[32,2903,2904],{"class":38},"# b ['banana', 'blueberry']\n",[14,2906,2908],{"id":2907},"generator-expressions-vs-list-comprehensions-when-to-use-which","Generator Expressions vs List Comprehensions — When to Use Which",[19,2910,2911],{"language":21},[23,2912,2914],{"className":25,"code":2913,"language":21,"meta":27,"style":27},"# When the result is consumed ONCE and immediately (sum, max, any, all, join) —\n# use a generator expression, saves memory, no intermediate list ever built\ntotal = sum(x ** 2 for x in range(1_000_000))     # note: no extra parens needed\n                                                      # when it's the sole function argument\n\n# When you need to iterate multiple times, index into it, or call len() —\n# use a list comprehension, you need the materialized container\nsquares = [x ** 2 for x in range(10)]\nprint(squares[3])       # works — lists support indexing\nprint(len(squares))       # works — lists support len()\n\n# gen = (x ** 2 for x in range(10))\n# gen[3]        # TypeError: 'generator' object is not subscriptable\n# len(gen)        # TypeError: object of type 'generator' has no len()\n",[29,2915,2916,2921,2926,2961,2966,2970,2975,2980,3007,3022,3036,3040,3045,3050],{"__ignoreMap":27},[32,2917,2918],{"class":34,"line":35},[32,2919,2920],{"class":38},"# When the result is consumed ONCE and immediately (sum, max, any, all, join) —\n",[32,2922,2923],{"class":34,"line":42},[32,2924,2925],{"class":38},"# use a generator expression, saves memory, no intermediate list ever built\n",[32,2927,2928,2931,2933,2935,2938,2940,2942,2944,2946,2948,2950,2952,2955,2958],{"class":34,"line":48},[32,2929,2930],{"class":68},"total ",[32,2932,145],{"class":64},[32,2934,2098],{"class":110},[32,2936,2937],{"class":68},"(x ",[32,2939,2395],{"class":64},[32,2941,832],{"class":110},[32,2943,835],{"class":64},[32,2945,838],{"class":68},[32,2947,308],{"class":64},[32,2949,843],{"class":110},[32,2951,846],{"class":68},[32,2953,2954],{"class":110},"1_000_000",[32,2956,2957],{"class":68},"))     ",[32,2959,2960],{"class":38},"# note: no extra parens needed\n",[32,2962,2963],{"class":34,"line":54},[32,2964,2965],{"class":38},"                                                      # when it's the sole function argument\n",[32,2967,2968],{"class":34,"line":61},[32,2969,58],{"emptyLinePlaceholder":57},[32,2971,2972],{"class":34,"line":72},[32,2973,2974],{"class":38},"# When you need to iterate multiple times, index into it, or call len() —\n",[32,2976,2977],{"class":34,"line":86},[32,2978,2979],{"class":38},"# use a list comprehension, you need the materialized container\n",[32,2981,2982,2985,2987,2989,2991,2993,2995,2997,2999,3001,3003,3005],{"class":34,"line":91},[32,2983,2984],{"class":68},"squares ",[32,2986,145],{"class":64},[32,2988,899],{"class":68},[32,2990,2395],{"class":64},[32,2992,832],{"class":110},[32,2994,835],{"class":64},[32,2996,838],{"class":68},[32,2998,308],{"class":64},[32,3000,843],{"class":110},[32,3002,846],{"class":68},[32,3004,768],{"class":110},[32,3006,1020],{"class":68},[32,3008,3009,3011,3014,3016,3019],{"class":34,"line":97},[32,3010,762],{"class":110},[32,3012,3013],{"class":68},"(squares[",[32,3015,1001],{"class":110},[32,3017,3018],{"class":68},"])       ",[32,3020,3021],{"class":38},"# works — lists support indexing\n",[32,3023,3024,3026,3028,3030,3033],{"class":34,"line":122},[32,3025,762],{"class":110},[32,3027,846],{"class":68},[32,3029,433],{"class":110},[32,3031,3032],{"class":68},"(squares))       ",[32,3034,3035],{"class":38},"# works — lists support len()\n",[32,3037,3038],{"class":34,"line":129},[32,3039,58],{"emptyLinePlaceholder":57},[32,3041,3042],{"class":34,"line":171},[32,3043,3044],{"class":38},"# gen = (x ** 2 for x in range(10))\n",[32,3046,3047],{"class":34,"line":183},[32,3048,3049],{"class":38},"# gen[3]        # TypeError: 'generator' object is not subscriptable\n",[32,3051,3052],{"class":34,"line":188},[32,3053,3054],{"class":38},"# len(gen)        # TypeError: object of type 'generator' has no len()\n",[14,3056,3058,3061],{"id":3057},"send-two-way-communication-with-generators-advanced",[29,3059,3060],{},"send()"," — Two-Way Communication with Generators (Advanced)",[1271,3063,3064,3065,3067,3068,724,3071,3074],{},"Generators can receive values, not just produce them, via ",[29,3066,1772],{},". This underpins the pre-",[29,3069,3070],{},"async",[29,3072,3073],{},"await"," coroutine style still occasionally seen in older codebases.",[19,3076,3077],{"language":21},[23,3078,3080],{"className":25,"code":3079,"language":21,"meta":27,"style":27},"def running_average():\n    total = 0\n    count = 0\n    average = None\n    while True:\n        value = yield average    # yields the CURRENT average, receives the NEXT value\n        total += value\n        count += 1\n        average = total \u002F count\n\navg_gen = running_average()\nnext(avg_gen)               # \"prime\" the generator — advances to the first yield\nprint(avg_gen.send(10))       # 10.0\nprint(avg_gen.send(20))         # 15.0\nprint(avg_gen.send(30))           # 20.0\n",[29,3081,3082,3091,3099,3107,3115,3123,3137,3145,3153,3165,3169,3179,3189,3204,3218],{"__ignoreMap":27},[32,3083,3084,3086,3089],{"class":34,"line":35},[32,3085,100],{"class":64},[32,3087,3088],{"class":103}," running_average",[32,3090,614],{"class":68},[32,3092,3093,3095,3097],{"class":34,"line":42},[32,3094,634],{"class":68},[32,3096,145],{"class":64},[32,3098,639],{"class":110},[32,3100,3101,3103,3105],{"class":34,"line":48},[32,3102,644],{"class":68},[32,3104,145],{"class":64},[32,3106,639],{"class":110},[32,3108,3109,3111,3113],{"class":34,"line":54},[32,3110,653],{"class":68},[32,3112,145],{"class":64},[32,3114,658],{"class":110},[32,3116,3117,3119,3121],{"class":34,"line":61},[32,3118,663],{"class":64},[32,3120,666],{"class":110},[32,3122,404],{"class":68},[32,3124,3125,3127,3129,3131,3134],{"class":34,"line":72},[32,3126,683],{"class":68},[32,3128,145],{"class":64},[32,3130,688],{"class":64},[32,3132,3133],{"class":68}," average    ",[32,3135,3136],{"class":38},"# yields the CURRENT average, receives the NEXT value\n",[32,3138,3139,3141,3143],{"class":34,"line":86},[32,3140,696],{"class":68},[32,3142,699],{"class":64},[32,3144,702],{"class":68},[32,3146,3147,3149,3151],{"class":34,"line":91},[32,3148,707],{"class":68},[32,3150,699],{"class":64},[32,3152,541],{"class":110},[32,3154,3155,3157,3159,3161,3163],{"class":34,"line":97},[32,3156,716],{"class":68},[32,3158,145],{"class":64},[32,3160,721],{"class":68},[32,3162,724],{"class":64},[32,3164,727],{"class":68},[32,3166,3167],{"class":34,"line":122},[32,3168,58],{"emptyLinePlaceholder":57},[32,3170,3171,3174,3176],{"class":34,"line":129},[32,3172,3173],{"class":68},"avg_gen ",[32,3175,145],{"class":64},[32,3177,3178],{"class":68}," running_average()\n",[32,3180,3181,3183,3186],{"class":34,"line":171},[32,3182,751],{"class":110},[32,3184,3185],{"class":68},"(avg_gen)               ",[32,3187,3188],{"class":38},"# \"prime\" the generator — advances to the first yield\n",[32,3190,3191,3193,3196,3198,3201],{"class":34,"line":183},[32,3192,762],{"class":110},[32,3194,3195],{"class":68},"(avg_gen.send(",[32,3197,768],{"class":110},[32,3199,3200],{"class":68},"))       ",[32,3202,3203],{"class":38},"# 10.0\n",[32,3205,3206,3208,3210,3212,3215],{"class":34,"line":188},[32,3207,762],{"class":110},[32,3209,3195],{"class":68},[32,3211,783],{"class":110},[32,3213,3214],{"class":68},"))         ",[32,3216,3217],{"class":38},"# 15.0\n",[32,3219,3220,3222,3224,3226,3229],{"class":34,"line":194},[32,3221,762],{"class":110},[32,3223,3195],{"class":68},[32,3225,797],{"class":110},[32,3227,3228],{"class":68},"))           ",[32,3230,3231],{"class":38},"# 20.0\n",[1271,3233,3234,3235,3238,3239,3242,3243,3245,3246,3249,3250,3252],{},"Generators must be ",[1274,3236,3237],{},"primed"," with an initial ",[29,3240,3241],{},"next()"," before the first ",[29,3244,1772],{}," — sending a value to a freshly-created, un-primed generator raises ",[29,3247,3248],{},"TypeError: can't send non-None value to a just-started generator",", because there's no ",[29,3251,1290],{}," expression yet waiting to receive it.",[14,3254,3256],{"id":3255},"tips-tricks","💡 Tips & Tricks",[3258,3259,3260,3281,3310,3328,3348],"ul",{},[3261,3262,3263,3272,3273,3276,3277,3280],"li",{},[1274,3264,3265,724,3268,3271],{},[29,3266,3267],{},"any()",[29,3269,3270],{},"all()"," short-circuit — pair them with generator expressions for early exit"," — ",[29,3274,3275],{},"any(x > 100 for x in huge_iterable)"," stops at the first ",[29,3278,3279],{},"True",", never materializing the rest of the sequence; using a list comprehension there would waste time and memory building results you'll immediately discard.",[3261,3282,3283,3272,3298,3301,3302,3305,3306,3309],{},[1274,3284,3285,151,3288,151,3291,151,3294,3297],{},[29,3286,3287],{},"sum()",[29,3289,3290],{},"max()",[29,3292,3293],{},"min()",[29,3295,3296],{},"sorted()"," all accept a generator expression directly, no extra parens needed as the sole argument",[29,3299,3300],{},"max(len(w) for w in words)"," is valid; you only need explicit parens ",[29,3303,3304],{},"max((len(w) for w in words), default=0)"," when passing additional arguments like ",[29,3307,3308],{},"default",".",[3261,3311,3312,3315,3316,3319,3320,3323,3324,3327],{},[1274,3313,3314],{},"Generator functions are the idiomatic way to make a class iterable"," — defining ",[29,3317,3318],{},"__iter__"," as a generator function (",[29,3321,3322],{},"def __iter__(self): yield from self._items",") is simpler than manually implementing ",[29,3325,3326],{},"__next__"," and tracking state — covered fully in chapter 14 and 19.",[3261,3329,3330,3336,3337,3340,3341,3344,3345,3309],{},[1274,3331,3332,3335],{},[29,3333,3334],{},"itertools.islice"," is how you \"slice\" an infinite or large generator"," — regular slice syntax (",[29,3338,3339],{},"gen[:5]",") doesn't work on generators; ",[29,3342,3343],{},"itertools.islice(gen, 5)"," does, and works even on infinite generators like ",[29,3346,3347],{},"itertools.count()",[3261,3349,3350,3272,3353,3356,3357,3360],{},[1274,3351,3352],{},"Generator expressions inside function calls don't need double parentheses",[29,3354,3355],{},"sum(x for x in range(10))"," not ",[29,3358,3359],{},"sum((x for x in range(10)))"," — the outer call parens double as the generator's parens when it's the only argument.",[14,3362,3364],{"id":3363},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[3258,3366,3367,3373,3391,3425,3445],{},[3261,3368,3369,3372],{},[1274,3370,3371],{},"Generators are single-use — exhausting one silently yields nothing on further iteration, with no error"," — this is the most dangerous gotcha in this chapter because it fails silently rather than raising; always materialize to a list first if you need more than one pass over the data.",[3261,3374,3375,3386,3387,3390],{},[1274,3376,3377,3380,3381,3385],{},[29,3378,3379],{},"itertools.groupby"," only groups ",[3382,3383,3384],"em",{},"consecutive"," matching elements, not all elements sharing a key"," — it is not a ",[29,3388,3389],{},"GROUP BY","; forgetting to sort the input first produces multiple small groups with duplicate keys scattered throughout the output instead of one group per key.",[3261,3392,3393,3420,3421,3424],{},[1274,3394,3395,3396,151,3399,151,3402,3405,3406,3409,3410,151,3413,151,3416,3419],{},"Infinite iterators (",[29,3397,3398],{},"itertools.count",[29,3400,3401],{},"itertools.cycle",[29,3403,3404],{},"itertools.repeat()"," with no ",[29,3407,3408],{},"times",") will hang a program forever if not paired with ",[29,3411,3412],{},"islice",[29,3414,3415],{},"break",[29,3417,3418],{},"zip"," against a finite iterable, or a manual counter"," — a bare ",[29,3422,3423],{},"for x in itertools.count(): print(x)"," never terminates.",[3261,3426,3427,3434,3435,3438,3439,3441,3442,3309],{},[1274,3428,3429,3430,3433],{},"A generator's local variables are only garbage-collected once the generator is exhausted, ",[29,3431,3432],{},".close()","d, or falls out of scope"," — a generator paused mid-iteration (never exhausted, never explicitly closed, still referenced) keeps its entire local stack frame — including any open file handles or large local variables — alive indefinitely; wrap generator-based file readers in ",[29,3436,3437],{},"with"," blocks inside the generator body so cleanup happens even on early ",[29,3440,3432],{},"\u002Fgarbage collection via ",[29,3443,3444],{},"GeneratorExit",[3261,3446,3447,3455,3456,3459,3460,3463,3464,3467,3468,3471,3472,3475,3476,3478],{},[1274,3448,3449,3450,3452,3453],{},"Priming is required before the first ",[29,3451,1772],{},", but not before the first ",[29,3454,3241],{}," — calling ",[29,3457,3458],{},".send(value)"," (with a non-",[29,3461,3462],{},"None"," value) on a freshly created, never-advanced generator raises ",[29,3465,3466],{},"TypeError","; you must call ",[29,3469,3470],{},"next(gen)"," (or ",[29,3473,3474],{},"gen.send(None)",", equivalent) once first to advance it to its first ",[29,3477,1290],{}," expression.",[14,3480,3482],{"id":3481},"spot-the-bug","🧠 Spot the Bug",[1271,3484,3485],{},"A data pipeline function looks correct but produces wrong statistics in production. What's wrong?",[19,3487,3488],{"language":21},[23,3489,3491],{"className":25,"code":3490,"language":21,"meta":27,"style":27},"def get_valid_readings(sensor_data):\n    return (reading for reading in sensor_data if reading is not None and reading >= 0)\n\ndef analyze(sensor_data):\n    valid = get_valid_readings(sensor_data)\n    total = sum(valid)\n    count = sum(1 for _ in valid)\n    average = total \u002F count if count else 0\n    return {\"total\": total, \"count\": count, \"average\": average}\n\nprint(analyze([10, None, 20, -5, 30]))\n",[29,3492,3493,3503,3545,3549,3558,3568,3579,3600,3622,3646,3650],{"__ignoreMap":27},[32,3494,3495,3497,3500],{"class":34,"line":35},[32,3496,100],{"class":64},[32,3498,3499],{"class":103}," get_valid_readings",[32,3501,3502],{"class":68},"(sensor_data):\n",[32,3504,3505,3507,3510,3512,3515,3517,3520,3522,3524,3527,3530,3533,3536,3538,3541,3543],{"class":34,"line":42},[32,3506,547],{"class":64},[32,3508,3509],{"class":68}," (reading ",[32,3511,990],{"class":64},[32,3513,3514],{"class":68}," reading ",[32,3516,308],{"class":64},[32,3518,3519],{"class":68}," sensor_data ",[32,3521,1136],{"class":64},[32,3523,3514],{"class":68},[32,3525,3526],{"class":64},"is",[32,3528,3529],{"class":64}," not",[32,3531,3532],{"class":110}," None",[32,3534,3535],{"class":64}," and",[32,3537,3514],{"class":68},[32,3539,3540],{"class":64},">=",[32,3542,1149],{"class":110},[32,3544,261],{"class":68},[32,3546,3547],{"class":34,"line":48},[32,3548,58],{"emptyLinePlaceholder":57},[32,3550,3551,3553,3556],{"class":34,"line":54},[32,3552,100],{"class":64},[32,3554,3555],{"class":103}," analyze",[32,3557,3502],{"class":68},[32,3559,3560,3563,3565],{"class":34,"line":61},[32,3561,3562],{"class":68},"    valid ",[32,3564,145],{"class":64},[32,3566,3567],{"class":68}," get_valid_readings(sensor_data)\n",[32,3569,3570,3572,3574,3576],{"class":34,"line":72},[32,3571,634],{"class":68},[32,3573,145],{"class":64},[32,3575,2098],{"class":110},[32,3577,3578],{"class":68},"(valid)\n",[32,3580,3581,3583,3585,3587,3589,3591,3593,3595,3597],{"class":34,"line":86},[32,3582,644],{"class":68},[32,3584,145],{"class":64},[32,3586,2098],{"class":110},[32,3588,846],{"class":68},[32,3590,1198],{"class":110},[32,3592,835],{"class":64},[32,3594,2118],{"class":68},[32,3596,308],{"class":64},[32,3598,3599],{"class":68}," valid)\n",[32,3601,3602,3604,3606,3608,3610,3613,3615,3617,3620],{"class":34,"line":91},[32,3603,653],{"class":68},[32,3605,145],{"class":64},[32,3607,721],{"class":68},[32,3609,724],{"class":64},[32,3611,3612],{"class":68}," count ",[32,3614,1136],{"class":64},[32,3616,3612],{"class":68},[32,3618,3619],{"class":64},"else",[32,3621,639],{"class":110},[32,3623,3624,3626,3628,3631,3634,3637,3640,3643],{"class":34,"line":97},[32,3625,547],{"class":64},[32,3627,412],{"class":68},[32,3629,3630],{"class":125},"\"total\"",[32,3632,3633],{"class":68},": total, ",[32,3635,3636],{"class":125},"\"count\"",[32,3638,3639],{"class":68},": count, ",[32,3641,3642],{"class":125},"\"average\"",[32,3644,3645],{"class":68},": average}\n",[32,3647,3648],{"class":34,"line":122},[32,3649,58],{"emptyLinePlaceholder":57},[32,3651,3652,3654,3657,3659,3661,3663,3665,3667,3669,3671,3673,3675,3677],{"class":34,"line":129},[32,3653,762],{"class":110},[32,3655,3656],{"class":68},"(analyze([",[32,3658,768],{"class":110},[32,3660,151],{"class":68},[32,3662,3462],{"class":110},[32,3664,151],{"class":68},[32,3666,783],{"class":110},[32,3668,151],{"class":68},[32,3670,219],{"class":64},[32,3672,849],{"class":110},[32,3674,151],{"class":68},[32,3676,797],{"class":110},[32,3678,3679],{"class":68},"]))\n",[3681,3682,3683,3687,3719,3722,3806],"details",{},[3684,3685,3686],"summary",{},"Answer",[1271,3688,3689,3690,3272,3693,3696,3697,3700,3701,3704,3705,3708,3709,3712,3713,3716,3717,3309],{},"Prints ",[29,3691,3692],{},"{'total': 60, 'count': 0, 'average': 0}",[29,3694,3695],{},"count"," is wrong, and the ZeroDivisionError is only avoided by luck (the ",[29,3698,3699],{},"if count else 0"," guard). ",[29,3702,3703],{},"get_valid_readings"," returns a generator expression, which is consumed entirely by the first ",[29,3706,3707],{},"sum(valid)"," call. By the time ",[29,3710,3711],{},"sum(1 for _ in valid)"," runs, ",[29,3714,3715],{},"valid"," is already exhausted, so it iterates zero remaining items and returns ",[29,3718,534],{},[1271,3720,3721],{},"The fix is to materialize the filtered readings once into a list, then compute both statistics from that reusable list:",[19,3723,3724],{"language":21},[23,3725,3727],{"className":25,"code":3726,"language":21,"meta":27,"style":27},"def analyze(sensor_data):\n    valid = list(get_valid_readings(sensor_data))\n    total = sum(valid)\n    count = len(valid)\n    average = total \u002F count if count else 0\n    return {\"total\": total, \"count\": count, \"average\": average}\n",[29,3728,3729,3737,3748,3758,3768,3788],{"__ignoreMap":27},[32,3730,3731,3733,3735],{"class":34,"line":35},[32,3732,100],{"class":64},[32,3734,3555],{"class":103},[32,3736,3502],{"class":68},[32,3738,3739,3741,3743,3745],{"class":34,"line":42},[32,3740,3562],{"class":68},[32,3742,145],{"class":64},[32,3744,2422],{"class":110},[32,3746,3747],{"class":68},"(get_valid_readings(sensor_data))\n",[32,3749,3750,3752,3754,3756],{"class":34,"line":48},[32,3751,634],{"class":68},[32,3753,145],{"class":64},[32,3755,2098],{"class":110},[32,3757,3578],{"class":68},[32,3759,3760,3762,3764,3766],{"class":34,"line":54},[32,3761,644],{"class":68},[32,3763,145],{"class":64},[32,3765,2239],{"class":110},[32,3767,3578],{"class":68},[32,3769,3770,3772,3774,3776,3778,3780,3782,3784,3786],{"class":34,"line":61},[32,3771,653],{"class":68},[32,3773,145],{"class":64},[32,3775,721],{"class":68},[32,3777,724],{"class":64},[32,3779,3612],{"class":68},[32,3781,1136],{"class":64},[32,3783,3612],{"class":68},[32,3785,3619],{"class":64},[32,3787,639],{"class":110},[32,3789,3790,3792,3794,3796,3798,3800,3802,3804],{"class":34,"line":72},[32,3791,547],{"class":64},[32,3793,412],{"class":68},[32,3795,3630],{"class":125},[32,3797,3633],{"class":68},[32,3799,3636],{"class":125},[32,3801,3639],{"class":68},[32,3803,3642],{"class":125},[32,3805,3645],{"class":68},[1271,3807,3808,3811,3812,3815],{},[1274,3809,3810],{},"The lesson",": a generator is not a reusable \"view\" of data — it's a one-shot iterator. Any function or pipeline stage that needs to make more than one pass over the same generator's output must materialize it into a list (or use ",[29,3813,3814],{},"itertools.tee"," if the two consumers must run in lockstep and the data may be too large to fully materialize).",[14,3817,3819],{"id":3818},"key-takeaways","Key Takeaways",[3258,3821,3822,3825,3832,3839,3848],{},[3261,3823,3824],{},"List\u002Fset\u002Fdict comprehensions are eager and build a full container immediately; generator expressions (parens instead of brackets) are lazy and produce one value at a time on demand.",[3261,3826,3827,3829,3830,3309],{},[29,3828,1290],{}," turns a function into a generator factory — calling it returns a paused generator object; nothing in the body runs until you iterate or call ",[29,3831,3241],{},[3261,3833,3834,3835,3838],{},"Generators are single-use: once exhausted, further iteration silently yields nothing (no error) — materialize to a list with ",[29,3836,3837],{},"list(gen)"," if you need multiple passes.",[3261,3840,3841,3843,3844,3847],{},[29,3842,1669],{}," delegates to a sub-generator\u002Fiterable, correctly forwarding values, exceptions, and return values — prefer it over a manual ",[29,3845,3846],{},"for x in sub: yield x"," loop, especially for recursive generators.",[3261,3849,3850,3852,3853,151,3856,151,3858,151,3860,151,3863,3865,3866,3868,3869,3871],{},[29,3851,2291],{}," provides efficient, lazy building blocks (",[29,3854,3855],{},"chain",[29,3857,3412],{},[29,3859,2734],{},[29,3861,3862],{},"product",[29,3864,3695],{},") — remember ",[29,3867,2734],{}," only merges ",[3382,3870,3384],{}," equal keys, so sort first if you want true grouping.",[3873,3874,3875],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .svAP2, html code.shiki .svAP2{--shiki-default:#032F62;--shiki-github-dark:#DBEDFF}html pre.shiki code .snRuI, html code.shiki .snRuI{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-github-dark:#85E89D;--shiki-github-dark-font-weight:bold}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}",{"title":27,"searchDepth":42,"depth":42,"links":3877},[3878,3879,3880,3884,3886,3887,3892,3893,3895,3896,3897,3898],{"id":16,"depth":42,"text":17},{"id":964,"depth":42,"text":965},{"id":1286,"depth":42,"text":3881,"children":3882},"Generator Functions and yield",[3883],{"id":1478,"depth":48,"text":1479},{"id":1666,"depth":42,"text":3885},"yield from — Delegating to a Sub-Generator",{"id":1920,"depth":42,"text":1921},{"id":2288,"depth":42,"text":3888,"children":3889},"itertools — The Standard Library's Generator Toolkit",[3890],{"id":2730,"depth":48,"text":3891},"The groupby gotcha: it only groups adjacent elements",{"id":2907,"depth":42,"text":2908},{"id":3057,"depth":42,"text":3894},"send() — Two-Way Communication with Generators (Advanced)",{"id":3255,"depth":42,"text":3256},{"id":3363,"depth":42,"text":3364},{"id":3481,"depth":42,"text":3482},{"id":3818,"depth":42,"text":3819},"md",{},"\u002Fpython\u002F09-comprehensions-and-generators",{"title":5,"description":27},"python\u002F09-comprehensions-and-generators","VGcOVIZjNSSBXxQeHgBdfAUc1nApdTe5-ZnW_TENRdg",1789924651450]