[{"data":1,"prerenderedAt":837},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-iterators-protocol-explained":3},{"id":4,"title":5,"body":6,"description":823,"difficulty":824,"extension":825,"framework":826,"frameworkSlug":80,"meta":827,"navigation":244,"order":141,"path":828,"qaPath":829,"seo":830,"stem":831,"subtopic":832,"topic":833,"topicSlug":834,"updated":835,"__hash__":836},"blog\u002Fblog\u002Fpython-iterators-protocol-explained.md","Python Iterators and the Iterator Protocol Explained — iter, next, and for Loops",{"type":7,"value":8,"toc":813},"minimark",[9,14,39,43,46,75,151,161,165,183,264,268,283,409,425,429,436,483,499,503,515,655,665,669,689,753,756,760,809],[10,11,13],"h2",{"id":12},"python-iterators-explained","Python iterators, explained",[15,16,17,18,22,23,26,27,30,31,34,35,38],"p",{},"Every ",[19,20,21],"code",{},"for"," loop, comprehension, and ",[19,24,25],{},"sum()"," in Python rests on one small protocol. Once\nyou see the machinery, a lot of behaviour — why a generator is \"used up\", why ",[19,28,29],{},"zip"," returns\nsomething you can only loop once — suddenly makes sense. This guide builds it up from\n",[19,32,33],{},"iter()"," and ",[19,36,37],{},"next()",".",[10,40,42],{"id":41},"iterable-vs-iterator","Iterable vs iterator",[15,44,45],{},"These two words sound the same but mean different things:",[47,48,49,62],"ul",{},[50,51,52,53,57,58,61],"li",{},"An ",[54,55,56],"strong",{},"iterable"," is anything you can loop over — a list, string, dict, file. It implements\n",[19,59,60],{},"__iter__",", which returns an iterator.",[50,63,52,64,67,68,71,72,74],{},[54,65,66],{},"iterator"," is the object that actually produces values one at a time. It implements\n",[19,69,70],{},"__next__"," (and returns itself from ",[19,73,60],{},").",[76,77,82],"pre",{"className":78,"code":79,"language":80,"meta":81,"style":81},"language-python shiki shiki-themes github-light github-dark","nums = [1, 2, 3]        # iterable (a list)\nit = iter(nums)         # iterator\ntype(it)                # \u003Cclass 'list_iterator'>\n","python","",[19,83,84,122,139],{"__ignoreMap":81},[85,86,89,93,97,100,104,107,110,112,115,118],"span",{"class":87,"line":88},"line",1,[85,90,92],{"class":91},"sVt8B","nums ",[85,94,96],{"class":95},"szBVR","=",[85,98,99],{"class":91}," [",[85,101,103],{"class":102},"sj4cs","1",[85,105,106],{"class":91},", ",[85,108,109],{"class":102},"2",[85,111,106],{"class":91},[85,113,114],{"class":102},"3",[85,116,117],{"class":91},"]        ",[85,119,121],{"class":120},"sJ8bj","# iterable (a list)\n",[85,123,125,128,130,133,136],{"class":87,"line":124},2,[85,126,127],{"class":91},"it ",[85,129,96],{"class":95},[85,131,132],{"class":102}," iter",[85,134,135],{"class":91},"(nums)         ",[85,137,138],{"class":120},"# iterator\n",[85,140,142,145,148],{"class":87,"line":141},3,[85,143,144],{"class":102},"type",[85,146,147],{"class":91},"(it)                ",[85,149,150],{"class":120},"# \u003Cclass 'list_iterator'>\n",[15,152,153,154,157,158,160],{},"A list is iterable but is ",[54,155,156],{},"not"," its own iterator — you get a fresh iterator each time you\ncall ",[19,159,33],{}," on it.",[10,162,164],{"id":163},"iter-and-next","iter() and next()",[15,166,167,170,171,174,175,178,179,182],{},[19,168,169],{},"iter(obj)"," gets an iterator; ",[19,172,173],{},"next(it)"," pulls the next value. When values run out,\n",[19,176,177],{},"next"," raises ",[19,180,181],{},"StopIteration",":",[76,184,186],{"className":78,"code":185,"language":80,"meta":81,"style":81},"it = iter([10, 20])\nnext(it)        # 10\nnext(it)        # 20\nnext(it)        # StopIteration\n\nnext(it, \"done\")   # supply a default to avoid the exception -> 'done'\n",[19,187,188,210,220,229,239,246],{"__ignoreMap":81},[85,189,190,192,194,196,199,202,204,207],{"class":87,"line":88},[85,191,127],{"class":91},[85,193,96],{"class":95},[85,195,132],{"class":102},[85,197,198],{"class":91},"([",[85,200,201],{"class":102},"10",[85,203,106],{"class":91},[85,205,206],{"class":102},"20",[85,208,209],{"class":91},"])\n",[85,211,212,214,217],{"class":87,"line":124},[85,213,177],{"class":102},[85,215,216],{"class":91},"(it)        ",[85,218,219],{"class":120},"# 10\n",[85,221,222,224,226],{"class":87,"line":141},[85,223,177],{"class":102},[85,225,216],{"class":91},[85,227,228],{"class":120},"# 20\n",[85,230,232,234,236],{"class":87,"line":231},4,[85,233,177],{"class":102},[85,235,216],{"class":91},[85,237,238],{"class":120},"# StopIteration\n",[85,240,242],{"class":87,"line":241},5,[85,243,245],{"emptyLinePlaceholder":244},true,"\n",[85,247,249,251,254,258,261],{"class":87,"line":248},6,[85,250,177],{"class":102},[85,252,253],{"class":91},"(it, ",[85,255,257],{"class":256},"sZZnC","\"done\"",[85,259,260],{"class":91},")   ",[85,262,263],{"class":120},"# supply a default to avoid the exception -> 'done'\n",[10,265,267],{"id":266},"what-a-for-loop-actually-does","What a for loop actually does",[15,269,270,271,273,274,276,277,279,280,282],{},"A ",[19,272,21],{}," loop is sugar for: call ",[19,275,33],{}," on the iterable, repeatedly call ",[19,278,37],{},", and stop\nwhen ",[19,281,181],{}," is raised. These are equivalent:",[76,284,286],{"className":78,"code":285,"language":80,"meta":81,"style":81},"for x in [1, 2, 3]:\n    print(x)\n\n# desugared:\nit = iter([1, 2, 3])\nwhile True:\n    try:\n        x = next(it)\n    except StopIteration:\n        break\n    print(x)\n",[19,287,288,313,321,325,330,352,363,371,385,396,402],{"__ignoreMap":81},[85,289,290,292,295,298,300,302,304,306,308,310],{"class":87,"line":88},[85,291,21],{"class":95},[85,293,294],{"class":91}," x ",[85,296,297],{"class":95},"in",[85,299,99],{"class":91},[85,301,103],{"class":102},[85,303,106],{"class":91},[85,305,109],{"class":102},[85,307,106],{"class":91},[85,309,114],{"class":102},[85,311,312],{"class":91},"]:\n",[85,314,315,318],{"class":87,"line":124},[85,316,317],{"class":102},"    print",[85,319,320],{"class":91},"(x)\n",[85,322,323],{"class":87,"line":141},[85,324,245],{"emptyLinePlaceholder":244},[85,326,327],{"class":87,"line":231},[85,328,329],{"class":120},"# desugared:\n",[85,331,332,334,336,338,340,342,344,346,348,350],{"class":87,"line":241},[85,333,127],{"class":91},[85,335,96],{"class":95},[85,337,132],{"class":102},[85,339,198],{"class":91},[85,341,103],{"class":102},[85,343,106],{"class":91},[85,345,109],{"class":102},[85,347,106],{"class":91},[85,349,114],{"class":102},[85,351,209],{"class":91},[85,353,354,357,360],{"class":87,"line":248},[85,355,356],{"class":95},"while",[85,358,359],{"class":102}," True",[85,361,362],{"class":91},":\n",[85,364,366,369],{"class":87,"line":365},7,[85,367,368],{"class":95},"    try",[85,370,362],{"class":91},[85,372,374,377,379,382],{"class":87,"line":373},8,[85,375,376],{"class":91},"        x ",[85,378,96],{"class":95},[85,380,381],{"class":102}," next",[85,383,384],{"class":91},"(it)\n",[85,386,388,391,394],{"class":87,"line":387},9,[85,389,390],{"class":95},"    except",[85,392,393],{"class":102}," StopIteration",[85,395,362],{"class":91},[85,397,399],{"class":87,"line":398},10,[85,400,401],{"class":95},"        break\n",[85,403,405,407],{"class":87,"line":404},11,[85,406,317],{"class":102},[85,408,320],{"class":91},[15,410,411,412,414,415,417,418,106,421,424],{},"This is why anything implementing the protocol works in a ",[19,413,21],{}," loop, ",[19,416,297],{}," test,\ncomprehension, ",[19,419,420],{},"sum",[19,422,423],{},"max",", unpacking, and so on.",[10,426,428],{"id":427},"iterators-are-exhausted-after-one-pass","Iterators are exhausted after one pass",[15,430,431,432,435],{},"An iterator holds its position and ",[54,433,434],{},"moves forward only"," — once consumed, it's empty. This\nis the source of many \"my data disappeared\" bugs:",[76,437,439],{"className":78,"code":438,"language":80,"meta":81,"style":81},"it = iter([1, 2, 3])\nlist(it)       # [1, 2, 3]\nlist(it)       # []  — already exhausted!\n",[19,440,441,463,474],{"__ignoreMap":81},[85,442,443,445,447,449,451,453,455,457,459,461],{"class":87,"line":88},[85,444,127],{"class":91},[85,446,96],{"class":95},[85,448,132],{"class":102},[85,450,198],{"class":91},[85,452,103],{"class":102},[85,454,106],{"class":91},[85,456,109],{"class":102},[85,458,106],{"class":91},[85,460,114],{"class":102},[85,462,209],{"class":91},[85,464,465,468,471],{"class":87,"line":124},[85,466,467],{"class":102},"list",[85,469,470],{"class":91},"(it)       ",[85,472,473],{"class":120},"# [1, 2, 3]\n",[85,475,476,478,480],{"class":87,"line":141},[85,477,467],{"class":102},[85,479,470],{"class":91},[85,481,482],{"class":120},"# []  — already exhausted!\n",[15,484,485,486,106,488,491,492,495,496,498],{},"The same applies to generators, ",[19,487,29],{},[19,489,490],{},"map",", and ",[19,493,494],{},"filter"," objects. If you need to iterate\ntwice, keep the underlying list, or call ",[19,497,33],{}," again on the original iterable (not on the\nspent iterator).",[10,500,502],{"id":501},"building-a-custom-iterator","Building a custom iterator",[15,504,505,506,508,509,511,512,514],{},"To make a class iterable, implement ",[19,507,60],{}," (return the iterator) and ",[19,510,70],{}," (produce\nvalues or raise ",[19,513,181],{},"):",[76,516,518],{"className":78,"code":517,"language":80,"meta":81,"style":81},"class Countdown:\n    def __init__(self, start):\n        self.n = start\n    def __iter__(self):\n        return self                 # the object is its own iterator\n    def __next__(self):\n        if self.n \u003C= 0:\n            raise StopIteration\n        self.n -= 1\n        return self.n + 1\n\nlist(Countdown(3))   # [3, 2, 1]\n",[19,519,520,531,542,555,565,576,585,602,610,622,635,639],{"__ignoreMap":81},[85,521,522,525,529],{"class":87,"line":88},[85,523,524],{"class":95},"class",[85,526,528],{"class":527},"sScJk"," Countdown",[85,530,362],{"class":91},[85,532,533,536,539],{"class":87,"line":124},[85,534,535],{"class":95},"    def",[85,537,538],{"class":102}," __init__",[85,540,541],{"class":91},"(self, start):\n",[85,543,544,547,550,552],{"class":87,"line":141},[85,545,546],{"class":102},"        self",[85,548,549],{"class":91},".n ",[85,551,96],{"class":95},[85,553,554],{"class":91}," start\n",[85,556,557,559,562],{"class":87,"line":231},[85,558,535],{"class":95},[85,560,561],{"class":102}," __iter__",[85,563,564],{"class":91},"(self):\n",[85,566,567,570,573],{"class":87,"line":241},[85,568,569],{"class":95},"        return",[85,571,572],{"class":102}," self",[85,574,575],{"class":120},"                 # the object is its own iterator\n",[85,577,578,580,583],{"class":87,"line":248},[85,579,535],{"class":95},[85,581,582],{"class":102}," __next__",[85,584,564],{"class":91},[85,586,587,590,592,594,597,600],{"class":87,"line":365},[85,588,589],{"class":95},"        if",[85,591,572],{"class":102},[85,593,549],{"class":91},[85,595,596],{"class":95},"\u003C=",[85,598,599],{"class":102}," 0",[85,601,362],{"class":91},[85,603,604,607],{"class":87,"line":373},[85,605,606],{"class":95},"            raise",[85,608,609],{"class":102}," StopIteration\n",[85,611,612,614,616,619],{"class":87,"line":387},[85,613,546],{"class":102},[85,615,549],{"class":91},[85,617,618],{"class":95},"-=",[85,620,621],{"class":102}," 1\n",[85,623,624,626,628,630,633],{"class":87,"line":398},[85,625,569],{"class":95},[85,627,572],{"class":102},[85,629,549],{"class":91},[85,631,632],{"class":95},"+",[85,634,621],{"class":102},[85,636,637],{"class":87,"line":404},[85,638,245],{"emptyLinePlaceholder":244},[85,640,642,644,647,649,652],{"class":87,"line":641},12,[85,643,467],{"class":102},[85,645,646],{"class":91},"(Countdown(",[85,648,114],{"class":102},[85,650,651],{"class":91},"))   ",[85,653,654],{"class":120},"# [3, 2, 1]\n",[15,656,657,658,661,662,664],{},"Returning ",[19,659,660],{},"self"," from ",[19,663,60],{}," makes this single-use, like the built-in iterators.",[10,666,668],{"id":667},"generators-iterators-without-the-boilerplate","Generators: iterators without the boilerplate",[15,670,671,672,674,675,677,678,681,682,685,686,688],{},"Writing ",[19,673,60],{},"\u002F",[19,676,70],{}," by hand is rarely necessary — a ",[54,679,680],{},"generator function","\n(any function with ",[19,683,684],{},"yield",") builds an iterator for you, managing state and ",[19,687,181],{},"\nautomatically:",[76,690,692],{"className":78,"code":691,"language":80,"meta":81,"style":81},"def countdown(start):\n    while start > 0:\n        yield start\n        start -= 1\n\nlist(countdown(3))   # [3, 2, 1]\n",[19,693,694,705,720,727,736,740],{"__ignoreMap":81},[85,695,696,699,702],{"class":87,"line":88},[85,697,698],{"class":95},"def",[85,700,701],{"class":527}," countdown",[85,703,704],{"class":91},"(start):\n",[85,706,707,710,713,716,718],{"class":87,"line":124},[85,708,709],{"class":95},"    while",[85,711,712],{"class":91}," start ",[85,714,715],{"class":95},">",[85,717,599],{"class":102},[85,719,362],{"class":91},[85,721,722,725],{"class":87,"line":141},[85,723,724],{"class":95},"        yield",[85,726,554],{"class":91},[85,728,729,732,734],{"class":87,"line":231},[85,730,731],{"class":91},"        start ",[85,733,618],{"class":95},[85,735,621],{"class":102},[85,737,738],{"class":87,"line":241},[85,739,245],{"emptyLinePlaceholder":244},[85,741,742,744,747,749,751],{"class":87,"line":248},[85,743,467],{"class":102},[85,745,746],{"class":91},"(countdown(",[85,748,114],{"class":102},[85,750,651],{"class":91},[85,752,654],{"class":120},[15,754,755],{},"This is the idiomatic way to produce custom iteration; the class form is mostly useful when\nyou need extra methods or attributes alongside iteration.",[10,757,759],{"id":758},"recap","Recap",[15,761,52,762,764,765,767,768,770,771,773,774,776,777,779,780,782,783,785,786,788,789,106,791,106,793,795,796,799,800,674,802,804,805,808],{},[54,763,56],{}," has ",[19,766,60],{}," and can be looped over repeatedly; an ",[54,769,66],{}," has\n",[19,772,70],{},", yields values once, and raises ",[19,775,181],{}," when done. A ",[19,778,21],{}," loop is sugar\nfor ",[19,781,33],{}," then repeated ",[19,784,37],{}," until ",[19,787,181],{},". Iterators (including generators,\n",[19,790,29],{},[19,792,490],{},[19,794,494],{},") are ",[54,797,798],{},"single-use"," — re-create them to iterate again. Implement the\nprotocol with ",[19,801,60],{},[19,803,70],{}," for a custom iterator, but reach for a ",[54,806,807],{},"generator\nfunction"," when you just want iteration without the boilerplate.",[810,811,812],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}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);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":81,"searchDepth":124,"depth":124,"links":814},[815,816,817,818,819,820,821,822],{"id":12,"depth":124,"text":13},{"id":41,"depth":124,"text":42},{"id":163,"depth":124,"text":164},{"id":266,"depth":124,"text":267},{"id":427,"depth":124,"text":428},{"id":501,"depth":124,"text":502},{"id":667,"depth":124,"text":668},{"id":758,"depth":124,"text":759},"How Python iteration really works — iterable vs iterator, the __iter__\u002F__next__ protocol, what for loops do under the hood, and why an iterator is exhausted after one pass.","medium","md","Python",{},"\u002Fblog\u002Fpython-iterators-protocol-explained","\u002Fpython\u002Fiteration\u002Fiterators",{"title":5,"description":823},"blog\u002Fpython-iterators-protocol-explained","Iterators & the Iterator Protocol","Comprehensions & Iteration","iteration","2026-06-19","FdTXtDWjQFhiu6SlwVm70QGQQHf4Mo9MTrqLvxtaLo8",1782244093503]