On Sun, Apr 03, 2022 at 10:06:35PM -0000, malmiteria wrote: > Then what's the solution to the diamond problem in python? > in this example :
[code removed for brevity] class hierarchy: ``` HighGobelin / \ / \ / \ ProudGobelin CorruptedGobelin \ / \ / \ / HalfBreed ``` By the way, you have a bug in your use of random. You call random.choices, which returns a list which is always true, and so only the super(HalfBreed, self) branch gets called. You should call random.choice (not plural). Also you misspelled CorruptedGobelin. > You want calls to ProudGobelin scream method to visit ProudGobelin, then > HighGobelin And indeed that is exactly what happens when you call ProudGobelin's scream method: >>> ProudGobelin().scream() I ... can't ... contain my scream! raAaaaAar This makes sense: ProudGobelin's class heirarchy is plain old single inheritence with no diamond, so there is absolutely no reason to expect it to call anything except its own method and that of its parent(s). And it doesn't. Python works perfectly fine here. > Not ProudGobelin, then CorruptedGobelin, then HighGobelin. This does not happen when calling ProudGobelin's method. But when you call HalfBreed's scream method, after fixing the two typos, again we get the correct behaviour. Although it might be *unexpected* if you don't understand super(). * Half the time you use super(HalfBreed, self), and we get the expected behaviour. Because HalfBreed is part of a diamond, it should call *both* immediate parents as well as the grandparent, and it does: >>> HalfBreed().scream() I ... can't ... contain my scream! my corrupted soul makes me wanna scream raAaaaAar * and the other half the time, you use super(ProudGobelin, self), but this time the behaviour is unexpected, because you don't realise that super(ProudGobelin) does **not** mean "call ProudGobelin's method". >>> HalfBreed().scream() my corrupted soul makes me wanna scream raAaaaAar You get *CorruptedGobelin*'s output instead of ProudGobelin. This is not a bug in super, it is a bug in your understanding of super. To get the effect you want, you should not use super, but call the method you actually want: ProudGobelin.scream(self) I am not an expert in super(), but I *think* that the call to super here: super(ProudGobelin, self).scream() looks at self's MRO: [HalfBreed, ProudGobelin, CorruptedGobelin, HighGobelin] and skips straight to the call that would occur *after* ProudGobelin, which of course is CorruptedGobelin. Because the instance self is still a HalfBreed, it uses the HalfBreed MRO, not the ProudGobelin MRO. What is the class that follows ProudGobelin in the HalfBreed MRO? It is CorruptedGobelin, so of course that is the method that will get used. The same thing occurs without the diamond shape. Remove CorruptedGobelin from HalfBreed, but keep the rest of the code the same: ``` class HalfBreed(ProudGobelin): # No diamond here. def scream(self): if random.choice([True, False]): print("Halfbreed --") super(HalfBreed, self).scream() else: print("ProudGobelin --") super(ProudGobelin, self).scream() ``` (I have added extra print statements so we can see which branch is taken.) You will see that super(ProudGobelin, self) goes to the *next* class in HalfGobelin's MRO, which is HighGobelin. Which is of course the right behaviour, if you think about how it must work. Otherwise you would have an infinite recursion. The TL;DR here is that you mistakenly expected: super(ProudGobelin, self).scream() to be the same as ProudGobelin.scream(self), but it is not. It is the same as self.scream(), using self's MRO (HalfGobelin), but called from ProudGobelin's method, which means it goes on to the next class in HalfGobelin's MRO *after* ProudGobelin. -- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/DUZ7UHIZEG3NH34I3SDATVZSOGEY2R6S/ Code of Conduct: http://python.org/psf/codeofconduct/