[{"data":1,"prerenderedAt":2840},["ShallowReactive",2],{"page-\u002Fpython\u002F13-inheritance-and-polymorphism":3},{"id":4,"title":5,"body":6,"description":454,"extension":2834,"meta":2835,"navigation":34,"path":2836,"seo":2837,"stem":2838,"__hash__":2839},"content\u002Fpython\u002F13-inheritance-and-polymorphism.md","13 — Inheritance & Polymorphism",{"type":7,"value":8,"toc":2801},"minimark",[9,13,85,171,292,361,432,669,747,1090,1262,1360,1586,1782,1967,2261,2347,2405,2488,2592,2702,2797],[10,11,5],"h1",{"id":12},"_13-inheritance-polymorphism",[14,15,16,21,55],"question-wrapper",{},[17,18,20],"h3",{"id":19},"q1-what-is-the-method-resolution-order-mro","Q1. What is the Method Resolution Order (MRO)?",[22,23,26,37,43,49],"ul",{"className":24},[25],"contains-task-list",[27,28,31,36],"li",{"className":29},[30],"task-list-item",[32,33],"input",{"disabled":34,"type":35},true,"checkbox"," The specific, linear order in which Python searches base classes for a method or attribute when it's not found on the instance or its own class",[27,38,40,42],{"className":39},[30],[32,41],{"disabled":34,"type":35}," The order in which a class's methods are defined in the source file",[27,44,46,48],{"className":45},[30],[32,47],{"disabled":34,"type":35}," The order in which methods execute when an instance is created",[27,50,52,54],{"className":51},[30],[32,53],{"disabled":34,"type":35}," A runtime cache of the most recently called methods, for performance",[56,57,58,62,70],"details",{},[59,60,61],"summary",{},"Show Answer",[63,64,65,69],"p",{},[66,67,68],"strong",{},"Answer:"," A — The specific, linear order in which Python searches base classes for a method or attribute when it's not found on the instance or its own class",[63,71,72,75,76,80,81,84],{},[66,73,74],{},"Explanation:"," Every class has a computed MRO (viewable via ",[77,78,79],"code",{},"ClassName.__mro__"," or ",[77,82,83],{},"ClassName.mro()",") that linearizes the entire inheritance graph into a single, deterministic sequence. Attribute and method lookups walk this sequence in order and stop at the first match. It has nothing to do with source-code definition order or a runtime cache — it's a static property computed when the class is created.",[14,86,87,99,139],{},[17,88,90,91,94,95,98],{"id":89},"q2-in-single-inheritance-what-does-super__init__args-inside-a-subclasss-__init__-do","Q2. In single inheritance, what does ",[77,92,93],{},"super().__init__(*args)"," inside a subclass's ",[77,96,97],{},"__init__"," do?",[22,100,102,111,121,130],{"className":101},[25],[27,103,105,107,108,110],{"className":104},[30],[32,106],{"disabled":34,"type":35}," Calls the immediate parent class's ",[77,109,97],{},", passing along the given arguments, using the instance's actual MRO",[27,112,114,116,117,120],{"className":113},[30],[32,115],{"disabled":34,"type":35}," Calls ",[77,118,119],{},"object.__init__"," directly, skipping any intermediate parent classes",[27,122,124,126,127,129],{"className":123},[30],[32,125],{"disabled":34,"type":35}," Re-runs the subclass's own ",[77,128,97],{}," recursively",[27,131,133,135,136],{"className":132},[30],[32,134],{"disabled":34,"type":35}," Creates a brand-new parent-class instance separate from ",[77,137,138],{},"self",[56,140,141,143,150],{},[59,142,61],{},[63,144,145,147,148,110],{},[66,146,68],{}," A — Calls the immediate parent class's ",[77,149,97],{},[63,151,152,154,155,158,159,163,164,166,167,170],{},[66,153,74],{}," ",[77,156,157],{},"super()"," (zero-argument form, Python 3+) returns a proxy object bound to the current class and instance, and delegates attribute lookup to the ",[160,161,162],"em",{},"next"," class in ",[77,165,138],{},"'s MRO after the current one. In simple single inheritance, that next class is just the immediate parent — but as covered later in this quiz, in multiple inheritance \"next in the MRO\" is not always the same as \"the literal parent class in the ",[77,168,169],{},"class"," statement.\"",[14,172,173,177,240],{},[17,174,176],{"id":175},"q3-what-is-diamond-inheritance","Q3. What is \"diamond inheritance\"?",[22,178,180,207,213,228],{"className":179},[25],[27,181,183,185,186,189,190,193,194,197,198,201,202,189,204,206],{"className":182},[30],[32,184],{"disabled":34,"type":35}," A class hierarchy where two classes ",[77,187,188],{},"B"," and ",[77,191,192],{},"C"," both inherit from a common base ",[77,195,196],{},"A",", and a class ",[77,199,200],{},"D"," inherits from both ",[77,203,188],{},[77,205,192],{},", forming a diamond shape",[27,208,210,212],{"className":209},[30],[32,211],{"disabled":34,"type":35}," A class that inherits from four or more base classes",[27,214,216,218,219,221,222,189,224,221,226],{"className":215},[30],[32,217],{"disabled":34,"type":35}," A circular inheritance chain where ",[77,220,196],{}," inherits from ",[77,223,188],{},[77,225,188],{},[77,227,196],{},[27,229,231,233,234,80,237],{"className":230},[30],[32,232],{"disabled":34,"type":35}," Inheriting from a built-in type like ",[77,235,236],{},"dict",[77,238,239],{},"list",[56,241,242,244,261],{},[59,243,61],{},[63,245,246,248,249,189,251,193,253,197,255,201,257,189,259,206],{},[66,247,68],{}," A — A class hierarchy where two classes ",[77,250,188],{},[77,252,192],{},[77,254,196],{},[77,256,200],{},[77,258,188],{},[77,260,192],{},[63,262,263,265,266,268,269,189,271,273,274,276,277,279,280,282,283,285,286,288,289,291],{},[66,264,74],{}," Diagrammed, ",[77,267,196],{}," sits at the top, ",[77,270,188],{},[77,272,192],{}," branch off it, and ",[77,275,200],{}," sits at the bottom pointing to both — a diamond. The classic question this raises is: when ",[77,278,200],{}," calls a method defined on ",[77,281,196],{}," (and possibly overridden in ",[77,284,188],{}," and\u002For ",[77,287,192],{},"), which version runs, and does ",[77,290,196],{},"'s code run once or twice? Python's C3 linearization (covered next) exists specifically to answer this unambiguously.",[14,293,294,298,334],{},[17,295,297],{"id":296},"q4-what-guarantee-does-pythons-c3-linearization-algorithm-provide-when-computing-a-classs-mro","Q4. What guarantee does Python's C3 linearization algorithm provide when computing a class's MRO?",[22,299,301,310,316,328],{"className":300},[25],[27,302,304,306,307,309],{"className":303},[30],[32,305],{"disabled":34,"type":35}," Every class appears exactly once in the MRO, a subclass always precedes its own base classes, and the relative order of base classes as listed in the ",[77,308,169],{}," statement is preserved",[27,311,313,315],{"className":312},[30],[32,314],{"disabled":34,"type":35}," It guarantees the MRO always matches simple depth-first, left-to-right traversal of the inheritance tree, as in old-style classes",[27,317,319,321,322,324,325,327],{"className":318},[30],[32,320],{"disabled":34,"type":35}," It guarantees every base class's ",[77,323,97],{}," runs automatically, even without ",[77,326,157],{}," calls",[27,329,331,333],{"className":330},[30],[32,332],{"disabled":34,"type":35}," It only applies to classes that inherit from exactly two base classes",[56,335,336,338,345],{},[59,337,61],{},[63,339,340,342,343,309],{},[66,341,68],{}," A — Every class appears exactly once in the MRO, a subclass always precedes its own base classes, and the relative order of base classes as listed in the ",[77,344,169],{},[63,346,347,154,349,352,353,356,357,360],{},[66,348,74],{},[66,350,351],{},"Debug"," — Python 2's old-style classes used naive depth-first-left-to-right (DFLR) search, which could visit a common ancestor multiple times or in an inconsistent order for diamond hierarchies. C3 linearization (used by all classes in Python 3, since they all implicitly inherit from ",[77,354,355],{},"object",") fixes this by merging each base's own MRO plus the base list itself, guaranteeing monotonicity and local precedence. If no consistent order can be computed, Python raises ",[77,358,359],{},"TypeError"," at class-creation time rather than silently picking an ambiguous order (covered in Q9).",[14,362,363,367,402],{},[17,364,366],{"id":365},"q5-what-is-duck-typing","Q5. What is \"duck typing\"?",[22,368,370,376,382,396],{"className":369},[25],[27,371,373,375],{"className":372},[30],[32,374],{"disabled":34,"type":35}," Relying on an object's behavior (which methods\u002Fattributes it supports) rather than its actual type or class hierarchy to decide if it's usable in a given context",[27,377,379,381],{"className":378},[30],[32,380],{"disabled":34,"type":35}," A typing style where every variable must have an explicit type hint",[27,383,385,387,388,391,392,395],{"className":384},[30],[32,386],{"disabled":34,"type":35}," Using ",[77,389,390],{},"isinstance()"," checks exclusively instead of ",[77,393,394],{},"type()"," comparisons",[27,397,399,401],{"className":398},[30],[32,400],{"disabled":34,"type":35}," A Python 2-only feature removed in Python 3",[56,403,404,406,411],{},[59,405,61],{},[63,407,408,410],{},[66,409,68],{}," A — Relying on an object's behavior (which methods\u002Fattributes it supports) rather than its actual type or class hierarchy to decide if it's usable in a given context",[63,412,413,415,416,419,420,423,424,427,428,431],{},[66,414,74],{}," \"If it walks like a duck and quacks like a duck, it's a duck\" — Python code that does ",[77,417,418],{},"obj.read()"," without checking ",[77,421,422],{},"isinstance(obj, SomeFileType)"," first is duck typing: any object with a compatible ",[77,425,426],{},".read()"," method works, regardless of its actual class or inheritance chain. This is central to Python's idiomatic style and is contrasted with rigid, explicit ",[77,429,430],{},"isinstance"," gatekeeping later in this quiz.",[14,433,435,446,583,637],{"language":434},"python",[17,436,438,439,441,442,445],{"id":437},"q6-what-happens-if-a-subclass-overrides-__init__-but-never-calls-super__init__","Q6. What happens if a subclass overrides ",[77,440,97],{}," but never calls ",[77,443,444],{},"super().__init__()","?",[447,448,449],"code-wrapper",{"language":434},[450,451,455],"pre",{"className":452,"code":453,"language":434,"meta":454,"style":454},"language-python shiki shiki-themes github-light github-dark","class Vehicle:\n    def __init__(self, wheels):\n        self.wheels = wheels\n\nclass Car(Vehicle):\n    def __init__(self, brand):\n        self.brand = brand  # forgot super().__init__(wheels)\n\nc = Car(\"Toyota\")\nprint(c.wheels)\n","",[77,456,457,473,486,501,507,524,534,551,556,574],{"__ignoreMap":454},[458,459,462,465,469],"span",{"class":460,"line":461},"line",1,[458,463,169],{"class":464},"svdQ7",[458,466,468],{"class":467},"sIsaT"," Vehicle",[458,470,472],{"class":471},"ssxIu",":\n",[458,474,476,479,483],{"class":460,"line":475},2,[458,477,478],{"class":464},"    def",[458,480,482],{"class":481},"snvgF"," __init__",[458,484,485],{"class":471},"(self, wheels):\n",[458,487,489,492,495,498],{"class":460,"line":488},3,[458,490,491],{"class":481},"        self",[458,493,494],{"class":471},".wheels ",[458,496,497],{"class":464},"=",[458,499,500],{"class":471}," wheels\n",[458,502,504],{"class":460,"line":503},4,[458,505,506],{"emptyLinePlaceholder":34},"\n",[458,508,510,512,515,518,521],{"class":460,"line":509},5,[458,511,169],{"class":464},[458,513,514],{"class":467}," Car",[458,516,517],{"class":471},"(",[458,519,520],{"class":467},"Vehicle",[458,522,523],{"class":471},"):\n",[458,525,527,529,531],{"class":460,"line":526},6,[458,528,478],{"class":464},[458,530,482],{"class":481},[458,532,533],{"class":471},"(self, brand):\n",[458,535,537,539,542,544,547],{"class":460,"line":536},7,[458,538,491],{"class":481},[458,540,541],{"class":471},".brand ",[458,543,497],{"class":464},[458,545,546],{"class":471}," brand  ",[458,548,550],{"class":549},"sdCPZ","# forgot super().__init__(wheels)\n",[458,552,554],{"class":460,"line":553},8,[458,555,506],{"emptyLinePlaceholder":34},[458,557,559,562,564,567,571],{"class":460,"line":558},9,[458,560,561],{"class":471},"c ",[458,563,497],{"class":464},[458,565,566],{"class":471}," Car(",[458,568,570],{"class":569},"sJ6F3","\"Toyota\"",[458,572,573],{"class":471},")\n",[458,575,577,580],{"class":460,"line":576},10,[458,578,579],{"class":481},"print",[458,581,582],{"class":471},"(c.wheels)\n",[22,584,586,602,614,625],{"className":585},[25],[27,587,589,154,591,594,595,597,598,601],{"className":588},[30],[32,590],{"disabled":34,"type":35},[77,592,593],{},"AttributeError: 'Car' object has no attribute 'wheels'"," — the parent's ",[77,596,97],{}," never runs, so ",[77,599,600],{},"self.wheels"," is never set",[27,603,605,154,607,610,611],{"className":604},[30],[32,606],{"disabled":34,"type":35},[77,608,609],{},"4"," — Python automatically infers a default value for ",[77,612,613],{},"wheels",[27,615,617,154,619,622,623],{"className":616},[30],[32,618],{"disabled":34,"type":35},[77,620,621],{},"None"," — uninitialized attributes default to ",[77,624,621],{},[27,626,628,154,630,632,633,636],{"className":627},[30],[32,629],{"disabled":34,"type":35},[77,631,359],{}," is raised immediately when ",[77,634,635],{},"Car(\"Toyota\")"," is called",[56,638,639,641,652],{},[59,640,61],{},[63,642,643,645,646,594,648,597,650,601],{},[66,644,68],{}," A — ",[77,647,593],{},[77,649,97],{},[77,651,600],{},[63,653,654,154,656,658,659,661,662,665,666,668],{},[66,655,74],{},[66,657,351],{}," — Overriding ",[77,660,97],{}," completely replaces the parent's version unless the subclass explicitly calls it via ",[77,663,664],{},"super().__init__(...)",". There is no automatic chaining — Python does not run every ",[77,667,97],{}," up the MRO unless the code says so. This is one of the most common real-world inheritance bugs: a subclass \"loses\" attributes the parent was responsible for setting up, and the failure only surfaces later when that attribute is accessed, far from the actual mistake.",[14,670,671,675,713],{},[17,672,674],{"id":673},"q7-how-can-you-inspect-a-classs-actual-mro-at-runtime","Q7. How can you inspect a class's actual MRO at runtime?",[22,676,678,689,698,707],{"className":677},[25],[27,679,681,154,683,685,686,688],{"className":680},[30],[32,682],{"disabled":34,"type":35},[77,684,79],{}," (a tuple) or ",[77,687,83],{}," (a list)",[27,690,692,154,694,697],{"className":691},[30],[32,693],{"disabled":34,"type":35},[77,695,696],{},"ClassName.__bases__"," gives the full MRO, including indirect ancestors",[27,699,701,154,703,706],{"className":700},[30],[32,702],{"disabled":34,"type":35},[77,704,705],{},"dir(ClassName)"," returns the MRO in order",[27,708,710,712],{"className":709},[30],[32,711],{"disabled":34,"type":35}," MRO cannot be inspected; it's only used internally by the interpreter",[56,714,715,717,725],{},[59,716,61],{},[63,718,719,645,721,685,723,688],{},[66,720,68],{},[77,722,79],{},[77,724,83],{},[63,726,727,154,729,732,733,736,737,740,741,743,744,746],{},[66,728,74],{},[77,730,731],{},"__mro__"," is the linearized order computed by C3 at class-creation time. ",[77,734,735],{},"__bases__"," (option B) is a common point of confusion — it only lists the ",[160,738,739],{},"direct"," parents named in the ",[77,742,169],{}," statement, not the full linearized ancestor chain, so it's insufficient for understanding how ",[77,745,157],{}," will actually resolve calls in a multi-level or multiple-inheritance hierarchy.",[14,748,749,753,943,1012],{"language":434},[17,750,752],{"id":751},"q8-given-cooperative-multiple-inheritance-what-does-this-print","Q8. Given cooperative multiple inheritance, what does this print?",[447,754,755],{"language":434},[450,756,758],{"className":452,"code":757,"language":434,"meta":454,"style":454},"class A:\n    def greet(self):\n        print(\"A\")\n\nclass B(A):\n    def greet(self):\n        print(\"B\")\n        super().greet()\n\nclass C(A):\n    def greet(self):\n        print(\"C\")\n        super().greet()\n\nclass D(B, C):\n    def greet(self):\n        print(\"D\")\n        super().greet()\n\nD().greet()\n",[77,759,760,769,779,791,795,808,816,827,835,839,852,861,873,880,885,904,913,925,932,937],{"__ignoreMap":454},[458,761,762,764,767],{"class":460,"line":461},[458,763,169],{"class":464},[458,765,766],{"class":467}," A",[458,768,472],{"class":471},[458,770,771,773,776],{"class":460,"line":475},[458,772,478],{"class":464},[458,774,775],{"class":467}," greet",[458,777,778],{"class":471},"(self):\n",[458,780,781,784,786,789],{"class":460,"line":488},[458,782,783],{"class":481},"        print",[458,785,517],{"class":471},[458,787,788],{"class":569},"\"A\"",[458,790,573],{"class":471},[458,792,793],{"class":460,"line":503},[458,794,506],{"emptyLinePlaceholder":34},[458,796,797,799,802,804,806],{"class":460,"line":509},[458,798,169],{"class":464},[458,800,801],{"class":467}," B",[458,803,517],{"class":471},[458,805,196],{"class":467},[458,807,523],{"class":471},[458,809,810,812,814],{"class":460,"line":526},[458,811,478],{"class":464},[458,813,775],{"class":467},[458,815,778],{"class":471},[458,817,818,820,822,825],{"class":460,"line":536},[458,819,783],{"class":481},[458,821,517],{"class":471},[458,823,824],{"class":569},"\"B\"",[458,826,573],{"class":471},[458,828,829,832],{"class":460,"line":553},[458,830,831],{"class":481},"        super",[458,833,834],{"class":471},"().greet()\n",[458,836,837],{"class":460,"line":558},[458,838,506],{"emptyLinePlaceholder":34},[458,840,841,843,846,848,850],{"class":460,"line":576},[458,842,169],{"class":464},[458,844,845],{"class":467}," C",[458,847,517],{"class":471},[458,849,196],{"class":467},[458,851,523],{"class":471},[458,853,855,857,859],{"class":460,"line":854},11,[458,856,478],{"class":464},[458,858,775],{"class":467},[458,860,778],{"class":471},[458,862,864,866,868,871],{"class":460,"line":863},12,[458,865,783],{"class":481},[458,867,517],{"class":471},[458,869,870],{"class":569},"\"C\"",[458,872,573],{"class":471},[458,874,876,878],{"class":460,"line":875},13,[458,877,831],{"class":481},[458,879,834],{"class":471},[458,881,883],{"class":460,"line":882},14,[458,884,506],{"emptyLinePlaceholder":34},[458,886,888,890,893,895,897,900,902],{"class":460,"line":887},15,[458,889,169],{"class":464},[458,891,892],{"class":467}," D",[458,894,517],{"class":471},[458,896,188],{"class":467},[458,898,899],{"class":471},", ",[458,901,192],{"class":467},[458,903,523],{"class":471},[458,905,907,909,911],{"class":460,"line":906},16,[458,908,478],{"class":464},[458,910,775],{"class":467},[458,912,778],{"class":471},[458,914,916,918,920,923],{"class":460,"line":915},17,[458,917,783],{"class":481},[458,919,517],{"class":471},[458,921,922],{"class":569},"\"D\"",[458,924,573],{"class":471},[458,926,928,930],{"class":460,"line":927},18,[458,929,831],{"class":481},[458,931,834],{"class":471},[458,933,935],{"class":460,"line":934},19,[458,936,506],{"emptyLinePlaceholder":34},[458,938,940],{"class":460,"line":939},20,[458,941,942],{"class":471},"D().greet()\n",[22,944,946,964,983,998],{"className":945},[25],[27,947,949,154,951,899,953,899,955,899,957,959,960,963],{"className":948},[30],[32,950],{"disabled":34,"type":35},[77,952,200],{},[77,954,188],{},[77,956,192],{},[77,958,196],{}," — each class's ",[77,961,962],{},"greet"," runs exactly once, in MRO order",[27,965,967,154,969,899,971,899,973,899,975,899,977,979,980,982],{"className":966},[30],[32,968],{"disabled":34,"type":35},[77,970,200],{},[77,972,188],{},[77,974,196],{},[77,976,192],{},[77,978,196],{}," — ",[77,981,196],{}," runs twice, once via each branch of the diamond",[27,984,986,154,988,899,990,899,992,994,995,997],{"className":985},[30],[32,987],{"disabled":34,"type":35},[77,989,200],{},[77,991,188],{},[77,993,196],{}," only — ",[77,996,192],{}," is never reached",[27,999,1001,154,1003,899,1005,899,1007,899,1009,1011],{"className":1000},[30],[32,1002],{"disabled":34,"type":35},[77,1004,200],{},[77,1006,192],{},[77,1008,188],{},[77,1010,196],{}," — multiple inheritance always resolves right-to-left",[56,1013,1014,1016,1030],{},[59,1015,61],{},[63,1017,1018,645,1020,899,1022,899,1024,899,1026,959,1028,963],{},[66,1019,68],{},[77,1021,200],{},[77,1023,188],{},[77,1025,192],{},[77,1027,196],{},[77,1029,962],{},[63,1031,1032,154,1034,979,1036,1038,1039,1042,1043,1045,1046,1048,1049,1052,1053,1056,1057,1060,1061,1063,1064,1066,1067,1069,1070,1072,1073,1063,1075,1077,1078,1080,1081,1083,1084,1086,1087,1089],{},[66,1033,74],{},[66,1035,351],{},[77,1037,200],{},"'s MRO is ",[77,1040,1041],{},"[D, B, C, A, object]"," (computed by C3, preserving ",[77,1044,188],{}," before ",[77,1047,192],{}," since that's their order in ",[77,1050,1051],{},"class D(B, C)","). Each ",[77,1054,1055],{},"super().greet()"," call doesn't jump straight to that class's own literal parent — it advances to the ",[160,1058,1059],{},"next class in the shared MRO",", so ",[77,1062,188],{},"'s ",[77,1065,1055],{}," calls ",[77,1068,192],{},"'s (not ",[77,1071,196],{},"'s directly), and only ",[77,1074,192],{},[77,1076,1055],{}," finally reaches ",[77,1079,196],{},". This is exactly why naive assumptions like \"each branch of the diamond calls ",[77,1082,196],{}," independently\" (option B, ",[77,1085,196],{}," running twice) are wrong — C3 linearization guarantees ",[77,1088,196],{}," is visited exactly once.",[14,1091,1092,1096,1165,1212],{"language":434},[17,1093,1095],{"id":1094},"q9-what-happens-when-you-try-to-define-this-class","Q9. What happens when you try to define this class?",[447,1097,1098],{"language":434},[450,1099,1101],{"className":452,"code":1100,"language":434,"meta":454,"style":454},"class X:\n    pass\n\nclass Y(X):\n    pass\n\nclass Z(X, Y):\n    pass\n",[77,1102,1103,1112,1117,1121,1135,1139,1143,1161],{"__ignoreMap":454},[458,1104,1105,1107,1110],{"class":460,"line":461},[458,1106,169],{"class":464},[458,1108,1109],{"class":467}," X",[458,1111,472],{"class":471},[458,1113,1114],{"class":460,"line":475},[458,1115,1116],{"class":464},"    pass\n",[458,1118,1119],{"class":460,"line":488},[458,1120,506],{"emptyLinePlaceholder":34},[458,1122,1123,1125,1128,1130,1133],{"class":460,"line":503},[458,1124,169],{"class":464},[458,1126,1127],{"class":467}," Y",[458,1129,517],{"class":471},[458,1131,1132],{"class":467},"X",[458,1134,523],{"class":471},[458,1136,1137],{"class":460,"line":509},[458,1138,1116],{"class":464},[458,1140,1141],{"class":460,"line":526},[458,1142,506],{"emptyLinePlaceholder":34},[458,1144,1145,1147,1150,1152,1154,1156,1159],{"class":460,"line":536},[458,1146,169],{"class":464},[458,1148,1149],{"class":467}," Z",[458,1151,517],{"class":471},[458,1153,1132],{"class":467},[458,1155,899],{"class":471},[458,1157,1158],{"class":467},"Y",[458,1160,523],{"class":471},[458,1162,1163],{"class":460,"line":553},[458,1164,1116],{"class":464},[22,1166,1168,1176,1188,1198],{"className":1167},[25],[27,1169,1171,154,1173],{"className":1170},[30],[32,1172],{"disabled":34,"type":35},[77,1174,1175],{},"TypeError: Cannot create a consistent method resolution order (MRO) for bases X, Y",[27,1177,1179,1181,1182,1038,1185],{"className":1178},[30],[32,1180],{"disabled":34,"type":35}," It works fine; ",[77,1183,1184],{},"Z",[77,1186,1187],{},"[Z, X, Y, object]",[27,1189,1191,1181,1193,1038,1195],{"className":1190},[30],[32,1192],{"disabled":34,"type":35},[77,1194,1184],{},[77,1196,1197],{},"[Z, Y, X, object]",[27,1199,1201,154,1203,1205,1206,1208,1209,1211],{"className":1200},[30],[32,1202],{"disabled":34,"type":35},[77,1204,1184],{}," silently ignores ",[77,1207,1132],{}," since ",[77,1210,1158],{}," already inherits from it",[56,1213,1214,1216,1222],{},[59,1215,61],{},[63,1217,1218,645,1220],{},[66,1219,68],{},[77,1221,1175],{},[63,1223,1224,154,1226,979,1228,1231,1232,1234,1235,1237,1238,1240,1241,1243,1244,1045,1246,1248,1249,1251,1252,1255,1256,1258,1259,1261],{},[66,1225,74],{},[66,1227,351],{},[77,1229,1230],{},"class Z(X, Y)"," demands that ",[77,1233,1132],{}," precede ",[77,1236,1158],{}," (as listed), but ",[77,1239,1158],{}," already inherits from ",[77,1242,1132],{},", which means any valid MRO must place ",[77,1245,1158],{},[77,1247,1132],{}," (subclasses must precede their own bases — a rule from Q4). These two requirements directly contradict each other, so C3 linearization has no valid solution, and Python raises ",[77,1250,359],{}," at class-definition time rather than guessing. The fix is to list bases in an order consistent with the existing hierarchy: ",[77,1253,1254],{},"class Z(Y, X)"," would work, since ",[77,1257,1158],{}," already implies ",[77,1260,1132],{}," comes after it.",[14,1263,1264,1277,1322],{},[17,1265,1267,1268,189,1270,1273,1274,445],{"id":1266},"q10-in-python-3-is-there-any-behavioral-difference-between-super-and-supercurrentclass-self-when-called-inside-a-normal-instance-method-of-currentclass","Q10. In Python 3, is there any behavioral difference between ",[77,1269,157],{},[77,1271,1272],{},"super(CurrentClass, self)"," when called inside a normal instance method of ",[77,1275,1276],{},"CurrentClass",[22,1278,1280,1292,1301,1310],{"className":1279},[25],[27,1281,1283,1285,1286,1288,1289,1291],{"className":1282},[30],[32,1284],{"disabled":34,"type":35}," No — Python 3's zero-argument ",[77,1287,157],{}," is compiler-assisted sugar that resolves to exactly ",[77,1290,1272],{}," in that context",[27,1293,1295,1297,1298,1300],{"className":1294},[30],[32,1296],{"disabled":34,"type":35}," Yes — the zero-argument form always uses ",[77,1299,355],{}," as the starting point, skipping intermediate classes",[27,1302,1304,1306,1307,1309],{"className":1303},[30],[32,1305],{"disabled":34,"type":35}," Yes — the zero-argument form only works in ",[77,1308,97],{},", not other methods",[27,1311,1313,1315,1316,1318,1319,1321],{"className":1312},[30],[32,1314],{"disabled":34,"type":35}," Yes — ",[77,1317,157],{}," without arguments raises ",[77,1320,359],{}," in Python 3",[56,1323,1324,1326,1335],{},[59,1325,61],{},[63,1327,1328,1330,1331,1288,1333,1291],{},[66,1329,68],{}," A — No — Python 3's zero-argument ",[77,1332,157],{},[77,1334,1272],{},[63,1336,1337,1339,1340,1343,1344,1346,1347,1349,1350,1352,1353,1356,1357,1359],{},[66,1338,74],{}," The compiler injects a hidden ",[77,1341,1342],{},"__class__"," cell reference so that bare ",[77,1345,157],{}," inside a method knows both the class it was defined in and the instance (",[77,1348,138],{},") it's being called on, letting it reconstruct the explicit two-argument form automatically. The explicit ",[77,1351,1272],{}," form (Python 2 style) still works in Python 3 and is occasionally still needed — e.g., inside a ",[77,1354,1355],{},"@staticmethod"," or a nested function where the implicit ",[77,1358,1342],{}," cell isn't available — but for ordinary methods, the two are equivalent.",[14,1361,1362,1368,1475,1537],{"language":434},[17,1363,1365,1366,445],{"id":1364},"q11-a-mixin-is-meant-to-add-caching-to-any-class-in-a-cooperative-multiple-inheritance-hierarchy-whats-wrong-with-this-__init__","Q11. A mixin is meant to add caching to any class in a cooperative multiple-inheritance hierarchy. What's wrong with this ",[77,1367,97],{},[447,1369,1370],{"language":434},[450,1371,1373],{"className":452,"code":1372,"language":434,"meta":454,"style":454},"class CacheMixin:\n    def __init__(self, *args, **kwargs):\n        self.cache = {}\n        super().__init__()  # note: no args\u002Fkwargs forwarded\n\nclass Repository(CacheMixin, Base):\n    def __init__(self, db_url):\n        super().__init__(db_url)\n",[77,1374,1375,1384,1405,1417,1432,1436,1455,1464],{"__ignoreMap":454},[458,1376,1377,1379,1382],{"class":460,"line":461},[458,1378,169],{"class":464},[458,1380,1381],{"class":467}," CacheMixin",[458,1383,472],{"class":471},[458,1385,1386,1388,1390,1393,1396,1399,1402],{"class":460,"line":475},[458,1387,478],{"class":464},[458,1389,482],{"class":481},[458,1391,1392],{"class":471},"(self, ",[458,1394,1395],{"class":464},"*",[458,1397,1398],{"class":471},"args, ",[458,1400,1401],{"class":464},"**",[458,1403,1404],{"class":471},"kwargs):\n",[458,1406,1407,1409,1412,1414],{"class":460,"line":488},[458,1408,491],{"class":481},[458,1410,1411],{"class":471},".cache ",[458,1413,497],{"class":464},[458,1415,1416],{"class":471}," {}\n",[458,1418,1419,1421,1424,1426,1429],{"class":460,"line":503},[458,1420,831],{"class":481},[458,1422,1423],{"class":471},"().",[458,1425,97],{"class":481},[458,1427,1428],{"class":471},"()  ",[458,1430,1431],{"class":549},"# note: no args\u002Fkwargs forwarded\n",[458,1433,1434],{"class":460,"line":509},[458,1435,506],{"emptyLinePlaceholder":34},[458,1437,1438,1440,1443,1445,1448,1450,1453],{"class":460,"line":526},[458,1439,169],{"class":464},[458,1441,1442],{"class":467}," Repository",[458,1444,517],{"class":471},[458,1446,1447],{"class":467},"CacheMixin",[458,1449,899],{"class":471},[458,1451,1452],{"class":467},"Base",[458,1454,523],{"class":471},[458,1456,1457,1459,1461],{"class":460,"line":536},[458,1458,478],{"class":464},[458,1460,482],{"class":481},[458,1462,1463],{"class":471},"(self, db_url):\n",[458,1465,1466,1468,1470,1472],{"class":460,"line":553},[458,1467,831],{"class":481},[458,1469,1423],{"class":471},[458,1471,97],{"class":481},[458,1473,1474],{"class":471},"(db_url)\n",[22,1476,1478,1504,1513,1524],{"className":1477},[25],[27,1479,1481,154,1483,1486,1487,1490,1491,1493,1494,1496,1497,1500,1501,1503],{"className":1480},[30],[32,1482],{"disabled":34,"type":35},[77,1484,1485],{},"CacheMixin.__init__"," drops ",[77,1488,1489],{},"*args, **kwargs"," when calling ",[77,1492,444],{},", so the next class in the MRO (",[77,1495,1452],{},") never receives ",[77,1498,1499],{},"db_url",", breaking ",[77,1502,1452],{},"'s own initialization",[27,1505,1507,1509,1510,1512],{"className":1506},[30],[32,1508],{"disabled":34,"type":35}," Mixins can never define ",[77,1511,97],{},"; only the final concrete class can",[27,1514,1516,154,1518,1520,1521,1523],{"className":1515},[30],[32,1517],{"disabled":34,"type":35},[77,1519,444],{}," inside a mixin always raises ",[77,1522,359],{}," since mixins have no base class",[27,1525,1527,1529,1530,1533,1534,1536],{"className":1526},[30],[32,1528],{"disabled":34,"type":35}," Nothing is wrong; ",[77,1531,1532],{},"Base.__init__"," will still receive ",[77,1535,1499],{}," automatically",[56,1538,1539,1541,1557],{},[59,1540,61],{},[63,1542,1543,645,1545,1486,1547,1490,1549,1493,1551,1496,1553,1500,1555,1503],{},[66,1544,68],{},[77,1546,1485],{},[77,1548,1489],{},[77,1550,444],{},[77,1552,1452],{},[77,1554,1499],{},[77,1556,1452],{},[63,1558,1559,154,1561,1563,1564,1567,1568,1570,1571,1573,1574,1576,1577,1579,1580,1582,1583,1585],{},[66,1560,74],{},[66,1562,351],{}," — In cooperative multiple inheritance, every class in the chain must forward whatever arguments it doesn't consume itself to ",[77,1565,1566],{},"super().__init__(*args, **kwargs)",", so the call correctly propagates down the entire MRO to whichever class ultimately needs them. Here, ",[77,1569,1447],{}," accepts ",[77,1572,1489],{}," but then calls ",[77,1575,444],{}," with nothing, silently swallowing ",[77,1578,1499],{}," before it ever reaches ",[77,1581,1452],{},". The fix is ",[77,1584,1566],{}," in the mixin, ensuring the cooperative chain stays intact.",[14,1587,1588,1592,1695,1729],{"language":434},[17,1589,1591],{"id":1590},"q12-what-does-this-print","Q12. What does this print?",[447,1593,1594],{"language":434},[450,1595,1597],{"className":452,"code":1596,"language":434,"meta":454,"style":454},"class Base:\n    def __init__(self):\n        self.value = self.compute()\n\n    def compute(self):\n        return 1\n\nclass Derived(Base):\n    def compute(self):\n        return 2\n\nprint(Derived().value)\n",[77,1598,1599,1608,1616,1631,1635,1644,1652,1656,1669,1677,1684,1688],{"__ignoreMap":454},[458,1600,1601,1603,1606],{"class":460,"line":461},[458,1602,169],{"class":464},[458,1604,1605],{"class":467}," Base",[458,1607,472],{"class":471},[458,1609,1610,1612,1614],{"class":460,"line":475},[458,1611,478],{"class":464},[458,1613,482],{"class":481},[458,1615,778],{"class":471},[458,1617,1618,1620,1623,1625,1628],{"class":460,"line":488},[458,1619,491],{"class":481},[458,1621,1622],{"class":471},".value ",[458,1624,497],{"class":464},[458,1626,1627],{"class":481}," self",[458,1629,1630],{"class":471},".compute()\n",[458,1632,1633],{"class":460,"line":503},[458,1634,506],{"emptyLinePlaceholder":34},[458,1636,1637,1639,1642],{"class":460,"line":509},[458,1638,478],{"class":464},[458,1640,1641],{"class":467}," compute",[458,1643,778],{"class":471},[458,1645,1646,1649],{"class":460,"line":526},[458,1647,1648],{"class":464},"        return",[458,1650,1651],{"class":481}," 1\n",[458,1653,1654],{"class":460,"line":536},[458,1655,506],{"emptyLinePlaceholder":34},[458,1657,1658,1660,1663,1665,1667],{"class":460,"line":553},[458,1659,169],{"class":464},[458,1661,1662],{"class":467}," Derived",[458,1664,517],{"class":471},[458,1666,1452],{"class":467},[458,1668,523],{"class":471},[458,1670,1671,1673,1675],{"class":460,"line":558},[458,1672,478],{"class":464},[458,1674,1641],{"class":467},[458,1676,778],{"class":471},[458,1678,1679,1681],{"class":460,"line":576},[458,1680,1648],{"class":464},[458,1682,1683],{"class":481}," 2\n",[458,1685,1686],{"class":460,"line":854},[458,1687,506],{"emptyLinePlaceholder":34},[458,1689,1690,1692],{"class":460,"line":863},[458,1691,579],{"class":481},[458,1693,1694],{"class":471},"(Derived().value)\n",[22,1696,1698,1706,1714,1722],{"className":1697},[25],[27,1699,1701,154,1703],{"className":1700},[30],[32,1702],{"disabled":34,"type":35},[77,1704,1705],{},"2",[27,1707,1709,154,1711],{"className":1708},[30],[32,1710],{"disabled":34,"type":35},[77,1712,1713],{},"1",[27,1715,1717,154,1719],{"className":1716},[30],[32,1718],{"disabled":34,"type":35},[77,1720,1721],{},"AttributeError: 'Derived' object has no attribute 'compute'",[27,1723,1725,154,1727],{"className":1724},[30],[32,1726],{"disabled":34,"type":35},[77,1728,621],{},[56,1730,1731,1733,1739],{},[59,1732,61],{},[63,1734,1735,645,1737],{},[66,1736,68],{},[77,1738,1705],{},[63,1740,1741,154,1743,1745,1746,1749,1750,1753,1754,1756,1757,1760,1761,1763,1764,1767,1768,1770,1771,1773,1774,1776,1777,1066,1779,1781],{},[66,1742,74],{},[66,1744,351],{}," — Even though ",[77,1747,1748],{},"compute()"," is ",[160,1751,1752],{},"called"," from within ",[77,1755,1532],{},", method lookup is always based on the ",[160,1758,1759],{},"actual runtime type"," of ",[77,1762,138],{}," (",[77,1765,1766],{},"Derived","), not on which class's code is currently executing. This is polymorphism working correctly, but it's a common surprise for developers coming from languages with static dispatch — it also means calling overridable methods from ",[77,1769,97],{}," is risky if the override depends on subclass attributes that haven't been set up yet, since ",[77,1772,97],{}," for ",[77,1775,1766],{}," hasn't necessarily finished running its own setup by the time ",[77,1778,1532],{},[77,1780,1748],{},".",[14,1783,1784,1791,1874,1926],{"language":434},[17,1785,1787,1788,1790],{"id":1786},"q13-a-function-accepts-any-file-like-object-and-calls-read-on-it-which-approach-is-duck-typing-and-which-is-its-rigid-alternative","Q13. A function accepts any \"file-like\" object and calls ",[77,1789,426],{}," on it. Which approach is duck typing, and which is its rigid alternative?",[447,1792,1793],{"language":434},[450,1794,1796],{"className":452,"code":1795,"language":434,"meta":454,"style":454},"# Version A\ndef load(source):\n    return source.read()\n\n# Version B\ndef load(source):\n    if not isinstance(source, io.IOBase):\n        raise TypeError(\"source must be a file\")\n    return source.read()\n",[77,1797,1798,1803,1814,1822,1826,1831,1839,1853,1868],{"__ignoreMap":454},[458,1799,1800],{"class":460,"line":461},[458,1801,1802],{"class":549},"# Version A\n",[458,1804,1805,1808,1811],{"class":460,"line":475},[458,1806,1807],{"class":464},"def",[458,1809,1810],{"class":467}," load",[458,1812,1813],{"class":471},"(source):\n",[458,1815,1816,1819],{"class":460,"line":488},[458,1817,1818],{"class":464},"    return",[458,1820,1821],{"class":471}," source.read()\n",[458,1823,1824],{"class":460,"line":503},[458,1825,506],{"emptyLinePlaceholder":34},[458,1827,1828],{"class":460,"line":509},[458,1829,1830],{"class":549},"# Version B\n",[458,1832,1833,1835,1837],{"class":460,"line":526},[458,1834,1807],{"class":464},[458,1836,1810],{"class":467},[458,1838,1813],{"class":471},[458,1840,1841,1844,1847,1850],{"class":460,"line":536},[458,1842,1843],{"class":464},"    if",[458,1845,1846],{"class":464}," not",[458,1848,1849],{"class":481}," isinstance",[458,1851,1852],{"class":471},"(source, io.IOBase):\n",[458,1854,1855,1858,1861,1863,1866],{"class":460,"line":553},[458,1856,1857],{"class":464},"        raise",[458,1859,1860],{"class":481}," TypeError",[458,1862,517],{"class":471},[458,1864,1865],{"class":569},"\"source must be a file\"",[458,1867,573],{"class":471},[458,1869,1870,1872],{"class":460,"line":558},[458,1871,1818],{"class":464},[458,1873,1821],{"class":471},[22,1875,1877,1897,1905,1920],{"className":1876},[25],[27,1878,1880,1882,1883,1885,1886,1889,1890,1893,1894],{"className":1879},[30],[32,1881],{"disabled":34,"type":35}," Version A is duck typing — it works with any object that implements ",[77,1884,426],{},", including ",[77,1887,1888],{},"io.StringIO",", sockets wrapped in ",[77,1891,1892],{},"makefile()",", or test doubles; Version B rejects perfectly valid file-like objects that don't literally subclass ",[77,1895,1896],{},"io.IOBase",[27,1898,1900,1902,1903],{"className":1899},[30],[32,1901],{"disabled":34,"type":35}," Version B is duck typing, since it explicitly checks the file's \"shape\" via ",[77,1904,430],{},[27,1906,1908,1910,1911,1913,1914,1916,1917,1919],{"className":1907},[30],[32,1909],{"disabled":34,"type":35}," Both versions are equally flexible; ",[77,1912,430],{}," checks against ",[77,1915,1896],{}," accept any object with a ",[77,1918,426],{}," method",[27,1921,1923,1925],{"className":1922},[30],[32,1924],{"disabled":34,"type":35}," Version A is unsafe and should never be used in production code",[56,1927,1928,1930,1943],{},[59,1929,61],{},[63,1931,1932,1934,1935,1885,1937,1889,1939,1893,1941],{},[66,1933,68],{}," A — Version A is duck typing — it works with any object that implements ",[77,1936,426],{},[77,1938,1888],{},[77,1940,1892],{},[77,1942,1896],{},[63,1944,1945,1947,1948,1951,1952,1954,1955,1957,1958,1960,1961,1963,1964,1966],{},[66,1946,74],{}," Duck typing (Version A) trusts that if ",[77,1949,1950],{},"source"," has a working ",[77,1953,426],{},", it's usable — this is precisely what makes Python code composable with third-party and test objects that were never designed to subclass anything in particular. Version B's ",[77,1956,430],{}," check is overly rigid: plenty of legitimate file-like objects (certain mocks, custom wrappers, some third-party libraries) don't inherit from ",[77,1959,1896],{}," even though ",[77,1962,426],{}," works perfectly, so the check produces false-negative ",[77,1965,359],{},"s for valid input — a real production bug pattern, not just a style nitpick.",[14,1968,1969,1973,2121,2186],{"language":434},[17,1970,1972],{"id":1971},"q14-what-does-this-print-and-why","Q14. What does this print, and why?",[447,1974,1975],{"language":434},[450,1976,1978],{"className":452,"code":1977,"language":434,"meta":454,"style":454},"class Base:\n    def __init__(self, name):\n        self.name = name\n        print(\"Base init\")\n\nclass Mixin:\n    def __init__(self, *a, **kw):\n        print(\"Mixin init\")\n        super().__init__(*a, **kw)\n\nclass Combined(Mixin, Base):\n    pass\n\nCombined(\"x\")\n",[77,1979,1980,1988,1997,2009,2020,2024,2033,2051,2062,2081,2085,2103,2107,2111],{"__ignoreMap":454},[458,1981,1982,1984,1986],{"class":460,"line":461},[458,1983,169],{"class":464},[458,1985,1605],{"class":467},[458,1987,472],{"class":471},[458,1989,1990,1992,1994],{"class":460,"line":475},[458,1991,478],{"class":464},[458,1993,482],{"class":481},[458,1995,1996],{"class":471},"(self, name):\n",[458,1998,1999,2001,2004,2006],{"class":460,"line":488},[458,2000,491],{"class":481},[458,2002,2003],{"class":471},".name ",[458,2005,497],{"class":464},[458,2007,2008],{"class":471}," name\n",[458,2010,2011,2013,2015,2018],{"class":460,"line":503},[458,2012,783],{"class":481},[458,2014,517],{"class":471},[458,2016,2017],{"class":569},"\"Base init\"",[458,2019,573],{"class":471},[458,2021,2022],{"class":460,"line":509},[458,2023,506],{"emptyLinePlaceholder":34},[458,2025,2026,2028,2031],{"class":460,"line":526},[458,2027,169],{"class":464},[458,2029,2030],{"class":467}," Mixin",[458,2032,472],{"class":471},[458,2034,2035,2037,2039,2041,2043,2046,2048],{"class":460,"line":536},[458,2036,478],{"class":464},[458,2038,482],{"class":481},[458,2040,1392],{"class":471},[458,2042,1395],{"class":464},[458,2044,2045],{"class":471},"a, ",[458,2047,1401],{"class":464},[458,2049,2050],{"class":471},"kw):\n",[458,2052,2053,2055,2057,2060],{"class":460,"line":553},[458,2054,783],{"class":481},[458,2056,517],{"class":471},[458,2058,2059],{"class":569},"\"Mixin init\"",[458,2061,573],{"class":471},[458,2063,2064,2066,2068,2070,2072,2074,2076,2078],{"class":460,"line":558},[458,2065,831],{"class":481},[458,2067,1423],{"class":471},[458,2069,97],{"class":481},[458,2071,517],{"class":471},[458,2073,1395],{"class":464},[458,2075,2045],{"class":471},[458,2077,1401],{"class":464},[458,2079,2080],{"class":471},"kw)\n",[458,2082,2083],{"class":460,"line":576},[458,2084,506],{"emptyLinePlaceholder":34},[458,2086,2087,2089,2092,2094,2097,2099,2101],{"class":460,"line":854},[458,2088,169],{"class":464},[458,2090,2091],{"class":467}," Combined",[458,2093,517],{"class":471},[458,2095,2096],{"class":467},"Mixin",[458,2098,899],{"class":471},[458,2100,1452],{"class":467},[458,2102,523],{"class":471},[458,2104,2105],{"class":460,"line":863},[458,2106,1116],{"class":464},[458,2108,2109],{"class":460,"line":875},[458,2110,506],{"emptyLinePlaceholder":34},[458,2112,2113,2116,2119],{"class":460,"line":882},[458,2114,2115],{"class":471},"Combined(",[458,2117,2118],{"class":569},"\"x\"",[458,2120,573],{"class":471},[22,2122,2124,2152,2162,2173],{"className":2123},[25],[27,2125,2127,154,2129,2132,2133,979,2136,1038,2139,1060,2142,2145,2146,2149,2150],{"className":2126},[30],[32,2128],{"disabled":34,"type":35},[77,2130,2131],{},"Mixin init"," then ",[77,2134,2135],{},"Base init",[77,2137,2138],{},"Combined",[77,2140,2141],{},"[Combined, Mixin, Base, object]",[77,2143,2144],{},"Mixin.__init__"," runs first and its ",[77,2147,2148],{},"super().__init__"," correctly forwards to ",[77,2151,1452],{},[27,2153,2155,154,2157,2132,2159,2161],{"className":2154},[30],[32,2156],{"disabled":34,"type":35},[77,2158,2135],{},[77,2160,2131],{}," — base classes always initialize before mixins",[27,2163,2165,2167,2168,2170,2171,997],{"className":2164},[30],[32,2166],{"disabled":34,"type":35}," Only ",[77,2169,2131],{}," prints; ",[77,2172,1532],{},[27,2174,2176,154,2178,2180,2181,2183,2184],{"className":2175},[30],[32,2177],{"disabled":34,"type":35},[77,2179,359],{},", because ",[77,2182,2138],{}," doesn't define its own ",[77,2185,97],{},[56,2187,2188,2190,2208],{},[59,2189,61],{},[63,2191,2192,645,2194,2132,2196,979,2198,1038,2200,1060,2202,2145,2204,2149,2206],{},[66,2193,68],{},[77,2195,2131],{},[77,2197,2135],{},[77,2199,2138],{},[77,2201,2141],{},[77,2203,2144],{},[77,2205,2148],{},[77,2207,1452],{},[63,2209,2210,2212,2213,2215,2216,2218,2219,2222,2223,2225,2226,2228,2229,2231,2232,2234,2235,2238,2239,2241,2242,2245,2246,2249,2250,2252,2253,2256,2257,2260],{},[66,2211,74],{}," Since ",[77,2214,2138],{}," defines no ",[77,2217,97],{}," of its own, calling ",[77,2220,2221],{},"Combined(\"x\")"," resolves ",[77,2224,97],{}," via the MRO, finding ",[77,2227,2144],{}," first (because ",[77,2230,2096],{}," is listed before ",[77,2233,1452],{}," in ",[77,2236,2237],{},"class Combined(Mixin, Base)","). Because ",[77,2240,2144],{}," properly forwards ",[77,2243,2244],{},"*a, **kw"," to ",[77,2247,2248],{},"super().__init__(*a, **kw)"," (the fix from Q11), the chain continues correctly into ",[77,2251,1532],{},", which prints and sets ",[77,2254,2255],{},"self.name",". This demonstrates why mixins are conventionally listed ",[160,2258,2259],{},"before"," the \"real\" base class — covered as a best practice later in this quiz.",[14,2262,2263,2274,2307],{},[17,2264,2266,2267,2269,2270,2273],{"id":2265},"q15-when-should-you-prefer-duck-typing-isinstance-checks-against-an-abstract-base-class-abc-or-collectionsabc-protocol-over-an-explicit-concrete-type-check","Q15. When should you prefer duck typing \u002F ",[77,2268,430],{}," checks against an Abstract Base Class (ABC) or ",[77,2271,2272],{},"collections.abc"," protocol over an explicit concrete-type check?",[22,2275,2277,2286,2295,2301],{"className":2276},[25],[27,2278,2280,2282,2283,2285],{"className":2279},[30],[32,2281],{"disabled":34,"type":35}," When you only care that the object supports the required behavior (e.g., iteration, ",[77,2284,426],{},", comparison), since this maximizes compatibility with any conforming object, including ones from third-party code or tests",[27,2287,2289,2291,2292,2294],{"className":2288},[30],[32,2290],{"disabled":34,"type":35}," Always avoid ",[77,2293,430],{}," entirely; type checks are never appropriate in idiomatic Python",[27,2296,2298,2300],{"className":2297},[30],[32,2299],{"disabled":34,"type":35}," Only when performance is not a concern, since duck typing is always slower",[27,2302,2304,2306],{"className":2303},[30],[32,2305],{"disabled":34,"type":35}," Only in Python 2 code; Python 3 favors strict type checks exclusively",[56,2308,2309,2311,2318],{},[59,2310,61],{},[63,2312,2313,2315,2316,2285],{},[66,2314,68],{}," A — When you only care that the object supports the required behavior (e.g., iteration, ",[77,2317,426],{},[63,2319,2320,154,2322,979,2325,2328,2329,2332,2333,2335,2336,2338,2339,2342,2343,2346],{},[66,2321,74],{},[66,2323,2324],{},"Idiom",[77,2326,2327],{},"isinstance(x, collections.abc.Iterable)"," or simply trying ",[77,2330,2331],{},"iter(x)"," and catching ",[77,2334,359],{}," (EAFP style) accepts any object that behaves correctly, regardless of its concrete class — this is far more Pythonic than requiring a specific concrete base class. ",[77,2337,430],{}," isn't inherently un-Pythonic (option B overstates it); checking against a ",[160,2340,2341],{},"behavioral"," ABC\u002Fprotocol is fine, while checking against one specific ",[160,2344,2345],{},"concrete"," implementation class (as in Q13's Version B) is the anti-pattern.",[14,2348,2349,2359,2386],{},[17,2350,2352,2353,2355,2356,2358],{"id":2351},"q16-what-is-the-best-practice-rule-about-calling-super__init__-when-overriding-__init__-in-a-subclass","Q16. What is the best-practice rule about calling ",[77,2354,444],{}," when overriding ",[77,2357,97],{}," in a subclass?",[22,2360,2362,2368,2374,2380],{"className":2361},[25],[27,2363,2365,2367],{"className":2364},[30],[32,2366],{"disabled":34,"type":35}," Call it (typically as the first statement) unless you have a deliberate, documented reason to fully replace the parent's initialization behavior",[27,2369,2371,2373],{"className":2370},[30],[32,2372],{"disabled":34,"type":35}," Never call it — each class should be responsible for setting up only its own attributes independently",[27,2375,2377,2379],{"className":2376},[30],[32,2378],{"disabled":34,"type":35}," Only call it if the parent class defines more than one attribute",[27,2381,2383,2385],{"className":2382},[30],[32,2384],{"disabled":34,"type":35}," Call it only in multiple inheritance, never in single inheritance",[56,2387,2388,2390,2395],{},[59,2389,61],{},[63,2391,2392,2394],{},[66,2393,68],{}," A — Call it (typically as the first statement) unless you have a deliberate, documented reason to fully replace the parent's initialization behavior",[63,2396,2397,154,2399,2401,2402,2404],{},[66,2398,74],{},[66,2400,2324],{}," — This directly prevents the Q6 bug (missing attributes) and the Q11 bug (broken cooperative chains). Skipping ",[77,2403,444],{}," should be a conscious, rare decision — e.g., when a subclass genuinely needs to bypass the parent's setup entirely — not the default, since forgetting it silently produces incompletely-initialized objects that only fail later when a missing attribute is accessed.",[14,2406,2407,2414,2461],{},[17,2408,2410,2411,2413],{"id":2409},"q17-for-mixins-designed-to-be-combined-with-other-classes-via-multiple-inheritance-whats-the-best-practice-pattern-for-their-__init__-methods","Q17. For mixins designed to be combined with other classes via multiple inheritance, what's the best-practice pattern for their ",[77,2412,97],{}," methods?",[22,2415,2417,2429,2438,2450],{"className":2416},[25],[27,2418,2420,2422,2423,2425,2426,2428],{"className":2419},[30],[32,2421],{"disabled":34,"type":35}," Accept ",[77,2424,1489],{},", do the mixin's own setup, then call ",[77,2427,1566],{}," to forward everything else down the MRO chain",[27,2430,2432,2434,2435,2437],{"className":2431},[30],[32,2433],{"disabled":34,"type":35}," Never define ",[77,2436,97],{}," in a mixin at all",[27,2439,2441,2443,2444,2447,2448],{"className":2440},[30],[32,2442],{"disabled":34,"type":35}," Call ",[77,2445,2446],{},"Base.__init__(self)"," directly by name instead of using ",[77,2449,157],{},[27,2451,2453,2455,2456,2458,2459],{"className":2452},[30],[32,2454],{"disabled":34,"type":35}," Require every consumer of the mixin to manually call the mixin's ",[77,2457,97],{}," separately from the class's own ",[77,2460,97],{},[56,2462,2463,2465,2474],{},[59,2464,61],{},[63,2466,2467,2469,2470,2425,2472,2428],{},[66,2468,68],{}," A — Accept ",[77,2471,1489],{},[77,2473,1566],{},[63,2475,2476,154,2478,2480,2481,2484,2485,2487],{},[66,2477,74],{},[66,2479,2324],{}," — This is the cooperative multiple inheritance pattern demonstrated correctly in Q14: every participant in the chain must both do its own work ",[160,2482,2483],{},"and"," pass along whatever it doesn't personally need, using ",[77,2486,157],{}," rather than a hardcoded class name (option C), since a hardcoded name breaks the MRO-based dispatch entirely and can call the wrong class or the same class twice in complex hierarchies.",[14,2489,2490,2509,2564],{},[17,2491,2493,2494,2497,2498,2501,2502,2505,2506,2508],{"id":2492},"q18-a-design-needs-a-car-to-have-engine-like-behavior-and-gps-like-behavior-but-these-are-unrelated-capabilities-with-no-natural-is-a-relationship-to-car-whats-the-best-practice-design-choice","Q18. A design needs a ",[77,2495,2496],{},"Car"," to have ",[77,2499,2500],{},"Engine","-like behavior and ",[77,2503,2504],{},"GPS","-like behavior, but these are unrelated capabilities with no natural \"is-a\" relationship to ",[77,2507,2496],{},". What's the best-practice design choice?",[22,2510,2512,2536,2546,2555],{"className":2511},[25],[27,2513,2515,2517,2518,2520,2521,189,2524,2527,2528,2530,2531,2533,2534],{"className":2514},[30],[32,2516],{"disabled":34,"type":35}," Favor composition — give ",[77,2519,2496],{}," an ",[77,2522,2523],{},"self.engine = Engine()",[77,2525,2526],{},"self.gps = GPS()"," attribute — over multiple inheritance, since ",[77,2529,2496],{}," \"has-a\" engine and GPS, it isn't \"an\" ",[77,2532,2500],{}," or \"a\" ",[77,2535,2504],{},[27,2537,2539,2541,2542,2545],{"className":2538},[30],[32,2540],{"disabled":34,"type":35}," Always use multiple inheritance (",[77,2543,2544],{},"class Car(Engine, GPS)",") since it's more concise",[27,2547,2549,2551,2552,2554],{"className":2548},[30],[32,2550],{"disabled":34,"type":35}," Duplicate the engine and GPS logic directly inside ",[77,2553,2496],{}," to avoid any inheritance complexity",[27,2556,2558,2560,2561,2563],{"className":2557},[30],[32,2559],{"disabled":34,"type":35}," Use multiple inheritance but avoid calling ",[77,2562,157],{}," anywhere to keep things simple",[56,2565,2566,2568,2585],{},[59,2567,61],{},[63,2569,2570,2572,2573,2520,2575,189,2577,2527,2579,2530,2581,2533,2583],{},[66,2571,68],{}," A — Favor composition — give ",[77,2574,2496],{},[77,2576,2523],{},[77,2578,2526],{},[77,2580,2496],{},[77,2582,2500],{},[77,2584,2504],{},[63,2586,2587,154,2589,2591],{},[66,2588,74],{},[66,2590,2324],{}," — \"Favor composition over inheritance\" is a core OOP design principle: multiple inheritance is powerful but adds real MRO complexity (as this whole quiz demonstrates) for relationships that aren't genuinely \"is-a.\" Reserving multiple inheritance for true mixins (small, focused, cooperative classes explicitly designed to be combined) and using composition for unrelated capabilities keeps hierarchies shallow, predictable, and far easier to reason about and test.",[14,2593,2594,2601,2647],{},[17,2595,2597,2598,2600],{"id":2596},"q19-when-multiple-concrete-types-should-be-accepted-by-one-isinstance-check-whats-the-idiomatic-way-to-write-it","Q19. When multiple concrete types should be accepted by one ",[77,2599,430],{}," check, what's the idiomatic way to write it?",[22,2602,2604,2613,2626,2638],{"className":2603},[25],[27,2605,2607,154,2609,2612],{"className":2606},[30],[32,2608],{"disabled":34,"type":35},[77,2610,2611],{},"isinstance(x, (int, float))"," — pass a tuple of types as the second argument",[27,2614,2616,154,2618,2621,2622,2625],{"className":2615},[30],[32,2617],{"disabled":34,"type":35},[77,2619,2620],{},"isinstance(x, int) or isinstance(x, float)"," — always spelled out with ",[77,2623,2624],{},"or",", since tuples aren't supported",[27,2627,2629,154,2631,2634,2635,2637],{"className":2628},[30],[32,2630],{"disabled":34,"type":35},[77,2632,2633],{},"type(x) in (int, float)"," — using ",[77,2636,394],{}," is preferred since it's more explicit",[27,2639,2641,154,2643,2646],{"className":2640},[30],[32,2642],{"disabled":34,"type":35},[77,2644,2645],{},"isinstance(x, int, float)"," — pass each type as a separate positional argument",[56,2648,2649,2651,2657],{},[59,2650,61],{},[63,2652,2653,645,2655,2612],{},[66,2654,68],{},[77,2656,2611],{},[63,2658,2659,154,2661,979,2663,2665,2666,2669,2670,2672,2673,2676,2677,2680,2681,2684,2685,2688,2689,2692,2693,2695,2696,2698,2699,2701],{},[66,2660,74],{},[66,2662,2324],{},[77,2664,430],{}," natively accepts a tuple of types (or classes) as its second argument and returns ",[77,2667,2668],{},"True"," if the object matches any of them, which is both more concise and, unlike ",[77,2671,2633],{},", still correctly honors subclasses (e.g., a ",[77,2674,2675],{},"bool",", which subclasses ",[77,2678,2679],{},"int",", matches ",[77,2682,2683],{},"isinstance(x, int)"," but ",[77,2686,2687],{},"type(x) in (int,)"," would reject it since ",[77,2690,2691],{},"type(True) is bool",", not ",[77,2694,2679],{},"). ",[77,2697,2645],{}," (option D) raises ",[77,2700,359],{}," — that's not valid syntax for multiple types.",[14,2703,2704,2715,2750],{},[17,2705,2707,2708,2711,2712,2714],{"id":2706},"q20-when-writing-class-combinedmixin-base-why-do-style-guides-recommend-listing-mixins-before-the-primary-base-class","Q20. When writing ",[77,2709,2710],{},"class Combined(Mixin, Base):",", why do style guides recommend listing mixins ",[160,2713,2259],{}," the primary base class?",[22,2716,2718,2727,2735,2741],{"className":2717},[25],[27,2719,2721,2723,2724,2726],{"className":2720},[30],[32,2722],{"disabled":34,"type":35}," Because Python's left-to-right MRO ordering means earlier-listed classes take precedence for overridden methods, and mixins are meant to \"layer on top of\" the base's behavior, intercepting calls via ",[77,2725,157],{}," before they reach the base",[27,2728,2730,2732,2733],{"className":2729},[30],[32,2731],{"disabled":34,"type":35}," Because Python requires mixins to be listed first or it raises a ",[77,2734,359],{},[27,2736,2738,2740],{"className":2737},[30],[32,2739],{"disabled":34,"type":35}," The order of base classes has no effect on behavior, only readability",[27,2742,2744,2746,2747,2749],{"className":2743},[30],[32,2745],{"disabled":34,"type":35}," Because mixins must always be defined before the base class in the source file, and ",[77,2748,169],{}," statement order must match definition order",[56,2751,2752,2754,2761],{},[59,2753,61],{},[63,2755,2756,2758,2759,2726],{},[66,2757,68],{}," A — Because Python's left-to-right MRO ordering means earlier-listed classes take precedence for overridden methods, and mixins are meant to \"layer on top of\" the base's behavior, intercepting calls via ",[77,2760,157],{},[63,2762,2763,154,2765,2767,2768,2770,2771,1060,2773,2775,2776,2778,2779,154,2781,2783,2784,2786,2787,2789,2790,2793,2794,2796],{},[66,2764,74],{},[66,2766,2324],{}," — As demonstrated in Q14, ",[77,2769,2237],{}," produces the MRO ",[77,2772,2141],{},[77,2774,2096],{},"'s methods (including ",[77,2777,97],{},") run ",[160,2780,2259],{},[77,2782,1452],{},"'s and can add behavior around calls that eventually reach ",[77,2785,1452],{}," via ",[77,2788,157],{},". Reversing the order (",[77,2791,2792],{},"Base, Mixin",") would mean ",[77,2795,1452],{},"'s methods take precedence instead, likely defeating the mixin's entire purpose of augmenting or intercepting behavior. This ordering convention is why nearly every mixin-based library (e.g., Django class-based views) documents \"mixins go first, left of the base class.\"",[2798,2799,2800],"style",{},"html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}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":454,"searchDepth":475,"depth":475,"links":2802},[2803,2804,2806,2807,2808,2809,2811,2812,2813,2814,2816,2818,2819,2821,2822,2824,2826,2828,2830,2832],{"id":19,"depth":488,"text":20},{"id":89,"depth":488,"text":2805},"Q2. In single inheritance, what does super().__init__(*args) inside a subclass's __init__ do?",{"id":175,"depth":488,"text":176},{"id":296,"depth":488,"text":297},{"id":365,"depth":488,"text":366},{"id":437,"depth":488,"text":2810},"Q6. What happens if a subclass overrides __init__ but never calls super().__init__()?",{"id":673,"depth":488,"text":674},{"id":751,"depth":488,"text":752},{"id":1094,"depth":488,"text":1095},{"id":1266,"depth":488,"text":2815},"Q10. In Python 3, is there any behavioral difference between super() and super(CurrentClass, self) when called inside a normal instance method of CurrentClass?",{"id":1364,"depth":488,"text":2817},"Q11. A mixin is meant to add caching to any class in a cooperative multiple-inheritance hierarchy. What's wrong with this __init__?",{"id":1590,"depth":488,"text":1591},{"id":1786,"depth":488,"text":2820},"Q13. A function accepts any \"file-like\" object and calls .read() on it. Which approach is duck typing, and which is its rigid alternative?",{"id":1971,"depth":488,"text":1972},{"id":2265,"depth":488,"text":2823},"Q15. When should you prefer duck typing \u002F isinstance checks against an Abstract Base Class (ABC) or collections.abc protocol over an explicit concrete-type check?",{"id":2351,"depth":488,"text":2825},"Q16. What is the best-practice rule about calling super().__init__() when overriding __init__ in a subclass?",{"id":2409,"depth":488,"text":2827},"Q17. For mixins designed to be combined with other classes via multiple inheritance, what's the best-practice pattern for their __init__ methods?",{"id":2492,"depth":488,"text":2829},"Q18. A design needs a Car to have Engine-like behavior and GPS-like behavior, but these are unrelated capabilities with no natural \"is-a\" relationship to Car. What's the best-practice design choice?",{"id":2596,"depth":488,"text":2831},"Q19. When multiple concrete types should be accepted by one isinstance check, what's the idiomatic way to write it?",{"id":2706,"depth":488,"text":2833},"Q20. When writing class Combined(Mixin, Base):, why do style guides recommend listing mixins before the primary base class?","md",{},"\u002Fpython\u002F13-inheritance-and-polymorphism",{"title":5,"description":454},"python\u002F13-inheritance-and-polymorphism","gSCxefWeTLWl6YSf_UWfAUbfIhbNQb8du-mR4Y7YNi4",1787335398276]