In the case of multiple base classes wouldn't it be more sensible for the derived class to forego the lexical convenience of super() and simply call each base explicitly? i.e.
If one wants to inherit from multiple classes then they should be responsible for specifying the details of how that happens. Why should a base class be expected to add boilerplate just in case some external consumer comes along and wants to use it in some unforeseeable context?
That super() has a "method resolution order" seems like a fudge. Now 'super' doesn't necessarily mean 'superclass' anymore at the point of use. Am I missing some other hypothetical situation in which super()'s MRO brings more value for the price of having to know about this extra, implicit behaviour?
And what's funny is that in the example given, the first base class not calling super() leads to the bad consequence that the other base class doesn't get to set some internal state (self.mode). Yet in the next section, "When to use a Mixin", it advises: "A mixin is a class that [...] does not contain state"
Seems fairly standard stuff for libraries to consider. I was really hoping for some weird stuff like patching bytecode or implementing entire different languages as a python library.
Check out Coconut (https://github.com/evhub/coconut), which implements an entire functional programming language as a Python superset that compiles to Python bytecode.
These are things that less experienced Python programmers might not know about, but they're not at all uncommon. If anything, calling `super()` in a base class should be the default if you're designing a framework where you expect people to use mixins (or even just explicitly intend for them to derive your classes, really).
Creating blank `__init__.py` files has basically become standard because the use cases where you'd prefer to omit them don't work well with packaging tools (since everything will be in `site-packages` anyway; most people also aren't going to install multiple things from a common namespace that you publish; adding those files helps build backends and other tools understand your project layout; etc.). On the flip side, the use cases for writing something in `__init__.py` should be evident from just considering the fact that it's possible. (It's also a useful refactoring tool; if you are planning to make a package but don't know what all its modules should be yet, you can start by turning an existing `foo.py` into `foo/__init__.py`.) Preemptively importing from `__init__.py`, though, is not always a great idea; it represents extra up-front import time that clients can't opt out of. (This has a lot to do with why Pip takes a significant amount of time even when it ultimately determines that it hasn't been asked to do anything.)
Preferring relative imports is, if anything, not common enough, but is certainly common among people who know what they're doing.
As for class/static/instance methods:
> When should we use class or static methods? Here are some basic guidelines I found.
The use cases more or less derive directly from their differences. But if you're going to cite sources for this, it's a crying shame to leave out Raymond Hettinger's "Python's Class Development Toolkit" (https://www.youtube.com/watch?v=HTLu2DFOdTg).
I briefly thought "oh yeah, mixins, shame we can't do that in C# with single inheritance" and then realized that's what extension methods are for (and slightly more general).
I have some C# code which relies on calling an extension method on a null instance, which is mildly naughty but saves a lot of refactoring.
You can call an extension method, because it's just fancy syntax for calling a non member method with the thing before the . as the first argument. If you then don't reference it at all, it doesn't matter that it's null.
If you want to combine a mixin with a base class you have no control over, just put the base class last in the inheritance chain. Then it does not matter if it calls its super __init__.
In the case of multiple base classes wouldn't it be more sensible for the derived class to forego the lexical convenience of super() and simply call each base explicitly? i.e.
If one wants to inherit from multiple classes then they should be responsible for specifying the details of how that happens. Why should a base class be expected to add boilerplate just in case some external consumer comes along and wants to use it in some unforeseeable context?That super() has a "method resolution order" seems like a fudge. Now 'super' doesn't necessarily mean 'superclass' anymore at the point of use. Am I missing some other hypothetical situation in which super()'s MRO brings more value for the price of having to know about this extra, implicit behaviour?
And what's funny is that in the example given, the first base class not calling super() leads to the bad consequence that the other base class doesn't get to set some internal state (self.mode). Yet in the next section, "When to use a Mixin", it advises: "A mixin is a class that [...] does not contain state"
I could try to answer myself, but this will be far better that I could express in english:
https://www.youtube.com/watch?v=EiOglTERPEo
Seems fairly standard stuff for libraries to consider. I was really hoping for some weird stuff like patching bytecode or implementing entire different languages as a python library.
Sure, but "Do not deprive people the joy of discovery." -Someone, not me.
Check out Coconut (https://github.com/evhub/coconut), which implements an entire functional programming language as a Python superset that compiles to Python bytecode.
These are things that less experienced Python programmers might not know about, but they're not at all uncommon. If anything, calling `super()` in a base class should be the default if you're designing a framework where you expect people to use mixins (or even just explicitly intend for them to derive your classes, really).
Creating blank `__init__.py` files has basically become standard because the use cases where you'd prefer to omit them don't work well with packaging tools (since everything will be in `site-packages` anyway; most people also aren't going to install multiple things from a common namespace that you publish; adding those files helps build backends and other tools understand your project layout; etc.). On the flip side, the use cases for writing something in `__init__.py` should be evident from just considering the fact that it's possible. (It's also a useful refactoring tool; if you are planning to make a package but don't know what all its modules should be yet, you can start by turning an existing `foo.py` into `foo/__init__.py`.) Preemptively importing from `__init__.py`, though, is not always a great idea; it represents extra up-front import time that clients can't opt out of. (This has a lot to do with why Pip takes a significant amount of time even when it ultimately determines that it hasn't been asked to do anything.)
Preferring relative imports is, if anything, not common enough, but is certainly common among people who know what they're doing.
As for class/static/instance methods:
> When should we use class or static methods? Here are some basic guidelines I found.
The use cases more or less derive directly from their differences. But if you're going to cite sources for this, it's a crying shame to leave out Raymond Hettinger's "Python's Class Development Toolkit" (https://www.youtube.com/watch?v=HTLu2DFOdTg).
I briefly thought "oh yeah, mixins, shame we can't do that in C# with single inheritance" and then realized that's what extension methods are for (and slightly more general).
I have some C# code which relies on calling an extension method on a null instance, which is mildly naughty but saves a lot of refactoring.
You can call methods on null instances?
You can call an extension method, because it's just fancy syntax for calling a non member method with the thing before the . as the first argument. If you then don't reference it at all, it doesn't matter that it's null.
thanks for resharing, interesting well written read
previous: https://news.ycombinator.com/item?id=32528919
If you want to combine a mixin with a base class you have no control over, just put the base class last in the inheritance chain. Then it does not matter if it calls its super __init__.
And if there are two such base classes?
What a fantastic read. It’s nothing groundbreaking, but it’s a perfect model of how to learn good patterns.