From 77c8d29954f2d383f2d74cb5e684ac8126621e12 Mon Sep 17 00:00:00 2001 From: Janis Lesinskis Date: Mon, 1 Oct 2018 17:01:45 +1000 Subject: [PATCH 01/12] Start writing Python MRO article --- .../tutorial-pages/2018-09-30/python-mro.md | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 content/tutorial-pages/2018-09-30/python-mro.md diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md new file mode 100644 index 00000000..467a1af6 --- /dev/null +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -0,0 +1,102 @@ +--- +title: "Method resolution in Python" +authors: + - "Janis Lesinskis" +date: "2018-09-30" +tags: + - Python + - OOP + - implementation-details + - inheritance + - MRO +contentType: "tutorial" +callToActionText: "Have you got a project that requires in depth knowledge of implementation details? Or do you have a topic about Python internals you would like to see a post about? We'd love to hear about it so fill in the form below with some details." +hideCallToAction: false +--- + +Wondered how Python chooses what method to call in complex class hierarchies? + +## A simple example + +```python +"""Example of a simple class hierarchy""" + +class A: + def foo(self): + print("A") + +class B(A): + def foo(self): + print("B") + +class C(A): + pass + +a = A() +a.foo() +b = B() +b.foo() +c = C() +c.foo() +``` + +When run this gives the following: + +``` +A +B +A +``` + +This is mostly what you'd expect, the derived classes are looked up first and any method not implemented is then searched for in the base class. + +## A more complex example + +In a simple linear structure the lookup goes from the derived class all the way to the base class. If the method is not found at the time the base class is searched you will get an `AttributeError` when the method can't be found. + +What about the classic non-linear structure that causes problems, [the diamond class hierarchy](https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem). + +There's more than one path to get to the base class, we have to resolve this somehow. + +```python +"""Example of a diamond multiple-inheritance class hierarchy""" + +class A: + def foo(self): + print("A") + +class B1(A): + def foo(self): + print("B1") + +class B2(A): + def foo(self): + print("B2") + +class C(B1, B2): + pass + +a = A() +a.foo() +b1 = B1() +b1.foo() +b2 = B2() +b2.foo() +c = C() +c.foo() +``` + +When we run this we get: + +``` +A +B1 +B2 +B1 +``` + +We can see that this has resolved the call to `c.foo()` to `B1.foo` over `B2.foo`. + +This thankfully is a deterministic situation that is goverened by Python's method resolution order. + +Since Python 2.3 Python has used the [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) to determine the order in which classes are searched. From 5a3b696b60d04c6fb7dd19efa78480890a972ccc Mon Sep 17 00:00:00 2001 From: Janis Lesinskis Date: Mon, 1 Oct 2018 17:15:02 +1000 Subject: [PATCH 02/12] More about MRO --- content/tutorial-pages/2018-09-30/python-mro.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md index 467a1af6..136810e0 100644 --- a/content/tutorial-pages/2018-09-30/python-mro.md +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -99,4 +99,15 @@ We can see that this has resolved the call to `c.foo()` to `B1.foo` over `B2.foo This thankfully is a deterministic situation that is goverened by Python's method resolution order. -Since Python 2.3 Python has used the [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) to determine the order in which classes are searched. +[Since version 2.3](https://www.python.org/download/releases/2.3/mro/) Python has used the [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) to determine the order in which classes are searched. + +## How to investiage the MRO + +Let's use the langauge features to see how the MRO works in these cases: + +In the simple case: + +```python +C.__class__.mro(C) +B.__class__.mro(B) +``` \ No newline at end of file From 25e044dff1274131e0ce12501305588656ca2df8 Mon Sep 17 00:00:00 2001 From: Janis Lesinskis Date: Mon, 1 Oct 2018 17:43:38 +1000 Subject: [PATCH 03/12] Added source repo and example of MRO feature --- content/tutorial-pages/2018-09-30/diamond.png | Bin 0 -> 11341 bytes .../tutorial-pages/2018-09-30/python-mro.md | 35 +++++++++++++++--- content/tutorial-pages/2018-09-30/simple.png | Bin 0 -> 7050 bytes 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 content/tutorial-pages/2018-09-30/diamond.png create mode 100644 content/tutorial-pages/2018-09-30/simple.png diff --git a/content/tutorial-pages/2018-09-30/diamond.png b/content/tutorial-pages/2018-09-30/diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..36c1b9cccbcb6a84c1e1c4f64db5680a2e4aedb4 GIT binary patch literal 11341 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 c.bar() +"B2" +``` +We can see from this that `B2` is checked first before `A` in this case. This thankfully is a deterministic situation that is goverened by Python's method resolution order. [Since version 2.3](https://www.python.org/download/releases/2.3/mro/) Python has used the [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) to determine the order in which classes are searched. ## How to investiage the MRO -Let's use the langauge features to see how the MRO works in these cases: +Python provides a method on the class called `__mro__` that will tell you the order in which lookups will be performed. Let's use that langauge features to see how the MRO works in these cases: In the simple case: ```python -C.__class__.mro(C) -B.__class__.mro(B) -``` \ No newline at end of file +>>> C.__class__.mro(C) +[, , ] +>>> B.__class__.mro(B) +[, , ] +``` + +This is what we would expect. + +The diamond case: + +```python +>>> C.__mro__ +(, , , , ) +``` diff --git a/content/tutorial-pages/2018-09-30/simple.png b/content/tutorial-pages/2018-09-30/simple.png new file mode 100644 index 0000000000000000000000000000000000000000..8ba36ba3b2e833da3382db86cdec248a9afff6d8 GIT binary patch literal 7050 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 literal 0 HcmV?d00001 From 242dc31b018bedee08191769c367c15f424e5180 Mon Sep 17 00:00:00 2001 From: Janis Lesinskis Date: Mon, 1 Oct 2018 18:35:27 +1000 Subject: [PATCH 04/12] Added info about monotonicity --- .../tutorial-pages/2018-09-30/python-mro.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md index 7cb02ad8..9b4ac276 100644 --- a/content/tutorial-pages/2018-09-30/python-mro.md +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -18,6 +18,16 @@ Wondered how Python chooses what method to call in complex class hierarchies? Sample code can be found here: https://github.com/CustomProgrammingSolutions/PythonMRO.git + +## Figuring out how what method to call + +In an arbitrary class hierarchy we have a graph of dependencies that overall specifies the behaviour of the classes. + +When we call a method on a class we have to find some way in which we will look up which method to call. +To make this work we have to make an ordering in which we will check classes for the methods. + +What we have to do is to perform a _linearization_ of this graph to make an ordering with which the interpreter will look up the classes. + ## A simple example ![Simple class hierarchy](simple.png) @@ -136,3 +146,15 @@ The diamond case: >>> C.__mro__ (, , , , ) ``` + +## Monotonicity + +In the case of multiple inheritance there's a subtle edge case that any sensible methor resolution strategy will have to handle. + +A definition: + + A MRO is monotonic when the following is true: if C1 precedes C2 in the linearization of C, then C1 precedes C2 in the linearization of any subclass of C + +The reason this matters is because we need a situation where adding any new derived class doesn't change the lookup behavior of any of the base classes it just derived from. +This property of monotonicity is very useful because otherwise we would get very annoying bugs where classes could change the behavior of other classes in a non-direct manner. +The C3 linearization that Python uses has this property. From 9194c33a098b1e1891e55c4ded47c3bb0321fe9f Mon Sep 17 00:00:00 2001 From: Janis Date: Mon, 8 Oct 2018 03:56:01 +1100 Subject: [PATCH 05/12] Update MRO article --- .../tutorial-pages/2018-09-30/python-mro.md | 61 ++++++++----------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md index 9b4ac276..f0435f9f 100644 --- a/content/tutorial-pages/2018-09-30/python-mro.md +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -14,22 +14,30 @@ callToActionText: "Have you got a project that requires in depth knowledge of im hideCallToAction: false --- -Wondered how Python chooses what method to call in complex class hierarchies? +Wondered how Python chooses what method to call in class hierarchies? Sample code can be found here: https://github.com/CustomProgrammingSolutions/PythonMRO.git - -## Figuring out how what method to call +## Figuring out what method will be called In an arbitrary class hierarchy we have a graph of dependencies that overall specifies the behaviour of the classes. When we call a method on a class we have to find some way in which we will look up which method to call. -To make this work we have to make an ordering in which we will check classes for the methods. +This order of classes in which a method is searched is the Method Resolution Order (MRO). + +## MRO + +When a class is instantiated it calls the function `class.mro` which computes the MRO for this instance and stores this in `__mro__`. +We can use this to see the ordering. + +[Since version 2.3](https://www.python.org/download/releases/2.3/mro/) Python has used the [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) to determine the order in which classes are searched. -What we have to do is to perform a _linearization_ of this graph to make an ordering with which the interpreter will look up the classes. +You can change the `mro` function via a metaclass if you want. ## A simple example +Single inheritance is the simplest case we will encounter, consider the following class heirarchy: + ![Simple class hierarchy](simple.png) ```python @@ -64,6 +72,15 @@ A This is mostly what you'd expect, the derived classes are looked up first and any method not implemented is then searched for in the base class. +```python +>>> C.__mro__ +[, , ] +>>> B.__mro__ +[, , ] +``` + +The lookups are as indicated by what's found in `__mro__`. + ## A more complex example In a simple linear structure the lookup goes from the derived class all the way to the base class. If the method is not found at the time the base class is searched you will get an `AttributeError` when the method can't be found. @@ -122,39 +139,9 @@ What about `c.bar()`? "B2" ``` -We can see from this that `B2` is checked first before `A` in this case. This thankfully is a deterministic situation that is goverened by Python's method resolution order. -[Since version 2.3](https://www.python.org/download/releases/2.3/mro/) Python has used the [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) to determine the order in which classes are searched. - -## How to investiage the MRO - -Python provides a method on the class called `__mro__` that will tell you the order in which lookups will be performed. Let's use that langauge features to see how the MRO works in these cases: - -In the simple case: - -```python ->>> C.__class__.mro(C) -[, , ] ->>> B.__class__.mro(B) -[, , ] -``` - -This is what we would expect. - -The diamond case: +We can see from this that `B2` is checked first before `A` in this case. This thankfully is a deterministic situation that is governed by Python's method resolution order. ```python >>> C.__mro__ (, , , , ) -``` - -## Monotonicity - -In the case of multiple inheritance there's a subtle edge case that any sensible methor resolution strategy will have to handle. - -A definition: - - A MRO is monotonic when the following is true: if C1 precedes C2 in the linearization of C, then C1 precedes C2 in the linearization of any subclass of C - -The reason this matters is because we need a situation where adding any new derived class doesn't change the lookup behavior of any of the base classes it just derived from. -This property of monotonicity is very useful because otherwise we would get very annoying bugs where classes could change the behavior of other classes in a non-direct manner. -The C3 linearization that Python uses has this property. +``` \ No newline at end of file From eacb49f399576ea79c52acbeed30d7a454ce33d5 Mon Sep 17 00:00:00 2001 From: Janis Date: Mon, 8 Oct 2018 04:36:26 +1100 Subject: [PATCH 06/12] Comment on non duplication in MRO list --- content/tutorial-pages/2018-09-30/python-mro.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md index f0435f9f..38d0043d 100644 --- a/content/tutorial-pages/2018-09-30/python-mro.md +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -144,4 +144,8 @@ We can see from this that `B2` is checked first before `A` in this case. This th ```python >>> C.__mro__ (, , , , ) -``` \ No newline at end of file +``` + +Note that this does not contain any duplicate entries. + +## The role of super From 30755460f019aecb9c6a0fef5288b32aebfbc2ef Mon Sep 17 00:00:00 2001 From: Janis Date: Mon, 8 Oct 2018 04:42:20 +1100 Subject: [PATCH 07/12] Reorganize --- .../tutorial-pages/2018-09-30/python-mro.md | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md index 38d0043d..1fc455af 100644 --- a/content/tutorial-pages/2018-09-30/python-mro.md +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -27,10 +27,25 @@ This order of classes in which a method is searched is the Method Resolution Ord ## MRO +[Since version 2.3](https://www.python.org/download/releases/2.3/mro/) Python has used the [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) to determine the order in which classes are searched. + +TODO: rule of thumb about how this works + + When a class is instantiated it calls the function `class.mro` which computes the MRO for this instance and stores this in `__mro__`. -We can use this to see the ordering. +We can access this `__mro__` attribute to see the ordering. -[Since version 2.3](https://www.python.org/download/releases/2.3/mro/) Python has used the [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) to determine the order in which classes are searched. +Note that the `__mro__` attribute is read only: + +```python +>>> class A: +... pass +... +>>> A.__mro__ = [] +Traceback (most recent call last): + File "", line 1, in +AttributeError: readonly attribute +``` You can change the `mro` function via a metaclass if you want. @@ -70,13 +85,13 @@ B A ``` -This is mostly what you'd expect, the derived classes are looked up first and any method not implemented is then searched for in the base class. +This is mostly what you'd expect, the derived classes are looked up first and any method that is not implemented is then searched for in the base class. ```python ->>> C.__mro__ -[, , ] >>> B.__mro__ [, , ] +>>> C.__mro__ +[, , ] ``` The lookups are as indicated by what's found in `__mro__`. @@ -146,6 +161,8 @@ We can see from this that `B2` is checked first before `A` in this case. This th (, , , , ) ``` -Note that this does not contain any duplicate entries. +Note that this does not contain any duplicate entries, this is actually guaranteed by the algorithm used. ## The role of super + +TODO: super \ No newline at end of file From d7ab3a30b243d7157a1e7968659baf755e6954d7 Mon Sep 17 00:00:00 2001 From: Janis Date: Mon, 8 Oct 2018 19:01:30 +1100 Subject: [PATCH 08/12] Added rule of thumb for MRO --- .../tutorial-pages/2018-09-30/python-mro.md | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md index 1fc455af..269cfb86 100644 --- a/content/tutorial-pages/2018-09-30/python-mro.md +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -25,15 +25,28 @@ In an arbitrary class hierarchy we have a graph of dependencies that overall spe When we call a method on a class we have to find some way in which we will look up which method to call. This order of classes in which a method is searched is the Method Resolution Order (MRO). -## MRO +## Python's MRO [Since version 2.3](https://www.python.org/download/releases/2.3/mro/) Python has used the [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) to determine the order in which classes are searched. -TODO: rule of thumb about how this works +In a single inheritance case you just look recursively at each base class until that Base class has no parents. +Given that every class in Python inherits from `object` that will always be the ending point for the search. +Multiple inheritance is a bit more complex, the [documentation on inheritance](https://docs.python.org/3/tutorial/classes.html#inheritance) has an example of how this works with a rule of thumb that should help in understanding the process: -When a class is instantiated it calls the function `class.mro` which computes the MRO for this instance and stores this in `__mro__`. -We can access this `__mro__` attribute to see the ordering. +```python +class DerivedClassName(Base1, Base2, Base3): + + . + . + . + +``` + + For most purposes, in the simplest cases, you can think of the search for attributes inherited from a parent class as depth-first, left-to-right, not searching twice in the same class where there is an overlap in the hierarchy. Thus, if an attribute is not found in DerivedClassName, it is searched for in Base1, then (recursively) in the base classes of Base1, and if it was not found there, it was searched for in Base2, and so on. + +When any class is instantiated it calls the function `class.mro` which computes the MRO for this instance and stores this in `__mro__`. +We can access this `__mro__` attribute to see the ordering with which any attribute search will use. Note that the `__mro__` attribute is read only: @@ -51,7 +64,7 @@ You can change the `mro` function via a metaclass if you want. ## A simple example -Single inheritance is the simplest case we will encounter, consider the following class heirarchy: +Single inheritance is the simplest case we will encounter, consider the following class hierarchy: ![Simple class hierarchy](simple.png) @@ -154,14 +167,16 @@ What about `c.bar()`? "B2" ``` -We can see from this that `B2` is checked first before `A` in this case. This thankfully is a deterministic situation that is governed by Python's method resolution order. +We can see from this that `B2` is checked first before `A` in this case. +Dealing with multiple classes on the same level of the inheritance graph is a deterministic situation governed by Python's method resolution order. +(The rule of thumb states that left-to-right is the order of classes) ```python >>> C.__mro__ (, , , , ) ``` -Note that this does not contain any duplicate entries, this is actually guaranteed by the algorithm used. +Note that this does not contain any duplicate entries, which is guaranteed by the algorithm used. ## The role of super From 8a36a61b096ab0cae0cb313f4e4bd65877b3a610 Mon Sep 17 00:00:00 2001 From: Janis Lesinskis Date: Wed, 10 Oct 2018 14:35:20 +1100 Subject: [PATCH 09/12] Update diagrams --- content/tutorial-pages/2018-09-30/diamond.png | Bin 11341 -> 15121 bytes content/tutorial-pages/2018-09-30/simple.png | Bin 7050 -> 10832 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/content/tutorial-pages/2018-09-30/diamond.png b/content/tutorial-pages/2018-09-30/diamond.png index 36c1b9cccbcb6a84c1e1c4f64db5680a2e4aedb4..4ba9547eadcadcc9fd659a05610abf3a540d3a77 100644 GIT binary patch literal 15121 zcmc(`2T)bpwyrw?B}vXX3y3ILa?S_{hzL_MNScBuNe}^%97RNO7ExgmBq>pnfD#2k zGKgeJ0)oWX#@^?>v-i8F-hH?3sk&=bE!SE#nT*j#@2&mq`~MMXpsz_v%tVYrp-8p0 z)QsTI3KRJ<4qr=c(rh2lVIt0@~l$XLttHKn;ZRuiZv zd6*|29Q3}7DEO+%5Q?&yFikgzA(_#tC&Ga$**=fayy>;wP}`Ylsg(D+FAS+8MR2$c zHT@^gDpQ*05o(Mok1FGs`8{e>WMD8f9x73o{N`nqJVKkU|7|i}Q9t{w%&!rqUGp}@r@g^HPZpAZf=)<|Ni|nJv}-&7}wa?*fZph zc7hg9SxrrNMTMB0oZQUvG7&jBISG?Ep=vl;XliO|nBv($N+L(GT8#oDPBAg+uCA`m z&d!g2w-*hKjBrt96%|jy!!cPo2VXDL&uwgE>+S7*u+>g4;=k{X{ESfjChp>O zJT4XZw%%;T=`B9E+@78ucOM^3Cnx@s&2UBQqx~&m35oe3^>~UF^Xu22goKdts!GB#@Yw5U zD?YGoe`}62fnldu1jjxnLoqPRp)X61j*iaW%}sxHc6R4@Z+dXD&d03CD>_~B?$=MT z%*zGImRt#1YWn*6m7dE+0v9gWU_V7Ycyez0DOpQagw+`?1)Eu zlRiJ^=hdkqLmYZDv_nHfi>oTnp0=8snrbB^B%BH2;^JCr2|ZVwB&GSr_-k*bY}epm zVs}rEb5EMY(Ad~#bTnq4*&#_sT|`90-o{3GYHG^!X#d`@4qEea@^xKZ5;HXVSz#ex zroyANDyrm7v2I#gS{gb!4PIW}oi4uYr@Fj$*tX}-o>38#lk-KYsbu^ACVFEmFsx(# zu}QeFurM((k@~}j4~7~V_!!nqWvs~{tW8&2Tgaz)_G_f1q;MmoO)dUQ{haSAD_<%e z&60aA_OcGk$Y?t_@JdTdCuC={-!L(GH$1?zRc|Iy ze2fbIQbyOW5A^p38Rl!`=H&%fJ^M7%PWy3Z$Fu(E_m>oD58moKqqqrLZD{SqH^s$j z1_l)HvyWkWc@-}W+U=a)_jY!^5Jt`(m%y$0W5g;j)Kt&``%)4Xms41n;_>6hTDrPJ zd&){pchkAJ>W}}7!*OW6rg+SA<}cCK=H^GCrla7%)5GcSjgMq8nU3Mh&yN}Z{u#fk zEl79W&#!iPucr{NTRoc2FrH0*X`v^*_(s;*WBK%fu`wNFhgdh`V%M(c8uS-t2j~bj z>`+Cv|LAB8{MngM=`_G~DMg+cw)fAK6`hU7!^@Z?N9DjihhGyPsJ*dA=-UD$B_$<0ib@-!TEodb-aT^7Nw!f4IFi!U)umuzDc*7&85yzL`q6G$ zeTOkGKVQUcLP||j)5o{f1%=4V$TYHXcd&Tof*p*J)7>C>lido`7n z9K5{vfq%bP3B$1u2@B)8c(G`1(Pv|-eXI(z1?R^0vbDX6BD0A zMG<#r%HEvIW=6pliys;?7MGNSYwNW+p4=2KMps4o`}>PGPKJfy|K8bod85e0tKP)S zOgk$p3t8WqyVJaRr}|=af~HEEaV)u|jR#SJf`U*EA}(7s>fZm5p`Rh8jDk{DWOwUs z)A1FHI&bXUhK-HQ&zTve-Q8WDWA+O<7%Cm7S`% zH>ZKCB<9e~kyjlmzZWJXFQ19>{JZ$^Fjw`gpXI-ZoGgnqtA|eij zZ{D~;iIVaC&Et4DLvfrTHr?(LLb)$=r|OrEfB)`zv$tiqvrc-RCldwt8)%nS#` z#LQgvPEjvE*=GG)5xt9xi+H02cYgJK8d_Q}zXo_@sLjsyt7{v}Bc)c!iltbrIxLvx zM$ALQH^#4vi_i35A$L?iY%X~61Wzp7QCX<<*V0nN@89=h@76pzqwrwUx^QH?Z!Ih= zOkwBLHSpSl2M>}J_x}7@mqOJiXJoM4nW|@O4I{-v`Ty?XGbsATswgBNpkicX)G?i; zbK6I;m-@Pi3I0q|Q;HwKpjq$r`#Vd9xJvEq?M#zy*RNCmJvcDRR(K@SlfKxOeGSe! zJj2L{&hhbdl!2@3CCaLv_{E-dO(>`@O^Res6eq+wT%DacZ{EC#t8}+vmkxP$mHvP4 z6Q4Vme{kUUxv!7!+_`hON_L-Oa(mJx2cu{&I{o=I%1RKjzP=7sHg~IUviJ04j;~=nH~^F>r32;RumWQ271qq=YJ4I5T7I zceqxw3_Yh1zCO|D&9BN!6FwhJpy*RlQrcrMR~sJgz4Dpz4S)OgtxQ0`{AXGwNjH|= zU!#c`nVHVb!Dlmvg9L9?$FQ)nI`?JCGo4PTxjNo_rI-GxtGY_5e(Ew#rnobefPjDu z*_bD3lFr#kHC#nSMf3OWkE?p^;HuhS{_2aF?o=@?J-yr5 zuaSSsbB}|1zkN$8(61RSv%x#~vlbmm&G*j4*JbBQw@~9gS8#A}*`3jM`UJYgj5415 z3Mcz^_V)HDR9;>l1G9V87;@&^ z+}voGna7ud4CrAu(a_MS^~vv8eme2wZ-d$yev< zyVG%9iF|g$#b*0EgV)Sfoydlp^wVCxdKGqbeB3oPl|{y`(2dqyG~lP%IX#&^tsAjNKh_q_``&g1N-rFZ!dI9QWEZNHPWO6_u+6j)-BN!5#dXtfMC)B9ii2p;6-5B z!hnE)va&Mkg^@Q<~?nD7Xf(#DK17F|f)>gdZgWW+V=E;SHg}Cr$M@PpwP-O4jXK~%8 z>WRutV`f{!xdjDDa&vPDNl0jLCm1=qx`-QC@T8XDxGJ;{twnBKaj%9W5)P;eHD#X=2yU0SMXXUF~d%NIjXzi`LT zpFf`&#@>QPOSLiG6xi`(ahzR6NN(&$0-;R+lM4oukenPoF<}mpCl|&J(0Q**N;LHJ zNYQAtft3|`4t6pbjSc(oLAtxUnUtLSYrKXWZt?b=w!82Roh24^GQHmXG{o@#^IaKJ+2#YB5 zSk%`rInpE)BRGO%%G!{%p^i1-mX~LRCP7lXA5Y;x_Wgs$qG~oZe}We1lbqY!txALy zVO@QF9rIt3>oSD!TzgtV-{8aeHY{A{z2;}Xt<0rjVq(%!aqWzFIE4c#H9b8+sLIy& zz4nd{O!KF*{<)KaT5W4*$!f7I-kI zy4a7)q-rX`_mMqB_}nHwXE$!WGGPVkE=7yrN9O;N|I6u0iL$W(t-!^LhGu4wvOepe zKsmX&@lfuYGs-DxX)O~IEb5(&&PnT>z&zb09J7s;8-`kx=VqR=yQ=_V#MP zFbDmL?cn*F5@9j1C(+U8>g(%;q51D09JKWHkt--DP(-S+1mIde;|Te{{Q8?qhO7^n zwzf8Mh(*Q3I1{@#l5}KMmgeWr^6~LW$;#%#4tlCnAS@~x46_^$6;WDxI(({sY%B_v z`*~7QZhbvVK|w)hSC_K4_Z8S=_#e#49zJ|{=ImLU?i3N&tZGdG$EL|j>@ZvNfBpKk z44NLYHE-X(jSQPwT7s*OlOZ~a3;t&7afn}lB z=ArVNiE5qM>nY@}JQ~c&WM?TU%Q+ zOiVgl2@zprtUB;tpjga`mWfqTZV1r2PSz&<`t_^x)2A?#VpHX+s;c5Dwyw}~^!%ct z&!7s%vPeG@6%{qTxQrXdx^RyEaz6~6o!`Hw&|N~m+~#b|j;0qff?H-}WE`0I;IRxe zqBzOaHpRxI=o<|+wd$u&pTzxkoNE1c1uzAL8d#I-=H@JLnMQD^FI>75TSaw|M5r4^ z7I7E^M6X<6mprZE!*krP5&cy$(+Mp7Xmq3#T6>eZ1_M{FxCQGKS^-N{;7*m3_*5Jkcr!^3oNY}!Dt z8JL@Qqr=4>FgjGBW50hl?M{~@e{}fgHa4Fcq!@zTrzlN3F2Dn;UB^41SK;TDbdl<%4(axf7`BXjbTcG4cLJg1tA1j zsRJ~R`|iq(SC)7LWNK(M(?5R#1Lune*R3Xr>9peA@$gYAgH>! z8Z}npSIz^4OErw-ae6wlNr^cTNSId&YeU1szpE3eHd-bW8lWjUtccisB7tUv>=D%1 z<)0|)MwW`&+O)qkF&7_5_H6F#guuzXY*Bj#AeRH%{QSI=lhen6d`&|@VzA;UC+70Z z%*<4a)cOZoTwx@PE%wvqt#t{bLqjxuil=hGp<0LRCTqRQ%FCO7&wrU+Uyp+>lMh19 zw8o7U8h(ltCFR$_!PM;PpTw3WX}3PyKi_z`E(`OPvLIc>@Bky!A4)2!;NoII5;nP% zs<>CPi*G-`*ft9i0MRrU+Du!J*9;=IXV{;R1ceWhpxiw?T9*d$DVdqSpw%7U`)>2X z(DDReVtN&^pGi5@j15a6By?Ryb^*(6&k}HTx zLj!}L?Zv*GBLPP5nu}luo!%$X9v6bh|B}wEu_q0lGFawRsny{V_1178XnSv z{6elHS2cWp0@x2h(Av)0IQ^{}w|02qTibn#aC0&)RZND4hCoHz_ND{-7CG={X4Ml9 zQ)RpafN+Jse$BtL^6ea;z1!HA5+^WHab37T1jD@Y##DpZsylgNdP`M|PC?%CU|}Nk zg-oe?!Bu37&`;3s-8m!MZFO{YL4RM`pOl=lgcGWlDU+nDr{@fHq}WSJl{aw!5#)fd zKo_^8HPadNQzFMSmX?;Bs3O%6*7xkoJYX#ys0e5A@t?)U#_G$rs9c4jHa=SI%8U>- z5Wui0%7+J#f`SZejg5_dlXAz5!rj8ul=DA-_LteTc1}!Wz}%n;dagJrD+)L+!q`wq zYXE-YfNdjgB^5Iqm-7RCX@C2+IvX1s4LyCKBx!BY+qX{3Ukea82~9JspJD4BgLld} z)ZhYGoM&1*2s4!R{+09M1>G>(0tRIjDDAwk*+I7FKpmOtInJiy?B08po_$1`d7XD1GxJ;_SA7N29ztjOG5vd<;Ml z8I3=8cMpw;zs${j3{685KEacu1ND9Y6xsy^g)Do~R1=mRl9TGnZ)f1)0;2d{=OaW# zO>Jmy9>XT@XAQCl3WbWA+8KOuwxjO83KM~(&Ym816B9ZrDk><0F(8qlfIXJgUuu&0hV`LNzL!Hv)WK}^r)dC}%{v2h~Di>N66%~>>(Mksp z2s{8rxum2RKv6uHPr3>H_b%1P?Z5n89gzl{+zgQ zsGK_X4i0dWDK*El;*k^!n(n`UYKMe|=2lhhK32GA9@o8BtqC<85p8IE1zqlXV3c#g*FgFgbs0vHIeymR)`2XPb&hx@<yiDGu^7}lr8?`urop8z|#s?diY-M(nxQ9@AC*XE(*%x z;^GH~gq4Nrgxm5+3zob)rRM3mqpFHE;Flt=sHu^RiD5e`q>OHdt@cszWQ!bnrI_nz zQ8b}VBRS|z|39OSa1*UC=)zfM%S)B{|F& z)^Rzz$!9@>b@ufkR>>>fRDj!O%1ue&pTK1G_tw_e$wF0d0NgM$Gy5NHbwtF)X+XOM z^F?~H#T(Nls)Oj|p%%po`}ofEy#2@P-EiUw{~ zX5uRdPj(+pZ26-@Z(vAe&_Y8J7!Q13C?)sR3ac=r;><(~H7db9&|Nm~L>G)lwA&V& zmg530dhfl)1m4ES8O;TtfA2qhm~GgbYE6^Cn6AoE!kz&f#R4l)4##O&rkGM=0SYWM zo1?Y6fp*y6Z48WzHuIm8BI4tbNz!apxFbh%0l0B%PY-D{-KDR~gZJWtBW4yC380_? zwn(lbyGruVJ}xryu^LzN(cf*eA~^}J1j3@5r5dmm5COj`+-|M805kvly1KcIz*AWe z@NMYDR3bvcAY*}ckhEq+Wi9TS3jkM|zka3qhp9jtTjsax!gKyS=lS!YRm5T>_w6qW z35D0y$=cf5Zk`-&K<8!P?YR>C@?<&-l!QFQCa%V(+qCY*^Yf4B@|FXEA3jzryEf`tjSYpeP)Z^o08@S2N=x?&kHR+VK zLD}4h=Lq)Bym#-YeAXu(>lCN}Q+lp*9waEzF2PsY`87%na1h39@;ls|oH$?hFJqx2F5eHHs{G$Kf`~aW%cDiNb=HilP(;AilQsBnTn~HS> zZ1(_;Aq)fzND&W;mFcwuMTKryi}S!TfP4EnNI&`s&MFrSQ;3I`czkYm!~2+>b>aAM zFA*>~5H%-VefCs2U(pZm-#Z;&w0s@NJXw6&+A5gX)j2tt`RZDBiLb1Deo0B(ueCMA zLqd-i8l0Yf?Kx1C>n<-ZN5+Hm=g+6rtOi4Sce<^3?F*n&@ZBBIhqd%8)2VJlO{>C1 z#sVuNrR?gOnjVgtYT!R89PeEBgLH$IAf4i$V_2M*uH)4Mz~4Kkr?aou942(x50zRe zVq((HDKrILn8MF^ zZanvau7Se=93-xX%^oVG0)C(LWPHiDrk5{60G|vmSDhX=s3VaAjBSeD7bbx;OVJ z7tYt~w{O3ubhc*E+=#I^J^8w#lJnpv$=fvGCpPVmoL#C<%gpHZs7jn`xFjIz>)>mq5U6# zaEl-5r+Il?z15{cyNVtQBv6WmODu|RbZCA%eeAsgc_9=E&ZmAstu0t&fDmv{mDSZh zo{%eign@e#tRKweyv_H~(cJ3l7Zq!(s>ew>=M|1NRqsqUvcmk0_VPDAW@kwKzX{3& z+DrK%CyuAwc@TS=t8DQt|0E|Fu2$?TO`sWKSY_!>w-rzGC2G9cZk!UdOiax$z??UM zmJfp}ix#(e{vTgeG#D@+YUktbHcIsDDQnE0-A_6rQ*Xbc! zcxu};K2+4XW*eOLdghU0CIFuVUIPHI}(*K)g#tVx4-Bm@CommvVz>*Tp7lWzm} zT8d#b0bj)4)m0CK)PpOk@=6dLf*yn9X+Y&-SmA^DhYbt=&S$PUz9Hze7frk3%9NUt z;&dFeVMw?eD0pr7tZ{*nAz)!3vFKXQ3yYH8F6nTFh)GCzU_Q$93sI3(IcDz~lwh9z zH$)@f!|NFb(Xn?`Rp)`_W!{~-g!G&f5ehhy;-GOvB_#_bFvCu3w!yD1@bl+vZo1|i`wVVRJuAk!p-d3 z9ASz0#J86!zkW4}ii+Zb!5+dnm3AFunGG&C{s&6ako}N&myb(Nf#B(DY~3LcUnE$C z?7Gcn0vVCh=U?VMXFlRYMMQ9vo9e=2*!jDdeH}&^j6|&M%U_m zYaPJq%!abZ37V(-z$-}rl>~hjs&Za&F$wCw7w5>Vi_$q2ot8G8L?OjjG?fJ8Szurhx_|w#Xh)v9u6;{h*P4dqT9s-jvh2f-|d!w@-b9&QwR_r z2tOytM*)b`8?jK@WdzBIa>Ww6K86RxYP11{!sWRYvY zAuG!a&5o5IBdi6o50rFtVW6<%o-}xeB$$zdZ4hLBd1EI{C07Y}2Bbh_#`L!`0rMk~ z&8J`H$vp#MhW#<`tYaCLS}UcT4`c|9CJqb?1ZpWFJje!-h)>LS>v15LQiVSL*q51+ z0ls+4$Cz6W7#G5G;o}w-r0{WIqRs<44Ap< zHH6MGPdLw05rL(?31}m)tc>Cuo#4#cZMXlC3VjQXc;FkyIOCi$IXMZpiFojKc2D9J zPZ$OU1|WB%4)Y2|9_tR158}m$h)`aCrTbWmCm1{u_$P=|jJ%t*pF}1%Y}bF~J9*Uv znO6&p(BLB2$*x0+1~DenWV~EDFfi_jJAdVYo3L~GbYViUcjU&uv7QVndU{RU@|64c z@0%7mQM=JEt}+1%M$A!TV;Ud_5Kal!DF}uE4Hp-;3`!Zy^E{7}Jr=@koSh>9zF31L z@ZM{c4#TPsG?;*xn7HizJWwQbM~;R=&RSPKED};A8ux#k8cuBtd};L{f&x!<)J!gQRMau?>Jqg^5jYb8I(CQBznUaL$vul{xis^)AsG zxu_67zcn_Wvf6DjYHSQGX!b7TpVR|?-)rbDp`&x{W1F~crE!^9m~uESUnUzVv9QB# z>mtC($;G7wnvq!%0$Ln$T$4sU`s4}V9RHeXNU!R>ZV2-!V7Pi1v`s4uA9fM*p39One^ zg55x#I^Z%K8+$iLn5?vPbX1`4Vv^j--6mxqR{mqsXZkiaPYl6sFrq36(#=8ix%dW~ zwy&==g72uQpMdF-T@_ct5!1c*8z{;gz;=Y+V3IW7{VNXgBnBoI4?-FOnB0i{tCI}= zgx$=?$KUIH#io20A?90qX8fePRtq2w62U>{b*OVT*liS&tJBYtiv$;R``yI>F~GqW zAu(!TX&DE>L?~6mGORxr7Fs$w2*Ac_1%KUib%{wOr4CY}{|mqiZ4*Z}6Oc0KjU?KH1@eD~q6jVuG0+sIt1usz$h- z-=9>vi=-8xhjzfT*@6t1*mnQD5Mf1P3+WlKW;E5+Lwi}Dt}v*iuy*3)cydI!`*Nv_pCnVuR9niWt;FGGbWgvwhJvs9KprLCK!lH^e2<8Db0F*NV z_PzT%@<)x$FGN~!W)hJkoei8jenG(yEY`I!8*<+N|Jjh@zq29NM}mO(|7yP}Ee(fX zhp2T(`Tno7ptC~A3JtkPAkN>*mpmCVUc}4G%V1OhRAG>NAPmYD#KiwrAmoj4)YGRF zu*L9!p)J8Myh^o%2M<{tC6K z*$m^wk=Vr#{u%@v5w{J3C5YPwtA&xUfbbA_px9eA&%i$){r#wffJtoMi&Xn30)zFi$<&Q=x6oW9x@HF%c2ueYn#g2{GCD zD7}j6Dv4M(%s){5k@Sd0JewX&%D1sQLx8=bqNBOtGFPUX6k%Q|H?a+!4gCO&0z%xH zz~Czbj{T;(rHhJ+ma9fAxj_N{GY5g&N{q}PNK_Y6WWLgU#zo(d=rbaI?oP=W2_zLK zRchBai(4T+3M?;@Ee9Q*cP(21G*H}sl?uThv}@%s>G_{!LV`$s)-r6gLZT!FIu0!) zP^BJha`^rE)rHo+2uUH}SU6w(=M-B;zBqS-aF5?KXL68h!{(KyoTc50ph>dNB zun%XF&b`0CZ`Z^2H7&Eo8LY1S4=7S`>_N2A0&(5R`iilN4h81DXl}tI+$` z_s4+L&cPvzh={OWxB~X=lsC=11%h4vkqPN$f#Mnh?DPn{3fA~L``g*4Bq(GK5fjS6 zUWT-jF6;YX9~(DkXB<>Ydb*egk{d&PY;P}^llW(*T}1Ri2>e*+?zY%wqIy}>oefdX z!#}PLWDv|pjj?g(Vjv3QJ*pi^zInNOZ7>=v76-C5*D6F3f#VoA0-WjT^XF|k=ag<) znCdsb5Anf>!3+SKB@$j1paX-7mpUArd=f^{Gf=e|#2iR?_0mG%r3K{0t!xM#4{ByN z{29X_$q!h#RB87!r^625N&i6l4s3xGX>gc0A(@CMpn|K(Wze_5y+n3~?h{=#n3Ws@ z#-2e8MHKHNl#eaw=eZCj1&LM_*Nf0)C}p6GZ6MJMh@bQn(OB=+pbWS}C?0vr5GWS5 zZ6j2`XGD>cqaIh6{)JM)edWrFs;FM~?FBsm%LK@a4@jzLUK|ev&>CL$h=Dgi?0`cQ zd!>kBh6Rx_+;nlIN^DtN;L$+Lpg1%nF7R_1HOwm{hyft=Q`jCu2h zaPo^6w%^Na9)M!sf^_n`VVf3sscIIiFA!5K073ftrWO`)tYx9%w!@HB?z`=Pywp|f zRT+oIYJlK`mbL|eYg@V#_2B)Lxqw&tnNe^UIRylW;hmNi5SV5cons*=T?)#l1&Uig zpv7UCiPj%k?ymX&1|7g-l7=D%jZg~~53&f5_&OJ`*YlqKgSkGq9Oq$@9&30giDB)9 zOp!R;1d=NUmr32JF=B|`ON z$)`iM(d=S*i+ii?(3N;g2-3kUm=GRL014J*y(jCC+AmtYOqit z^tcIAaeuAXYA3u9fO-lL{E}5;26U>bE2Pd&PC4*64dLNw7Z^c;M%??CX;geXU#jja zS_1heO_y9H9>c?hUW+(zZEb2GBJ(xl*^ra15zBNIa@G)W+E2}P#2O0#iH`;&lnZtj zq}4vb`N%OTLOf`YRJK3bA{m6OgB%nX6leETxb-|BUa1Mn{3)jpVAKdBNoRAK`E4{vr^A zggJRk__8VnlDd5={|$%$UdGwr?a|1S@dD!c#y literal 11341 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 literal 7050 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 From 3aec7b3ae8efceaaafed1b76f0b854fe6cb978b7 Mon Sep 17 00:00:00 2001 From: Janis Date: Fri, 12 Oct 2018 15:33:06 +1100 Subject: [PATCH 10/12] Mention Dylan langauge --- content/tutorial-pages/2018-09-30/python-mro.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md index 269cfb86..a0ce6161 100644 --- a/content/tutorial-pages/2018-09-30/python-mro.md +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -180,4 +180,9 @@ Note that this does not contain any duplicate entries, which is guaranteed by th ## The role of super -TODO: super \ No newline at end of file +TODO: super + +Super calls the next method along in the MRO chain. +Note that this is NOT necessarily the same as the superclass. + +The [Dylan language](https://en.wikipedia.org/wiki/Dylan_(programming_language)), which influenced Python's MRO development, refers to this as [the `next-method` function](https://opendylan.org/books/drm/Method_Dispatch#XREF-858) which more clearly explains what it does. \ No newline at end of file From 3e5c91cc46f7503f4e3347dc5aa0471df0d01d8c Mon Sep 17 00:00:00 2001 From: Janis Lesinskis Date: Thu, 1 Nov 2018 19:11:45 +1100 Subject: [PATCH 11/12] Mention how everything is a diamond --- .../2018-09-30/multiple_bases.png | Bin 0 -> 13050 bytes .../tutorial-pages/2018-09-30/python-mro.md | 24 ++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 content/tutorial-pages/2018-09-30/multiple_bases.png diff --git a/content/tutorial-pages/2018-09-30/multiple_bases.png b/content/tutorial-pages/2018-09-30/multiple_bases.png new file mode 100644 index 0000000000000000000000000000000000000000..cecb46fcc629f06de611c345dfbff642d9d21528 GIT binary patch literal 13050 zcmY*=2RxPk`~ESKjLhs!8BzAiDk59i$4X^qB#LB3AuE{&WpA=&Q$#rSDtlzBi0tvZ zpMKx}|MmTSRks@va8F%D33ZD6o!XESjY6@ZRF$slc_jaQ=V=-;@{H3IVE!f@N zv+*??!MR&l4E^Hqvu<_I#o6TEtpyRA9;sf>#vm0Xd^`fT6gtikA`&_sS^^QqK1LF2 z@l**yBjP^VAFfhdl;_mc)o+`bh1b?fqZDr5JcCl;qP)&egNLehUn6+@`0=-I--%Fspl_k16rm{WY`c@uuTJZc))0l%BqRT7Ev!#fuktu3UMg z#Bu%lbsS+4kthr%q_B{GXmnJOhx+s2AXQ^y;L}!Qr;`qE5)-?~L;?lF5N@a4-i_4q5v_WkT6)>i}sZfadQ((x+`!dJmh}Je<3U1F(tT`#kjMT)JOvF6fq$y*F2j9=cQNpN z1Ibd4zYYz>XlQ8g$jBr&9{#$PpO(nI zUo-90x~HQftv^GB3iUcTI2G2QG_F-DJUo2+cy~Iwpx`nlA)#-q(jl+0@qH!#hkgr@ z%hW`#U%%$i)zx)<`ZOmn5P#&YXoSY4jNDuv%Fr)AR#(+RLP82JJ__+ktjWy{zM-h7 z%0=0)!s@L=N=jOIQRt$)e9GsR7FDIp*;yN4&`P`vR(KyjQL$>*$a}?YtVy(JnC9UJoka2{dl{d; zMh1t568r2g&>roKJAbQmpmmVaK0kQnkgDu{`}w)8eYe@qXTnE|wDGV|MY^IsLTnscdIg7X>|iUa9mMTpXG!romxhBs|owgWmsMUe4X&zDYzx zG=yeBB_t%=-JJUZw-)cz>r`?gDSM???vTGbK`20V(#grGmBS72K@?U_t20h5>w%-A z=Iz_JlVgf;+{&%4z+&0k^Ig(NXhy$otM)z=hn;4Rx+Tdw-P(%ZD}O2z!F;Vvbw5#o zyF2;K8&uS-z?qr5mGNfA#vvEg`3TRgMa$*BwEV5L)m8Ef7hd`vuUSB`--L=D7#Ps|JvuZr(?TZS zDu24K&2LnK`t<43w|Y;JV8UsiLjhr7VI4iaK=_Qj<60axetwdro_7Iyd<&V+dn}J9 zHzW(um9J%FWQNS0;M~>J)(+(B7wEOW4h`)X9*$*VX3k4be-V5#+HF+r!v3YbeGqo3 z14=wBENre~wj#qWYlNLxRz>ju3zZ0_v~WfV zO4I?I2tBLL1y?9&+SvGbDvDj}E4;kyD7V!i-k#MN^2v1(ST+~eLor_7bEvycPE&Jx zZ`c)4D8M@BNA(V)AM#HlnXl2H-b6*=po)HFXJuwKx3u6X4Xs{aVTphO!9zX!yP9>t z?62TQFJj&N`ST4@!(A6F7K=g+4-YfsX-_U^Vv352ZllrpJFekjiJzmAlE&w%i;4tL z6?GnY`^i%cULW^;jE(7CU0wBRM1I{&(@Cwarc=R zFSE+{@d@1awzewCDVdLql$3v(ryb?EWn}8RcPA$&_3@g$I=+5YaB~x_Z)m_lv3hS) z#HeMh9#2e|GRZ#E`}_F*{rf6cm!f$2`SCZJ$g+DrRm5*4Fv0ui7>-+v4 z13ww|ne09~oIbte;NW29O?gw|tl!_ie;?S}t6BISSB`ak$j?uQa?!E1Xq=SN3!OcBn`+B#+5 z=6pNA{Vg%uL2+uLGx)eT0K6_M0~beJS=6+&&L8|;3zGHPnOTUpuohT))HiuCH7Y7f z()UEB=iRk-v>I{Z_^U;ncNrO+>Qc}ck-$GH4El>pB}153!N7zLzF74 zx@bo3=oOmP#UYiZrKMG2H<(R>cf(OBO$YuWKb~hj)gg6pr=Da&O?9mf7pU^n3@&uV z8>{!Lj(jjv=ZFgaU|RDTa5MeTI0(FEjMo5V526&tPE1R$;+45@(Kv( zJFa-mwVwO2xOjt&Jk|H~1iI79$Vf8i2{UtZF97EX#KJ!SUN{n@yni17)N6JiOC4#N zd(Y*bdwWwbFuaCu2RcDVGC>)DVO4f=x&lncWpnPPX|3D2_^TGmo}N+&z5mqTPx0i* zlak8Hn~^NCckkcFgJ;)gzy-EXh>troJe=0p$fA}-35_TB!-uxXx~G7@L?KEqj*gyB z)I2_`pqu!j(fcr8{Jry3;8aQF%{n^l5znoxJ7Fxc4Cl_BOOSTw10n}}{2aU~J)HxV zDkd&2{lkaz@R2CL{CqxGdY}%?-@eh|`lA*X7X>9Gf&kPXK70tb6YyTv>+_c{XSNo* z6(2nk0?Hc(WJ|d5-n;ZIC;Zb~Jp+TcO-=IW@Nsb!u02_w$$SsJut1m@x_?Bp^fvXe zkyyLfg$ozx#2?bZ3g~%W20bE~*VWyvIZSI_<9d;UlT*L<0)s6pEYl762B?9kxVRAx z9AZOjSQvw>9S)9%6V()O1B3ZXOqCY`Fyrj<@~l2SK3}oeK+`LR%(Nj&E-o%JnOZhB zHeVkI5BI`)U3>bgHHKGLvfDb73|0gMEr}c|7+$Ur6h_JX9n#IOcU#RaqOnNRnOREl zZA%ckuVZ1+tJ-kj_X+C=UDE%006|)AZfBQ`* z?d|O)3oPP=687b;nAHXXpVQORtJtr+LQT|PY$4yXDj_7~Us>s%^jl0^oCErDT3T9e ze*T#yiYW!sq7Z)^e||t(DtoXlqk8t@oe+;**~wL69hz zu+NgMne?i*w)V+cG~h)!Cd?XcY1+v;4K6*}UrPB_Vu_a{?M51a`8~Tk?c2V$Isa*X zbIfdaW_=x-cizTk>FjwyppUKhghmRD1IXm|{B)UXUwy*v&iwink&r-_nU%%P!GViH zV-kCpGPG0Vl2<`xIf-ph6XKH-y+i=}wvLV;yiuXjF~I*4iM10RG*^v8(Q|+}8=IRr zsNvB@z?7weVc255r^kUe*g*h5Iau1;zs^#Rw|^K(Wd_1kT!)9+sNtEIx#z+K(`pwS z5FH>5@%r5AFb?p}=J`!Faza6`orgbu{Fs4fIh)ek4*W=}*uuuLPF(5Q{>kC*klv+_ z&y+WY@^syxdxhHuhlJQwPPQPj#M;_g&(yS#f>ip|tZMY(Z64~4?d?D~qmBEEj3cgS z9TO8`SZdG;4a3Uv1a6X#1hK3XsmAc(uiLfRGQr3y2x;k4#7!KnpNXj zj0VBer%%I}q$tNfI@<{3Xs)iU&91J#hK|a3&?_KRf!#%f05uKGz5PE6!28L8p75Jg zk-+7KKV@xG&nb2tS-9nWaX2A3M@-y8Yw`ROI-=^XEhg!El_O(kXD2y5eFwTzks?IN zhj^$z4~Q zO5$4H_Dl+&0^fOci|aEq1|xOPhk(Aw2@5z&mR}|LtI%yM&X^;r`TKWz*5?~IG*`{B z=pL&1rKPi%FJEqLYb%TU{JLjcxY(kJXynm4>7-| z8i=8~m2TdgE&4bG59vt4EKLn~#jTZmSK#HDcjZSoW(eF?p#t?ew)@%lq_Vj>ZAVkQ|6^80OJz&3QqpUdH^Uj5OlXqO~aZ_PZ;53gF>-=_%JXpkGIxs z1(%A7%I)_QGbrwoii(H&%3ujy(o75-8q)Ld@)D^g`f2@lb@*GE6>(X4xrrlpTEw16 zU^oWU=$p51UjVJ11C<3Er($4013Q|k!y|1PQCcbl`sj>=goF&RMu3!7IAOEE2D}e< z9(kOpRfmcLbt&Y&s#jfIohy4HCnvYDv2piNj=qSs0blH1ukT3!cp7tH;oMSHy{@Q; z#}7>7y36Co0f3rJOiXtj9EjD`)#>QzKTS+9!P&l(M-9eHZgH^+kOd-Q;zyvFsHv&h zI63iFR#vKgj-^4&6c!eeGcko(w!E?g5wkp5CovkIJ3PU93eFZZ!=5>3sEO26HqG`F z6A|u<7cG0=%kKRhwYY6$L`14sVJ(?|AI28zYSgD&acl=l9+_#$l}T zEKn3L0|EljYeUx3#z*&u8n0`+yNfxFSA`Rh&?%t4c6Eh9(JLAjo9jQ-C(BAp^9R;! z3kL#m8F2mm%%81Xd>t7%T1}(bA2Q!$;b{Hg!-wqdB#G#E@0jTs83$WKs8*n7t@53O z*xA~q9v|-Nf*k>F|Hick&(xXbRBH6%!yn*1^$MZwFYRwNHMkT{b98Eh`gt z51tPLCf2{)p8?#mzu6y;S4s*~nc3b(?t4ModJ*~A<6c>n8)+9>e z&>>@DVp`DyibAbTnkcuJgpIA^di8|9PUkuN-iNvbZ5!#iQ}8dFw{^H5xdpp~xzK zbe{Hc%aU&W6mS+%31HPIAku+}L%6jG&kc(Os|`A)5h?m zpG0eu;-+sk26So1_;}L9r|LZ)SXy4M zsj1QC*P{L2=zR@YBfz?ZA?IMmAO2Iv}}lYN`YkinbC-84M=JFsV1&wirm zCU`<7{uqw9)U|7aK*NTLwc2^EUgc(FWJH%e2x(gtZ9VnIQf3~)Ui$9Q_ zoE$ob4{cRHoUDxv3lA6Dafk0ymnJ{0>Mqpb$$k2Js=~IPu3Ky`uX}dAzX#gVv8lMN#7{2#^Bi%+OzAo{`?_C!6G~=EEFp+DB=Js{B6gBjM4TlZN@xwx%$E~B?j~IJ4At4Iji>9&^spS9} zXThLLcJ|3|-0bb@YJvV_!o(=$%2fz{%$+;wLd;~LzL!PfPRbTO7X0D&rvt=NSF&YIFx^_RQPiKfg4^V&IV#lmL_F zO}`yK9IqlJrr~dXMaqcqVNf)t4bSxFrN=TXntZ-?cP|t^Hw!u4-&$gi?%0?OVzt-1 z@3rY1tJP3ZL5;d=W%VU5x5}vQi2xKS5ei_eecZVz9CYDa-S5W1>bSF(R#q>eaCZf1Tyfc)a#&O2#+~z^Tgf#C3J-=7L6o8gnPc==w!L_UA+oD?qV=ulDOk%Kq4XU zgKe56@g-WH7|}bcTw-Du@CZm|3ZFZMpN3FzL%$^mW0W}G-`|f)e5+?|W24AV!^y^` zz=<9Y_cbZ+g`E`jJ$c@9sp&VjoZNe`WO+fGTX!ekbZ+=db5lj-MO40aX6V4fad$H2hbs)ye{|2t}#nOwp`LhLBV#*m@ZXdFhJ{YTj!M3o-+v)nJ4Fk+ zW!AyLv+yCC|E=pC)+EH+f(6VkD9~+^W}btpW|K?N_S#wRw{3W}C(-|D@1ye~luB7i zN$SU`XX*{BZo#Xo_O9;kStTWc;WUQQvhsM*1wl)xYNx|r|mt(VqvwEpn?Ey1_6SNy8!p^yUC0u!vsY&`qJ(AD`vJp(js&2oCRMawIiB4 z`WDx~o?o#n$)+z)WZW6OG@ZWmo1wwboWL!R@-5LF1c%{{f&$9@=a_y$m5yy2`RNnS z`Umr%Qn^ZvG(h6UU@-fVH*J~0*+4)Ex&}I>ew_SN-1Eqh4Xp65faNfpvIUOMP=`r% z0z$(JgDO-X^zd7JvCv4^VKcu(|Fq)(V>?<~j$K4V#P!jmG>{8x*tvwaZz<7$WH2gv z1BAA`HCX!v`-y-~?}*)*GiO8{$3!U!@!=+wr=M?yk4#l|_V(t0eF@_d`oGKl0pgBh znOol4ibo;0-W{SS#jKvD$azbHg;rKkk@<1j$K>)siZCWDf=TKIFw@qht&X0a2s!YQ z@{5YB1T>4>{_GWuV!L6G(+|#LM}L15>P=nUH35spWbg_^cf^eJ^>2c&by+h>JRH~( z($`^O6}~aDBau+u8^zNRT!d=giK} z2Y{wI2-($jdibyvoQXGaaj!t~{#aO;g<{d+i{04WZLfYbk2smzKgSJaX|p+Hcut^` z1|}sja&T}AF`R;fKKuD4@huIF2Nb?e5-*xkkXK-CD(SVu4~-`X40Dtp)IL1P*=yIX zAr=Dwz*%Jc1nxld&=56{>FdCn7#JCmAul*DfHjCg4yIwX=hh`4bD-tm(1Nm$1Rniw zMv@aoD*ENLFHI2<_zVmTec!$jDtK?w65=mUH_5*U2oQSkm7IiLSSfmQv=H+dZ}?K0JaZWKDN8NztX{Qd;L2V7%j`g1+>5l zW>;21plP-M8CMDn4km1EZAC_lg;%uKzIJq6cX1JfX_KJ+5YG|FE&K2$I5k}!?Jfg0 z)*-R67jTfuwY0R97IDUk!F~LP{ejOcU{vB)$>l!yght1#4aA^=F5e4~XJF8!=I6gI z<*Ulf&gK9a0;UuYdHl%s0GPHp7~8A-#!kTCmJnZaMFAEr3J5ybt7dK z!Fk);-)9#P&0KA*BE_ z9ZY9?9s1qpApR00oLPc%yPdgF;K*o{{c*r;5E1cvqOvN(LZ*Zdl|8&{ZUM&`ehUAP z$*5T5ETCk?%Auyh!q65Bpx?k`-0(f!_5Iq}IbhUjq$vdL1!mcdp)>-|Qu7vEYd&FX z0}BcqLgh0R*!*;OTA|+FL`MgJ>9_jR(Fq9L!*3-x-~&TM05_%AnSz*Opi9bHLAx7Z zmIU?z#z)Y@?@iXa8`XOVfdve+&tCL<<$wBTZtfnFv>PE6w-)R$UP|v-*k>?_9XuzR zx1FR_z=MhcJy2xckO;$;kX*Zr#~_H%;1b?I0HnF;wEc|3$EcO_FLM|{`p;^Hfy755Hzeikm+CiV;qO*I{Ra}D0AxLDy+hwbU2Je?!(jX zfs8lm^5g&t@M3HXU4Qtit}sh5YY;BdU0YvRIOFW>ygpeMUzyyVURFj4E8{UAE>ZI2 zCwj!yXu#9NIyKMT9BeuyOkrB%`Vy|YH<+yn$ID~s-BTm=f9{Zfw*CVUx-M>Rt>8t# z*KzUj@gaT@%)pgd=v}9pc zMHjTV+4c1>NH^5OL=8TK_*LA#`G5ODF;DjYk7=Y&hh97+{4ZBXEeU!=8nE5qh=?|z z2jIS3`nG5@q73ax(6)~a=8)7G%Hj6}axOs3rxgT}%X}MY16FMtpAI`g^Z#8TA~3}q zr1&7IbB2tJY<;4J3Iw&4fXcXFLXE&3UESHWwNU6*_aKG>rc;8j710&*`d~QZ`eWvJ zd?eOBTt@zcF z^%CxaW$aJohoVUq0kB?o`r>fntIpr5BmuXbU@cG3F@-QIv7zzvxY2@tAy?Uw441NL* zyy**cLiSiSu{%qUXK`7?(!*q4jq~pcvX=n>hLTcJmc#k_48|nI4rIi(IPh`?B#mam zC8oegrv^SKRkXG-+XBHP@rusK;4~{Ae6UIX<3{$dusQlPk92gLYdZQv%>Ekzyt;u4@jglV3a0cFnQ=PFOzvMlNB)h^$ZQ?Ay1$T z14md89Rq_`z~g|Xad2~=_4M>aw&q5fp8}gglh5%CR659A0J-~+GZ7RMv!deq+1l5Q zOsl}7aRHYA3_*5yCpb>PFX;sD`gJO3%O8tA+gZ=M?dV#=1PgNmjZRz*_zN(U4*40l z5{jOXkgyrL0|ak2dYpds*e!zN#3bd4Us_tax790;xc*3{hJfJS#>^)=QCo7z5*T$o zX9FLjt>*F4o0you)>b8ulo#6C+UQ_N2=Yeg*|x2uq-054o*fJlx3;!Qou}oHc`KYn zB_NmNG&HY3hsvBDZJ`~ff*_zmPD>jE5KRgy4F+Vdz~|4_diNT-Yvp7^>)&9yhAC-H zAl`sZ$XFBV5ROJaGCu^qeor7=1Z@13cnhC2IHPZGad80cF1PMZ2X0py*CuvQLv|N5 zrX#>I>?ty^RgPrQgrwHcw{Kt3iOP@%$XH&sg*X*AOQZ@AA8J}|eSYDPwNc6N4rzgHymH-NVmTIDew3;m0XK}H3JCcu^y zem}MJHa*#!CnGw4{t`;m8cWyN(P1f|YPQ^nQCCy59mrJ0_q(M1zEInjNlOaca!(JB zH%9!~0wz^&Zlv86SW)eF6k(Ne4Fr!M4~!FFf$ivs9wdr%+3*8bn$9iAuIcIMG@}Qi zQCMMkAJ1gvBU-5nZJpkwJk_2gDm z#6;n@c7 zSzEt4M|Ekr)c}i@6??k3VQFM+Yzak`9CI~Rt@Pd(B1jaZ0=0v|8ZdmvM_Mq|sB)To z4b*WCMq0~L4c9=b;X~_zROB3piGQv5?OQ?5KMxSH3$_H<|4I)Z^23-EK?Gp^cLA6{ zHaCMnDs`HaMl~Z8L}L0m6&P*ppe|XAru}g6qzjEF!yr~<;j@1c-jK1W(#~>jWSaD+ zki!T+0~l1?R$U9O3=p;h0-!Ed0uaC@mohzf*$eDqx8no%;a)JghB8#h_;`8K{+~%v z;dA^<+UH0Ta$%?GAoT&iIZ=Rb*$0!b1(YaA3goUDnVYjT9IO_Q6%~V}(ULf<2`)KK z>U?|TV}l@uzF%@%$o9e#E@iGm4lWE;k*EUE9)0?Gka75_-J`(Pf`fCRx#Rl*ilSpO z^!UIC0_*zyvsGR&C3KigO7ES?%Fce0+ZbWHNCeP;aKRjR8TPSB8%XlZt?yStbO+^^ zk#RqCe)kvc+qZ9VVUfvi7Z`eYNTPCuznh@ZRXjOGB)c3@gb>hag(&AM*j(U!6V;FK zdS$jWf>zgptv|rb-FNPY%`{`!x~jY!nY43TNi2QlxqR7cM#{>{3bdD9xpuw|4@5JEfmkSYe`T{UlA$a2jX}o zh}9<*2&pavp7ae2C@F3Oh!djp4Gll?G=cC#K?=pYptiic906B35S29TtOm&Ad;*sg zqPKeE&JGT{NFezwOm=QSUU)I{2)LFG*e0MtqCh=(gQp2fS_vpe7AOmy`}a8)e*Dl; zQo={768dQOd)XwIs~=@_9(D7ZR+n_w*^}k} zzAajiw6WpBAYvUh)}=3USSfc73xF3DA8+$bJd6U2;&wRuB{sb*j??r8hawC>CP=5I zruM*G6?!zMG~z1F4B;q6kl-grTiXA7(GrAc1`%op(}%D>e_Y|B3y|;o1VjSy0UafT zQOv4#CO}eHSy??iJZ8W^5pk0cRe(e_694&EX1>Q_4pPk54^6C5z;BvCsXsc}dsM$W z=tW&mFhW^h%smKJR2=f{6XA>lxPkLz!r7J>8k&h6X&Fb#}} zjhzK^Svq#h*al020#bU0!V+R{xp{e?z%n87SID_?y`ZDFw;g~Sf+w$`oIch%e)zep zBr$J}L=qajcJH-EFw;S)18H|qef9}*+z6conu5%cKvoo9logh?u|^?8RnJ6R=5W1y z53F8@7a4=)VNh%y4tIjgp&+U_T0>)ersbNrwgzyUhNC}S_9KV(L0~9-`qBY^zcVk3?z)m3rYsA9UXe|g6 zlK4j%=J8>W(nH!|1T_^0}jOv$`CpO;cE+-EXai#b={FTuvxSQi^O(iAnSphohlfj zh>ZqlRxQUh{0ri)7b+kozyR($4jVFtfIR2$=xBLd8>F}vtszpf3^OCh(GgIfAh^ga zU|bf6kbnk}C(x3QVeBOe2TWL8{1OZ~6GiPPFLH5}#ATnW@I99+UGr$3U}yb%08~EP zwQG#x;^H1B`%9a1p;zyLeFVP`U@5Q}#l~UUGB7YG%qmOWO58UGQ6Ci(lR4HXaq;3A$VDQ*iSRS+=gP`C zLqo%1%q9p;ogA!PHHG2=FA4G)1Qee}Mhq&&{(!5ui52Okb6R7> zPKZOIfAoV{3uG7cPqTA!GD=Ex+_gXf_t!mjHZn13>FiYdTMV8TG#?0h=`X=lQB+h^ zfiD&p1(cw_ug?#p^>9IbJriWuzV`O2z~Bm{0Kc~Y;sPQQ2qU(?|IDm@xDW@V5;fr4 zo1~;rh@m0|BG^8F(u#I=d7Uw0Vq);i34DqMdU`0^P7FIuD30iYGgXKZA`Kv`w`u|7 zH%V#fbm!^D?*|9(3JA9c?tRPe3>sp+1t Z6<)eAbP;=B4>#_<_#clTZbSe8 literal 0 HcmV?d00001 diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md index a0ce6161..c2b1c52f 100644 --- a/content/tutorial-pages/2018-09-30/python-mro.md +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -178,6 +178,30 @@ Dealing with multiple classes on the same level of the inheritance graph is a de Note that this does not contain any duplicate entries, which is guaranteed by the algorithm used. +### All multiple inheritance in Python has a diamond topology embedded in it + +The diamond pattern for illustrating a multiple inheritance trouble zone is a bit of a cliche in other languages because you can often structure your classes to not do this with a bit of work. + +However all classes in Python inherit from `object` which means that any time you have inherited from multiple classes you effectively have a diamond pattern with `object` at the base. + +For example: + +```python +class B1: + pass + +class B2: + pass + +class Derived(B1, B2): + pass +``` + +Will have a topology like this: + +![Multiple base class hierarchy](multiple_bases.png "We still have a diamond here in the hierarchy even though it was not expressed explicitly in the code.") + + ## The role of super TODO: super From 3b1ae363de84c99fb9ad79c55956380149d3c3c6 Mon Sep 17 00:00:00 2001 From: Janis Lesinskis Date: Thu, 1 Nov 2018 19:13:21 +1100 Subject: [PATCH 12/12] Mention super --- content/tutorial-pages/2018-09-30/python-mro.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/content/tutorial-pages/2018-09-30/python-mro.md b/content/tutorial-pages/2018-09-30/python-mro.md index c2b1c52f..b9013885 100644 --- a/content/tutorial-pages/2018-09-30/python-mro.md +++ b/content/tutorial-pages/2018-09-30/python-mro.md @@ -206,7 +206,9 @@ Will have a topology like this: TODO: super -Super calls the next method along in the MRO chain. -Note that this is NOT necessarily the same as the superclass. +There's a function called [`super`](https://docs.python.org/3/library/functions.html#super) that gives you the ability to call the next class up in the MRO without having to specify it by name. + +Super calls the *next* method along in the MRO chain. +Note that this is *NOT* necessarily the same as the superclass. The [Dylan language](https://en.wikipedia.org/wiki/Dylan_(programming_language)), which influenced Python's MRO development, refers to this as [the `next-method` function](https://opendylan.org/books/drm/Method_Dispatch#XREF-858) which more clearly explains what it does. \ No newline at end of file