[{"data":1,"prerenderedAt":822},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-inheritance-mro-explained":3},{"id":4,"title":5,"body":6,"description":808,"difficulty":809,"extension":810,"framework":811,"frameworkSlug":35,"meta":812,"navigation":83,"order":43,"path":813,"qaPath":814,"seo":815,"stem":816,"subtopic":817,"topic":818,"topicSlug":819,"updated":820,"__hash__":821},"blog\u002Fblog\u002Fpython-inheritance-mro-explained.md","Python Inheritance and the MRO Explained — super(), the Diamond Problem, and Mixins",{"type":7,"value":8,"toc":798},"minimark",[9,14,23,27,30,159,162,166,178,273,293,297,315,520,546,550,582,597,611,615,618,726,729,733,756,760,794],[10,11,13],"h2",{"id":12},"python-inheritance-explained","Python inheritance, explained",[15,16,17,18,22],"p",{},"Inheritance is easy until multiple inheritance enters the room — then ",[19,20,21],"code",{},"super()",", the MRO,\nand the diamond problem decide who answers a method call. Python has a precise, deterministic\nanswer to all of it (the C3 linearisation), and understanding it is what separates a shallow\nfrom a deep OOP answer.",[10,24,26],{"id":25},"single-vs-multiple-inheritance","Single vs multiple inheritance",[15,28,29],{},"A class can inherit from one base (single) or several (multiple):",[31,32,37],"pre",{"className":33,"code":34,"language":35,"meta":36,"style":36},"language-python shiki shiki-themes github-light github-dark","class Animal:\n    def speak(self):\n        return \"...\"\n\nclass Dog(Animal):              # single inheritance\n    def speak(self):\n        return \"Woof\"\n\nclass Amphibious(Car, Boat):    # multiple inheritance\n    pass\n","python","",[19,38,39,56,68,78,85,106,115,123,128,153],{"__ignoreMap":36},[40,41,44,48,52],"span",{"class":42,"line":43},"line",1,[40,45,47],{"class":46},"szBVR","class",[40,49,51],{"class":50},"sScJk"," Animal",[40,53,55],{"class":54},"sVt8B",":\n",[40,57,59,62,65],{"class":42,"line":58},2,[40,60,61],{"class":46},"    def",[40,63,64],{"class":50}," speak",[40,66,67],{"class":54},"(self):\n",[40,69,71,74],{"class":42,"line":70},3,[40,72,73],{"class":46},"        return",[40,75,77],{"class":76},"sZZnC"," \"...\"\n",[40,79,81],{"class":42,"line":80},4,[40,82,84],{"emptyLinePlaceholder":83},true,"\n",[40,86,88,90,93,96,99,102],{"class":42,"line":87},5,[40,89,47],{"class":46},[40,91,92],{"class":50}," Dog",[40,94,95],{"class":54},"(",[40,97,98],{"class":50},"Animal",[40,100,101],{"class":54},"):              ",[40,103,105],{"class":104},"sJ8bj","# single inheritance\n",[40,107,109,111,113],{"class":42,"line":108},6,[40,110,61],{"class":46},[40,112,64],{"class":50},[40,114,67],{"class":54},[40,116,118,120],{"class":42,"line":117},7,[40,119,73],{"class":46},[40,121,122],{"class":76}," \"Woof\"\n",[40,124,126],{"class":42,"line":125},8,[40,127,84],{"emptyLinePlaceholder":83},[40,129,131,133,136,138,141,144,147,150],{"class":42,"line":130},9,[40,132,47],{"class":46},[40,134,135],{"class":50}," Amphibious",[40,137,95],{"class":54},[40,139,140],{"class":50},"Car",[40,142,143],{"class":54},", ",[40,145,146],{"class":50},"Boat",[40,148,149],{"class":54},"):    ",[40,151,152],{"class":104},"# multiple inheritance\n",[40,154,156],{"class":42,"line":155},10,[40,157,158],{"class":46},"    pass\n",[15,160,161],{},"Single inheritance models \"is-a\" cleanly. Multiple inheritance is powerful but needs the MRO\nto stay sane.",[10,163,165],{"id":164},"the-method-resolution-order-mro","The Method Resolution Order (MRO)",[15,167,168,169,173,174,177],{},"The MRO is the ",[170,171,172],"strong",{},"ordered list of classes"," Python searches when looking up an attribute or\nmethod. It's computed by the ",[170,175,176],{},"C3 linearisation"," algorithm, which guarantees a consistent\norder where subclasses come before their parents:",[31,179,181],{"className":33,"code":180,"language":35,"meta":36,"style":36},"class A: pass\nclass B(A): pass\nclass C(A): pass\nclass D(B, C): pass\n\nD.__mro__   # (D, B, C, A, object)\nD.mro()     # same thing as a list\n",[19,182,183,196,213,228,249,253,265],{"__ignoreMap":36},[40,184,185,187,190,193],{"class":42,"line":43},[40,186,47],{"class":46},[40,188,189],{"class":50}," A",[40,191,192],{"class":54},": ",[40,194,195],{"class":46},"pass\n",[40,197,198,200,203,205,208,211],{"class":42,"line":58},[40,199,47],{"class":46},[40,201,202],{"class":50}," B",[40,204,95],{"class":54},[40,206,207],{"class":50},"A",[40,209,210],{"class":54},"): ",[40,212,195],{"class":46},[40,214,215,217,220,222,224,226],{"class":42,"line":70},[40,216,47],{"class":46},[40,218,219],{"class":50}," C",[40,221,95],{"class":54},[40,223,207],{"class":50},[40,225,210],{"class":54},[40,227,195],{"class":46},[40,229,230,232,235,237,240,242,245,247],{"class":42,"line":80},[40,231,47],{"class":46},[40,233,234],{"class":50}," D",[40,236,95],{"class":54},[40,238,239],{"class":50},"B",[40,241,143],{"class":54},[40,243,244],{"class":50},"C",[40,246,210],{"class":54},[40,248,195],{"class":46},[40,250,251],{"class":42,"line":87},[40,252,84],{"emptyLinePlaceholder":83},[40,254,255,258,262],{"class":42,"line":108},[40,256,257],{"class":54},"D.",[40,259,261],{"class":260},"sj4cs","__mro__",[40,263,264],{"class":104},"   # (D, B, C, A, object)\n",[40,266,267,270],{"class":42,"line":117},[40,268,269],{"class":54},"D.mro()     ",[40,271,272],{"class":104},"# same thing as a list\n",[15,274,275,276,279,280,282,283,282,285,282,287,282,289,292],{},"A lookup on a ",[19,277,278],{},"D"," instance checks ",[19,281,278],{},", then ",[19,284,239],{},[19,286,244],{},[19,288,207],{},[19,290,291],{},"object",", stopping\nat the first match.",[10,294,296],{"id":295},"how-super-really-works","How super() really works",[15,298,299,300,302,303,306,307,310,311,314],{},"A common misconception: ",[19,301,21],{}," does ",[170,304,305],{},"not"," mean \"my parent class\". It means \"the ",[170,308,309],{},"next","\nclass in the ",[170,312,313],{},"MRO"," after the current one\". In single inheritance those coincide; in\nmultiple inheritance they don't:",[31,316,318],{"className":33,"code":317,"language":35,"meta":36,"style":36},"class A:\n    def __init__(self):\n        print(\"A\")\n\nclass B(A):\n    def __init__(self):\n        print(\"B\")\n        super().__init__()      # calls the NEXT in the MRO, not necessarily A\n\nclass C(A):\n    def __init__(self):\n        print(\"C\")\n        super().__init__()\n\nclass D(B, C):\n    def __init__(self):\n        print(\"D\")\n        super().__init__()\n\nD()   # prints D, B, C, A\n",[19,319,320,328,337,350,354,367,375,386,403,407,419,428,440,452,457,474,483,495,506,511],{"__ignoreMap":36},[40,321,322,324,326],{"class":42,"line":43},[40,323,47],{"class":46},[40,325,189],{"class":50},[40,327,55],{"class":54},[40,329,330,332,335],{"class":42,"line":58},[40,331,61],{"class":46},[40,333,334],{"class":260}," __init__",[40,336,67],{"class":54},[40,338,339,342,344,347],{"class":42,"line":70},[40,340,341],{"class":260},"        print",[40,343,95],{"class":54},[40,345,346],{"class":76},"\"A\"",[40,348,349],{"class":54},")\n",[40,351,352],{"class":42,"line":80},[40,353,84],{"emptyLinePlaceholder":83},[40,355,356,358,360,362,364],{"class":42,"line":87},[40,357,47],{"class":46},[40,359,202],{"class":50},[40,361,95],{"class":54},[40,363,207],{"class":50},[40,365,366],{"class":54},"):\n",[40,368,369,371,373],{"class":42,"line":108},[40,370,61],{"class":46},[40,372,334],{"class":260},[40,374,67],{"class":54},[40,376,377,379,381,384],{"class":42,"line":117},[40,378,341],{"class":260},[40,380,95],{"class":54},[40,382,383],{"class":76},"\"B\"",[40,385,349],{"class":54},[40,387,388,391,394,397,400],{"class":42,"line":125},[40,389,390],{"class":260},"        super",[40,392,393],{"class":54},"().",[40,395,396],{"class":260},"__init__",[40,398,399],{"class":54},"()      ",[40,401,402],{"class":104},"# calls the NEXT in the MRO, not necessarily A\n",[40,404,405],{"class":42,"line":130},[40,406,84],{"emptyLinePlaceholder":83},[40,408,409,411,413,415,417],{"class":42,"line":155},[40,410,47],{"class":46},[40,412,219],{"class":50},[40,414,95],{"class":54},[40,416,207],{"class":50},[40,418,366],{"class":54},[40,420,422,424,426],{"class":42,"line":421},11,[40,423,61],{"class":46},[40,425,334],{"class":260},[40,427,67],{"class":54},[40,429,431,433,435,438],{"class":42,"line":430},12,[40,432,341],{"class":260},[40,434,95],{"class":54},[40,436,437],{"class":76},"\"C\"",[40,439,349],{"class":54},[40,441,443,445,447,449],{"class":42,"line":442},13,[40,444,390],{"class":260},[40,446,393],{"class":54},[40,448,396],{"class":260},[40,450,451],{"class":54},"()\n",[40,453,455],{"class":42,"line":454},14,[40,456,84],{"emptyLinePlaceholder":83},[40,458,460,462,464,466,468,470,472],{"class":42,"line":459},15,[40,461,47],{"class":46},[40,463,234],{"class":50},[40,465,95],{"class":54},[40,467,239],{"class":50},[40,469,143],{"class":54},[40,471,244],{"class":50},[40,473,366],{"class":54},[40,475,477,479,481],{"class":42,"line":476},16,[40,478,61],{"class":46},[40,480,334],{"class":260},[40,482,67],{"class":54},[40,484,486,488,490,493],{"class":42,"line":485},17,[40,487,341],{"class":260},[40,489,95],{"class":54},[40,491,492],{"class":76},"\"D\"",[40,494,349],{"class":54},[40,496,498,500,502,504],{"class":42,"line":497},18,[40,499,390],{"class":260},[40,501,393],{"class":54},[40,503,396],{"class":260},[40,505,451],{"class":54},[40,507,509],{"class":42,"line":508},19,[40,510,84],{"emptyLinePlaceholder":83},[40,512,514,517],{"class":42,"line":513},20,[40,515,516],{"class":54},"D()   ",[40,518,519],{"class":104},"# prints D, B, C, A\n",[15,521,522,523,526,527,529,530,532,533,535,536,538,539,541,542,545],{},"Notice ",[19,524,525],{},"B.__init__","'s ",[19,528,21],{}," calls ",[19,531,244],{},", not ",[19,534,207],{},", because ",[19,537,244],{}," is next in ",[19,540,278],{},"'s MRO. This\n",[170,543,544],{},"cooperative"," behaviour is exactly what makes the diamond work.",[10,547,549],{"id":548},"the-diamond-problem","The diamond problem",[15,551,552,553,555,556,558,559,561,562,564,565,568,569,572,573,575,576,578,579,581],{},"The \"diamond\" is when two parents share a common grandparent (",[19,554,278],{}," inherits from ",[19,557,239],{}," and ",[19,560,244],{},",\nboth from ",[19,563,207],{},"). The danger is calling the shared base ",[170,566,567],{},"twice",". Python's MRO solves this:\neach class appears exactly ",[170,570,571],{},"once"," in the MRO, so cooperative ",[19,574,21],{}," calls run ",[19,577,207],{},"'s\n",[19,580,396],{}," a single time:",[31,583,585],{"className":33,"code":584,"language":35,"meta":36,"style":36},"# In the example above, A printed once — not twice —\n# even though both B and C inherit from it.\n",[19,586,587,592],{"__ignoreMap":36},[40,588,589],{"class":42,"line":43},[40,590,591],{"class":104},"# In the example above, A printed once — not twice —\n",[40,593,594],{"class":42,"line":58},[40,595,596],{"class":104},"# even though both B and C inherit from it.\n",[15,598,599,600,606,607,610],{},"The rule for making this work: ",[170,601,602,603],{},"every class in the hierarchy should call ",[19,604,605],{},"super().__init__()","\n(and accept\u002Fforward ",[19,608,609],{},"**kwargs","), so the chain isn't broken.",[10,612,614],{"id":613},"mixins","Mixins",[15,616,617],{},"A mixin is a class that provides a focused piece of behaviour to be \"mixed in\" via multiple\ninheritance — it isn't meant to be instantiated alone:",[31,619,621],{"className":33,"code":620,"language":35,"meta":36,"style":36},"class JsonMixin:\n    def to_json(self):\n        import json\n        return json.dumps(self.__dict__)\n\nclass User(JsonMixin):\n    def __init__(self, name):\n        self.name = name\n\nUser(\"Ada\").to_json()    # '{\"name\": \"Ada\"}'\n",[19,622,623,632,641,649,667,671,685,694,708,712],{"__ignoreMap":36},[40,624,625,627,630],{"class":42,"line":43},[40,626,47],{"class":46},[40,628,629],{"class":50}," JsonMixin",[40,631,55],{"class":54},[40,633,634,636,639],{"class":42,"line":58},[40,635,61],{"class":46},[40,637,638],{"class":50}," to_json",[40,640,67],{"class":54},[40,642,643,646],{"class":42,"line":70},[40,644,645],{"class":46},"        import",[40,647,648],{"class":54}," json\n",[40,650,651,653,656,659,662,665],{"class":42,"line":80},[40,652,73],{"class":46},[40,654,655],{"class":54}," json.dumps(",[40,657,658],{"class":260},"self",[40,660,661],{"class":54},".",[40,663,664],{"class":260},"__dict__",[40,666,349],{"class":54},[40,668,669],{"class":42,"line":87},[40,670,84],{"emptyLinePlaceholder":83},[40,672,673,675,678,680,683],{"class":42,"line":108},[40,674,47],{"class":46},[40,676,677],{"class":50}," User",[40,679,95],{"class":54},[40,681,682],{"class":50},"JsonMixin",[40,684,366],{"class":54},[40,686,687,689,691],{"class":42,"line":117},[40,688,61],{"class":46},[40,690,334],{"class":260},[40,692,693],{"class":54},"(self, name):\n",[40,695,696,699,702,705],{"class":42,"line":125},[40,697,698],{"class":260},"        self",[40,700,701],{"class":54},".name ",[40,703,704],{"class":46},"=",[40,706,707],{"class":54}," name\n",[40,709,710],{"class":42,"line":130},[40,711,84],{"emptyLinePlaceholder":83},[40,713,714,717,720,723],{"class":42,"line":155},[40,715,716],{"class":54},"User(",[40,718,719],{"class":76},"\"Ada\"",[40,721,722],{"class":54},").to_json()    ",[40,724,725],{"class":104},"# '{\"name\": \"Ada\"}'\n",[15,727,728],{},"Mixins keep cross-cutting capabilities (serialisation, comparison, logging) separate from\nthe main class hierarchy.",[10,730,732],{"id":731},"abstract-base-classes-vs-mixins","Abstract base classes vs mixins",[15,734,735,736,739,740,558,743,747,748,751,752,755],{},"They're often confused. An ",[170,737,738],{},"abstract base class"," defines an interface with\n",[19,741,742],{},"@abstractmethod",[744,745,746],"em",{},"can't"," be instantiated until subclasses implement those methods. A\n",[170,749,750],{},"mixin"," ",[744,753,754],{},"provides"," working behaviour. ABCs say \"you must implement this\"; mixins say \"here,\nhave this\".",[10,757,759],{"id":758},"recap","Recap",[15,761,762,763,765,766,768,769,772,773,775,776,779,780,782,783,786,787,789,790,793],{},"Python supports single and multiple inheritance, and resolves attributes via the ",[170,764,313],{},"\ncomputed by ",[170,767,176],{}," (",[19,770,771],{},"Cls.__mro__","). ",[19,774,21],{}," delegates to the ",[170,777,778],{},"next class in\nthe MRO",", not literally the parent — which is why cooperative ",[19,781,605],{}," calls\nmake the ",[170,784,785],{},"diamond problem"," safe, running each shared base exactly once. Use ",[170,788,613],{}," to\nadd focused, reusable behaviour through multiple inheritance, and reserve ",[170,791,792],{},"abstract base\nclasses"," for defining interfaces that subclasses must implement.",[795,796,797],"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 .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":36,"searchDepth":58,"depth":58,"links":799},[800,801,802,803,804,805,806,807],{"id":12,"depth":58,"text":13},{"id":25,"depth":58,"text":26},{"id":164,"depth":58,"text":165},{"id":295,"depth":58,"text":296},{"id":548,"depth":58,"text":549},{"id":613,"depth":58,"text":614},{"id":731,"depth":58,"text":732},{"id":758,"depth":58,"text":759},"How Python inheritance works — single vs multiple inheritance, the C3 method resolution order, what super() really does, how the diamond problem is solved, and mixins.","hard","md","Python",{},"\u002Fblog\u002Fpython-inheritance-mro-explained","\u002Fpython\u002Foop\u002Finheritance",{"title":5,"description":808},"blog\u002Fpython-inheritance-mro-explained","Inheritance & the MRO","Object-Oriented Programming","oop","2026-06-19","w74_QzKNZWftybCh1O1WddYXUg-eWTBKoXiPwVkim9c",1782244092229]