[{"data":1,"prerenderedAt":950},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-generators-yield-explained":3},{"id":4,"title":5,"body":6,"description":936,"difficulty":937,"extension":938,"framework":939,"frameworkSlug":66,"meta":940,"navigation":123,"order":74,"path":941,"qaPath":942,"seo":943,"stem":944,"subtopic":945,"topic":946,"topicSlug":947,"updated":948,"__hash__":949},"blog\u002Fblog\u002Fpython-generators-yield-explained.md","Python Generators and yield Explained — Lazy Iteration and Memory",{"type":7,"value":8,"toc":925},"minimark",[9,14,36,40,61,188,198,202,219,305,315,319,330,434,445,449,469,580,590,594,612,688,691,695,706,790,793,797,815,872,881,885,921],[10,11,13],"h2",{"id":12},"python-generators-explained","Python generators, explained",[15,16,17,18,22,23,26,27,30,31,35],"p",{},"Generators are Python's answer to \"produce a sequence of values without building the whole\nthing in memory.\" They power lazy pipelines, let you model infinite streams, and turn up\nconstantly in interviews because they sit at the intersection of ",[19,20,21],"strong",{},"functions",", the\n",[19,24,25],{},"iterator protocol",", and ",[19,28,29],{},"memory efficiency",". This guide explains what ",[32,33,34],"code",{},"yield"," really\ndoes and when a generator beats a list.",[10,37,39],{"id":38},"what-a-generator-is","What a generator is",[15,41,42,43,45,46,49,50,53,54,56,57,60],{},"Any function containing a ",[32,44,34],{}," is a ",[19,47,48],{},"generator function",". Calling it doesn't run the\nbody — it returns a ",[19,51,52],{},"generator object"," (an iterator) that runs the body lazily, pausing\nat each ",[32,55,34],{}," and resuming where it left off on the next ",[32,58,59],{},"next()",".",[62,63,68],"pre",{"className":64,"code":65,"language":66,"meta":67,"style":67},"language-python shiki shiki-themes github-light github-dark","def count_up(n):\n    for i in range(n):\n        yield i          # pause here, hand back i, remember the position\n\ngen = count_up(3)        # nothing has run yet\nnext(gen)                # 0  — runs until the first yield\nnext(gen)                # 1  — resumes after the yield\nnext(gen)                # 2\nnext(gen)                # StopIteration — function returned\n","python","",[32,69,70,87,105,118,125,146,158,168,178],{"__ignoreMap":67},[71,72,75,79,83],"span",{"class":73,"line":74},"line",1,[71,76,78],{"class":77},"szBVR","def",[71,80,82],{"class":81},"sScJk"," count_up",[71,84,86],{"class":85},"sVt8B","(n):\n",[71,88,90,93,96,99,103],{"class":73,"line":89},2,[71,91,92],{"class":77},"    for",[71,94,95],{"class":85}," i ",[71,97,98],{"class":77},"in",[71,100,102],{"class":101},"sj4cs"," range",[71,104,86],{"class":85},[71,106,108,111,114],{"class":73,"line":107},3,[71,109,110],{"class":77},"        yield",[71,112,113],{"class":85}," i          ",[71,115,117],{"class":116},"sJ8bj","# pause here, hand back i, remember the position\n",[71,119,121],{"class":73,"line":120},4,[71,122,124],{"emptyLinePlaceholder":123},true,"\n",[71,126,128,131,134,137,140,143],{"class":73,"line":127},5,[71,129,130],{"class":85},"gen ",[71,132,133],{"class":77},"=",[71,135,136],{"class":85}," count_up(",[71,138,139],{"class":101},"3",[71,141,142],{"class":85},")        ",[71,144,145],{"class":116},"# nothing has run yet\n",[71,147,149,152,155],{"class":73,"line":148},6,[71,150,151],{"class":101},"next",[71,153,154],{"class":85},"(gen)                ",[71,156,157],{"class":116},"# 0  — runs until the first yield\n",[71,159,161,163,165],{"class":73,"line":160},7,[71,162,151],{"class":101},[71,164,154],{"class":85},[71,166,167],{"class":116},"# 1  — resumes after the yield\n",[71,169,171,173,175],{"class":73,"line":170},8,[71,172,151],{"class":101},[71,174,154],{"class":85},[71,176,177],{"class":116},"# 2\n",[71,179,181,183,185],{"class":73,"line":180},9,[71,182,151],{"class":101},[71,184,154],{"class":85},[71,186,187],{"class":116},"# StopIteration — function returned\n",[15,189,190,191,193,194,197],{},"The key idea: ",[32,192,34],{}," ",[19,195,196],{},"suspends"," the function with all its local state intact. The\ngenerator remembers exactly where it paused, so it picks up mid-loop on the next call.",[10,199,201],{"id":200},"yield-vs-return","yield vs return",[15,203,204,207,208,211,212,214,215,218],{},[32,205,206],{},"return"," ends a function and hands back ",[19,209,210],{},"one"," value. ",[32,213,34],{}," hands back a value but keeps\nthe function ",[19,216,217],{},"alive and paused",", ready to produce more. A generator can yield many times;\na plain function returns once.",[62,220,222],{"className":64,"code":221,"language":66,"meta":67,"style":67},"def squares(nums):\n    for n in nums:\n        yield n * n      # produces a value each iteration, doesn't end the function\n\nfor s in squares([1, 2, 3]):\n    print(s)             # 1, 4, 9\n",[32,223,224,234,246,261,265,294],{"__ignoreMap":67},[71,225,226,228,231],{"class":73,"line":74},[71,227,78],{"class":77},[71,229,230],{"class":81}," squares",[71,232,233],{"class":85},"(nums):\n",[71,235,236,238,241,243],{"class":73,"line":89},[71,237,92],{"class":77},[71,239,240],{"class":85}," n ",[71,242,98],{"class":77},[71,244,245],{"class":85}," nums:\n",[71,247,248,250,252,255,258],{"class":73,"line":107},[71,249,110],{"class":77},[71,251,240],{"class":85},[71,253,254],{"class":77},"*",[71,256,257],{"class":85}," n      ",[71,259,260],{"class":116},"# produces a value each iteration, doesn't end the function\n",[71,262,263],{"class":73,"line":120},[71,264,124],{"emptyLinePlaceholder":123},[71,266,267,270,273,275,278,281,284,287,289,291],{"class":73,"line":127},[71,268,269],{"class":77},"for",[71,271,272],{"class":85}," s ",[71,274,98],{"class":77},[71,276,277],{"class":85}," squares([",[71,279,280],{"class":101},"1",[71,282,283],{"class":85},", ",[71,285,286],{"class":101},"2",[71,288,283],{"class":85},[71,290,139],{"class":101},[71,292,293],{"class":85},"]):\n",[71,295,296,299,302],{"class":73,"line":148},[71,297,298],{"class":101},"    print",[71,300,301],{"class":85},"(s)             ",[71,303,304],{"class":116},"# 1, 4, 9\n",[15,306,307,308,310,311,314],{},"A bare ",[32,309,206],{}," inside a generator just stops iteration (raises ",[32,312,313],{},"StopIteration","); its value\nisn't yielded.",[10,316,318],{"id":317},"the-memory-win-lazy-evaluation","The memory win: lazy evaluation",[15,320,321,322,325,326,329],{},"A list comprehension builds ",[19,323,324],{},"every"," element up front and holds them all in memory. A\ngenerator produces values ",[19,327,328],{},"one at a time, on demand"," — so it uses roughly constant\nmemory regardless of how many values flow through.",[62,331,333],{"className":64,"code":332,"language":66,"meta":67,"style":67},"import sys\n\nnums = [x * x for x in range(1_000_000)]    # list: ~8 MB, all at once\ngen  = (x * x for x in range(1_000_000))    # generator: a few hundred bytes\n\nsys.getsizeof(nums)   # ~8000000+\nsys.getsizeof(gen)    # ~200\n",[32,334,335,343,347,382,414,418,426],{"__ignoreMap":67},[71,336,337,340],{"class":73,"line":74},[71,338,339],{"class":77},"import",[71,341,342],{"class":85}," sys\n",[71,344,345],{"class":73,"line":89},[71,346,124],{"emptyLinePlaceholder":123},[71,348,349,352,354,357,359,362,364,366,368,370,373,376,379],{"class":73,"line":107},[71,350,351],{"class":85},"nums ",[71,353,133],{"class":77},[71,355,356],{"class":85}," [x ",[71,358,254],{"class":77},[71,360,361],{"class":85}," x ",[71,363,269],{"class":77},[71,365,361],{"class":85},[71,367,98],{"class":77},[71,369,102],{"class":101},[71,371,372],{"class":85},"(",[71,374,375],{"class":101},"1_000_000",[71,377,378],{"class":85},")]    ",[71,380,381],{"class":116},"# list: ~8 MB, all at once\n",[71,383,384,387,389,392,394,396,398,400,402,404,406,408,411],{"class":73,"line":120},[71,385,386],{"class":85},"gen  ",[71,388,133],{"class":77},[71,390,391],{"class":85}," (x ",[71,393,254],{"class":77},[71,395,361],{"class":85},[71,397,269],{"class":77},[71,399,361],{"class":85},[71,401,98],{"class":77},[71,403,102],{"class":101},[71,405,372],{"class":85},[71,407,375],{"class":101},[71,409,410],{"class":85},"))    ",[71,412,413],{"class":116},"# generator: a few hundred bytes\n",[71,415,416],{"class":73,"line":127},[71,417,124],{"emptyLinePlaceholder":123},[71,419,420,423],{"class":73,"line":148},[71,421,422],{"class":85},"sys.getsizeof(nums)   ",[71,424,425],{"class":116},"# ~8000000+\n",[71,427,428,431],{"class":73,"line":160},[71,429,430],{"class":85},"sys.getsizeof(gen)    ",[71,432,433],{"class":116},"# ~200\n",[15,435,436,437,440,441,444],{},"This is the headline benefit: you can process a 100 GB file or an endless stream because\nyou only ever hold ",[19,438,439],{},"one item"," at a time. The trade-off is that a generator is\n",[19,442,443],{},"single-use"," — once exhausted, you must recreate it to iterate again.",[10,446,448],{"id":447},"generator-expressions-vs-comprehensions","Generator expressions vs comprehensions",[15,450,451,452,455,456,283,459,283,462,465,466,468],{},"A ",[19,453,454],{},"generator expression"," uses the same syntax as a list comprehension but with\nparentheses, and it's lazy. Prefer it when you're feeding the result straight into a\nconsumer like ",[32,457,458],{},"sum",[32,460,461],{},"any",[32,463,464],{},"max",", or a ",[32,467,269],{}," loop.",[62,470,472],{"className":64,"code":471,"language":66,"meta":67,"style":67},"total = sum(x * x for x in range(1000))     # no intermediate list built\nbig   = any(n > 100 for n in data)          # stops early at the first match\n\n# you can even drop the parens when it's the sole argument:\ntotal = sum(x * x for x in range(1000))\n",[32,473,474,510,542,546,551],{"__ignoreMap":67},[71,475,476,479,481,484,487,489,491,493,495,497,499,501,504,507],{"class":73,"line":74},[71,477,478],{"class":85},"total ",[71,480,133],{"class":77},[71,482,483],{"class":101}," sum",[71,485,486],{"class":85},"(x ",[71,488,254],{"class":77},[71,490,361],{"class":85},[71,492,269],{"class":77},[71,494,361],{"class":85},[71,496,98],{"class":77},[71,498,102],{"class":101},[71,500,372],{"class":85},[71,502,503],{"class":101},"1000",[71,505,506],{"class":85},"))     ",[71,508,509],{"class":116},"# no intermediate list built\n",[71,511,512,515,517,520,523,526,529,532,534,536,539],{"class":73,"line":89},[71,513,514],{"class":85},"big   ",[71,516,133],{"class":77},[71,518,519],{"class":101}," any",[71,521,522],{"class":85},"(n ",[71,524,525],{"class":77},">",[71,527,528],{"class":101}," 100",[71,530,531],{"class":77}," for",[71,533,240],{"class":85},[71,535,98],{"class":77},[71,537,538],{"class":85}," data)          ",[71,540,541],{"class":116},"# stops early at the first match\n",[71,543,544],{"class":73,"line":107},[71,545,124],{"emptyLinePlaceholder":123},[71,547,548],{"class":73,"line":120},[71,549,550],{"class":116},"# you can even drop the parens when it's the sole argument:\n",[71,552,553,555,557,559,561,563,565,567,569,571,573,575,577],{"class":73,"line":127},[71,554,478],{"class":85},[71,556,133],{"class":77},[71,558,483],{"class":101},[71,560,486],{"class":85},[71,562,254],{"class":77},[71,564,361],{"class":85},[71,566,269],{"class":77},[71,568,361],{"class":85},[71,570,98],{"class":77},[71,572,102],{"class":101},[71,574,372],{"class":85},[71,576,503],{"class":101},[71,578,579],{"class":85},"))\n",[15,581,582,583,586,587,589],{},"Use a ",[19,584,585],{},"list comprehension"," when you need the materialised list (to index it, reuse it, or\niterate more than once); use a ",[19,588,454],{}," when you just stream through once.",[10,591,593],{"id":592},"yield-from-delegating-to-a-sub-generator","yield from: delegating to a sub-generator",[15,595,596,599,600,603,604,607,608,611],{},[32,597,598],{},"yield from"," yields ",[19,601,602],{},"every value"," from another iterable, flattening nested generators\nwithout a manual loop. It also transparently passes through ",[32,605,606],{},"send","\u002F",[32,609,610],{},"throw"," to the\nsub-generator.",[62,613,615],{"className":64,"code":614,"language":66,"meta":67,"style":67},"def chain(*iterables):\n    for it in iterables:\n        yield from it            # equivalent to: for x in it: yield x\n\nlist(chain([1, 2], [3, 4]))      # [1, 2, 3, 4]\n",[32,616,617,631,643,654,658],{"__ignoreMap":67},[71,618,619,621,624,626,628],{"class":73,"line":74},[71,620,78],{"class":77},[71,622,623],{"class":81}," chain",[71,625,372],{"class":85},[71,627,254],{"class":77},[71,629,630],{"class":85},"iterables):\n",[71,632,633,635,638,640],{"class":73,"line":89},[71,634,92],{"class":77},[71,636,637],{"class":85}," it ",[71,639,98],{"class":77},[71,641,642],{"class":85}," iterables:\n",[71,644,645,648,651],{"class":73,"line":107},[71,646,647],{"class":77},"        yield from",[71,649,650],{"class":85}," it            ",[71,652,653],{"class":116},"# equivalent to: for x in it: yield x\n",[71,655,656],{"class":73,"line":120},[71,657,124],{"emptyLinePlaceholder":123},[71,659,660,663,666,668,670,672,675,677,679,682,685],{"class":73,"line":127},[71,661,662],{"class":101},"list",[71,664,665],{"class":85},"(chain([",[71,667,280],{"class":101},[71,669,283],{"class":85},[71,671,286],{"class":101},[71,673,674],{"class":85},"], [",[71,676,139],{"class":101},[71,678,283],{"class":85},[71,680,681],{"class":101},"4",[71,683,684],{"class":85},"]))      ",[71,686,687],{"class":116},"# [1, 2, 3, 4]\n",[15,689,690],{},"It's the clean way to compose generators — a generator that defers part of its output to\nanother one.",[10,692,694],{"id":693},"infinite-sequences","Infinite sequences",[15,696,697,698,701,702,705],{},"Because generators are lazy, they can represent ",[19,699,700],{},"endless"," streams that you slice with\nsomething like ",[32,703,704],{},"itertools.islice"," or break out of manually.",[62,707,709],{"className":64,"code":708,"language":66,"meta":67,"style":67},"def naturals():\n    n = 0\n    while True:\n        yield n              # never ends — fine, it's lazy\n        n += 1\n\nimport itertools\nlist(itertools.islice(naturals(), 5))   # [0, 1, 2, 3, 4]\n",[32,710,711,721,731,742,752,763,767,774],{"__ignoreMap":67},[71,712,713,715,718],{"class":73,"line":74},[71,714,78],{"class":77},[71,716,717],{"class":81}," naturals",[71,719,720],{"class":85},"():\n",[71,722,723,726,728],{"class":73,"line":89},[71,724,725],{"class":85},"    n ",[71,727,133],{"class":77},[71,729,730],{"class":101}," 0\n",[71,732,733,736,739],{"class":73,"line":107},[71,734,735],{"class":77},"    while",[71,737,738],{"class":101}," True",[71,740,741],{"class":85},":\n",[71,743,744,746,749],{"class":73,"line":120},[71,745,110],{"class":77},[71,747,748],{"class":85}," n              ",[71,750,751],{"class":116},"# never ends — fine, it's lazy\n",[71,753,754,757,760],{"class":73,"line":127},[71,755,756],{"class":85},"        n ",[71,758,759],{"class":77},"+=",[71,761,762],{"class":101}," 1\n",[71,764,765],{"class":73,"line":148},[71,766,124],{"emptyLinePlaceholder":123},[71,768,769,771],{"class":73,"line":160},[71,770,339],{"class":77},[71,772,773],{"class":85}," itertools\n",[71,775,776,778,781,784,787],{"class":73,"line":170},[71,777,662],{"class":101},[71,779,780],{"class":85},"(itertools.islice(naturals(), ",[71,782,783],{"class":101},"5",[71,785,786],{"class":85},"))   ",[71,788,789],{"class":116},"# [0, 1, 2, 3, 4]\n",[15,791,792],{},"A list version of this would loop forever and exhaust memory; the generator only computes\nas far as you consume.",[10,794,796],{"id":795},"a-note-on-generator-state","A note on generator state",[15,798,799,800,803,804,807,808,810,811,814],{},"Generators are also ",[19,801,802],{},"coroutine-like",": you can push values in with ",[32,805,806],{},"gen.send(value)"," (the\nvalue becomes the result of the paused ",[32,809,34],{}," expression) and stop them early with\n",[32,812,813],{},"gen.close()",". This is advanced, but it's why generators underpin older-style coroutines.",[62,816,818],{"className":64,"code":817,"language":66,"meta":67,"style":67},"def accumulator():\n    total = 0\n    while True:\n        x = yield total      # receives whatever send() passes in\n        total += x\n",[32,819,820,829,838,846,862],{"__ignoreMap":67},[71,821,822,824,827],{"class":73,"line":74},[71,823,78],{"class":77},[71,825,826],{"class":81}," accumulator",[71,828,720],{"class":85},[71,830,831,834,836],{"class":73,"line":89},[71,832,833],{"class":85},"    total ",[71,835,133],{"class":77},[71,837,730],{"class":101},[71,839,840,842,844],{"class":73,"line":107},[71,841,735],{"class":77},[71,843,738],{"class":101},[71,845,741],{"class":85},[71,847,848,851,853,856,859],{"class":73,"line":120},[71,849,850],{"class":85},"        x ",[71,852,133],{"class":77},[71,854,855],{"class":77}," yield",[71,857,858],{"class":85}," total      ",[71,860,861],{"class":116},"# receives whatever send() passes in\n",[71,863,864,867,869],{"class":73,"line":127},[71,865,866],{"class":85},"        total ",[71,868,759],{"class":77},[71,870,871],{"class":85}," x\n",[15,873,874,875,607,877,880],{},"In day-to-day code you'll mostly just iterate, but knowing ",[32,876,606],{},[32,878,879],{},"close"," exist explains\nhow generators generalise beyond simple iteration.",[10,882,884],{"id":883},"recap","Recap",[15,886,887,888,45,890,893,894,896,897,899,900,903,904,907,908,911,912,914,915,917,918,920],{},"A function with ",[32,889,34],{},[19,891,892],{},"generator"," — calling it returns a lazy iterator that pauses\nat each ",[32,895,34],{}," and resumes on the next ",[32,898,59],{},", keeping its local state. Generators\ntrade the random-access convenience of a list for ",[19,901,902],{},"constant memory"," and the ability to\nmodel ",[19,905,906],{},"infinite"," streams, at the cost of being single-use. Reach for a ",[19,909,910],{},"generator\nexpression"," when streaming into a consumer, a ",[19,913,585],{}," when you need the\nlist itself, and ",[32,916,598],{}," to delegate to a sub-generator. Once you see ",[32,919,34],{}," as\n\"pause and hand back,\" the rest follows.",[922,923,924],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":67,"searchDepth":89,"depth":89,"links":926},[927,928,929,930,931,932,933,934,935],{"id":12,"depth":89,"text":13},{"id":38,"depth":89,"text":39},{"id":200,"depth":89,"text":201},{"id":317,"depth":89,"text":318},{"id":447,"depth":89,"text":448},{"id":592,"depth":89,"text":593},{"id":693,"depth":89,"text":694},{"id":795,"depth":89,"text":796},{"id":883,"depth":89,"text":884},"How Python generators and yield work — lazy evaluation, the memory win over lists, generator expressions vs comprehensions, yield from, and infinite sequences.","medium","md","Python",{},"\u002Fblog\u002Fpython-generators-yield-explained","\u002Fpython\u002Fiteration\u002Fgenerators",{"title":5,"description":936},"blog\u002Fpython-generators-yield-explained","Generators & yield","Comprehensions & Iteration","iteration","2026-06-19","p8wv9UQwNGRpia3LLimDIyK7k6SPg_xooQln3aEUZy4",1781808673081]