The Python documentation says that the __init__ method of each class is responsible for initializing its super class. But for new-style classes, the ultimate base class is object. Doing dir(object) shows that object itself has an __init__ method and could potentially be initialized. Is there any reason to do that?
I'm inclined to do it for consistency and (slightly) easier refactoring of the class heirarchy, but I wonder if it's strictly necessary or is considered best practice.
You don't need to initialize object; its __init__ is a no-op. It's still good practice, though, as you might want to introduce an intermediate class in the hierarchy later on.
Yes, do it. It's a good habit to get into, and it doesn't hurt.
IMHO it doesn't make any sense at all.
It makes you double check the inheritance to realize that it does nothing
It's the same as adding a pass statement with the overhead of function call.
Quoting the zen: Although practicality beats purity.
Python 3 doesn't require you to declare object as super class.
Yes, and there is a reason why you should do it.
If you ever need to use multi inheritance, python's C3 method resolution order (MRO) will not call all your __init__() base classes.
Related
Is there a reason we call methods in python like object.method instead of Class.method(object)?
Maybe it isn't a strange choice, but personally it made understanding the self parameter much easier when I was shown the second way of calling a method.
Hardcoding the class name basically prevents you from using polymorphism. This is general OOP, not particularly a Python feature.
Your calling code should not need to know, nor care, which exact class object is.
This is immediately a problem for code where object can be a member of either Baseclass or Derivedclass, but much more complex inheritance and method overriding scenarios are possible, and sometimes necessary.
I read the highest rated answer to this question, and it says we should call the super class' __init__ if we need to, and we don't have to. But my question is more about convention.
Should I normally, as a general rule, always call the superclass' __init__ in my class' __init__, regardless of whether or not I currently 'need' the functionality in that method?
Some classes need their __init__ method to be called in order to work. They use their __init__ method sets attributes that will be needed.
Example:
class one ():
def __init__ (self):
self.number = 20
def show_number(self):
return self.number
If you inherit from the above class, you will need to call its __init__ method in order to define the attribute number. If the __init__ method is not called you could get an error when you try to call the method show_number.
As for the syntax, if nothing happens in the __init__ method of the inherited class you don't need to call it. If you think not calling the __init__ method would confuse others, you can always explain your reasoning with comments. It does not do any harm to call it even if you don't need it.
This answer has some downvotes because the downvoters disagree with me on the focus, and perhaps on what "convention" means. I think we mostly agree on the actual practice when it comes to writing code.
No. You should not normally, as a general rule, always call the superclass's __init__ in your class's __init__, regardless of whether or not you currently "need" the functionality in that method.
But please note that my emphasis is on that last phrase, starting with "regardless", and that is what my "no" answer is meant to address. You shouldn't be throwing something into your Python code "just because someone told you to" or "just because that seems to be what most people are doing".
You should include something if it is needed, and not include something if it is not.
It is very often the case, some would argue that it is normally the case, that you do want to call the superclass's __init__ method in your subclass's __init__ method. I do this myself most of the time.
But why?
Crucially, it is not because of some "convention". I do it because my subclass normally needs the same initialization as the superclass, plus a bit of extra customization. Note that the extra customization is the whole reason for overriding __init__ in the first place. If the initialization of your subclass is meant to be identical to that of the superclass, then you shouldn't be defining your own __init__ at all.
It's not a convention in Python to code something you don't need. Some people have their own conventions to include unnecessary things; perhaps in the name of "defensive programming" or because they are used to a different language in which more boilerplate is required.
Where Python's conventions come in is when you have a choice between multiple ways to express something useful. It's true that Python does not emphasize brevity above all else. But that doesn't mean it emphasizes verbosity either. So let me add this, in case it's not clear:
You should normally, as a general rule, always avoid unnecessary boilerplate code. (And not just in Python.)
[For those who think the phrase "normally always" is awkward or nonsensical: I completely agree, but I was trying to emphasize my point by repeating the asker's own choice of words.]
Yes. As a general rule you should call the superclass's __init__ from a subclass's __init__ method. This is not a Python convention, it is what OO best practice suggests you should do (given the language you happen to be using, leaves this decision up to you):
The superclass doesn't know about the subclass, but the subclass is expected to know about the semantics of the superclass it inherits from. Ultimately it is up to the subclass to maintain a consistent behavior of a true sub-typing (which unfortunately, the Python language does little to help the programmer with). You, as the subclass implementer get to decide whether or not you need to call the superclass __init__, just like you get to decide whether you do/don't need/want to call the superclass's implementation of any method you override. However, initialization of an object tends to be a pretty important step in the life-cycle of many objects. Until the object has been initialized one can argue the object is not truly an instance of the given class. It is an implied and important post-condition in ~all sane OO languages that when you instantiate an object certain things have happened and we can depend on those things having happened, initialization (or "construction" in other languages) being the central thing - whether it involves complex parameter validation and computed value generation, or is just a null op. So if you don't call super's initializer you better know exactly what your in for.
Another argument for calling super's __init__ as a general rule is, if you didn't write the superclass, or your not tightly controlling the version, the implementation of __init__ may change in future (does adding something to __init__ call for a major version bump? I'm not sure but I bet a lot of folks wouldn't bump the major version number for that, even if technically they should). So if you do call super's __init__ your code is less likely to break with updates to the superclass implementation.
Update: Should have read the linked question before answering this question. Most of the answers over there echo the general sentiment here - perhaps not in the same terms or as strongly in favor of calling __init__() as a general rule as I am. But I'll leave this answer for others that fall here.
I understand mixin as what looks like inheritance but what is more like composition.
(edit: I tend to think giving additional functionality/attributes by mixin rather than giving another is-a relationship.)
Mentally, I'm saying something like this when I use mixin: I'm giving you this mixin you are missing, rather than you are actually this mixin-type as well.(is-a)
And I read few times, you should prefer composition over inheritance.
We could just use straight compositions instead of mixins, what is mixin for?
If I have to guess, it's because my_instance.foo() is easier than my_instance.another_instance.foo()?
(You can use my_instance.foo() if mixin has foo(), you need my_instance.another_instance.foo() when you composite another_instance as an attribute of my_instance)
Are there any other reason?
Edit:
So even though I feel it's has-a, mixin is still is-a relationship. and benefit you get when you use is-a here is, cleaner interface. That' how I interpret delnan's answer.
(Since mixin doesn't give you is-a relationship, it gives you has-a)
Wrong, it does give you a is-a relationship. Consider class C(A, B). issubclass(C, A) is true and so is issubclass(C, B). The call C().method_of_B() calls the method of B if it isn't overridden somewhere in the MRO (which can happen with single inheritance too!), and similarly for methods of A. The attribute access C().attr_of_{a,b} gives you an attribute of A or B too (same caveat as with methods).
And I read few times, you should prefer composition over inheritance.
This rule of thumb exists because many people tend to use inheritance where it isn't appropriate, not because inheritance isn't a useful tool in any case. This applies to Python too. Common (good) reasons include:
A is-a relationship would be wrong, for example because it breaks the Liskov Substitution Principle. This reason is not affected by mixins, see above.
Composition is easier or less error-prone, for various reasons. This reason is valid when mixins are possible too, if anything it's amplified as it can be a bit tricky (though not impossible) to get the MRO and sequence of super() calls right.
If I have to guess, it's because my_instance.foo() is easier than my_instance.another_instance.foo()?
That's just a few additional characters. More important is that you have to re-type wrapper methods for every single method you want to re-export (which would be all of them if you're emulating an is-a relationship via composition).
More conceptually, this manual work seems pointless and error-prone if C really is-a A. Mixins/multiple inheritance support the case where an object is more than what can or should be represented by a single bass class. For example, a UTF-8 string may be both a ByteBuffer and a UnicodeStream. In general, we have interfaces for this (or not; in Python this is implicit), but mixins also allow adding related functionality in a composable and convenient manner.
How do you decide between using decorators and inheritance when both are possible?
E.g., this problem has two solutions.
I'm particularly interested in Python.
Decorators...:
...should be used if what you are trying to do is "wrapping". Wrapping consists of taking something, modifying (or registering it with something), and/or returning a proxy object that behaves "almost exactly" like the original.
...are okay for applying mixin-like behavior, as long as you aren't creating a large stack of proxy objects.
...have an implied "stack" abstraction:
e.g.
#decoA
#decoB
#decoC
def myFunc(...): ...
...
Is equivalent to:
def myFunc(...): ...
...
myFunc = decoA(decoB(decoC(myFunc))) #note the *ordering*
Multiple inheritance...:
... is best for adding methods to classes; you cannot use it to decorate functions easily. In this context, it can be used to achieve mixin-like behavior if all you need is a set of "duck-typing style" extra methods.
... may be a bit unwieldy if your problem is not a good match for it, with issues with superclass constructors, etc. For example, the subclasses __init__ method will not be called unless it is called explicitly (via the method-resolution-order protocol)!
To sum up, I would use decorators for mixin-like behavior if they didn't return proxy objects. Some examples would include any decorator which returns the original function, slightly modified (or after registering it somewhere or adding it to some collection).
Things you will often find decorators for (like memoization) are also good candidates, but should be used in moderation if they return proxy objects; the order they are applied matter. And too many decorators on top of one another is using them in a way they aren't intended to be used.
I would consider using inheritance if it was a "classic inheritance problem", or if all I needed for the mixin behavior were methods. A classic inheritance problem is one where you can use the child wherever you could use the parent.
In general, I try to write code where it is not necessary to enhance arbitrary things.
The problem you reference is not deciding between decorators and classes. It is using decorators, but you have the option of using either:
a decorator, which returns a class
a decorator, which returns a function
A decorator is just a fancy name for the "wrapper" pattern, i.e. replacing something with something else. The implementation is up to you (class or function).
When deciding between them, it's completely a matter of personal preference. You can do everything you can do in one with the other.
if decorating a function, you may prefer decorators which return proxy functions
if decorating a class, you may prefer decorators which return proxy classes
(Why is it a good idea? There may be assumptions that a decorated function is still a function, and a decorated class is still a class.)
Even better in both cases would be to use a decorator which just returns the original, modified somehow.
edit: After better understanding your question, I have posted another solution at Python functools.wraps equivalent for classes
The other answers are quite great, but I wanted to give a succinct list of pros and cons.
The main advantage of mixins is that the type can be checked at runtime using isinstance and it can be checked with linters like MyPy. Like all inheritance, it should be used when you have an is-a relationship. For example dataclass should probably have been a mixin in order to expose dataclass-specific introspection variables like the list of dataclass fields.
Decorators should be preferred when you don't have an is-a relationship. For example, a decorator that propagates documentation from another class, or registers a class in some collection.
Decoration typically only affects the class it decorates, but not classes that inherit from the base class:
#decorator
class A:
... # Can be affected by the decorator.
class B(A):
... # Not affected by the decorator in most cases.
Now that Python has __init_subclass__, everything that decorators can do can be done with mixins, and they typically do affect child subclasses:
class A(Mixin):
... # Is affected by Mixin.__init_subclass__.
class B(A):
... # Is affected by Mixin.__init_subclass__.
Mixins have another advantage, which is that they can provide empty base class methods. Child classes can override these methods with some "augmenting" behavior, and then call super. The decorator cannot easily provide such base class methods. This is another way in which mixins are more flexible.
In summary, the questions you should ask when deciding between a mixin and decoration are:
Is there an is-a pattern?
Would you ever call isinstance?
Would you use the mixin in a type annotation?
Do you want the behavior to affect child classes?
Do you need augmenting methods?
In general, lean towards inheritance.
If both are equivalent, I would prefer decorators, since you can use the same decorator for many classes, while inheriting apply to only one specific class.
Personally, I would think in terms of code reuse. Decorator is sometimes more flexible than inheritance.
Let's take caching as an example. If you want to add caching facility to two classes in your system: A and B, with inheritance, you'll probably wind up having ACached and BCached. And by overriding some of the methods in these classes, you'll probably duplicate a lot of codes for the same caching logic. But if you use decorator in this case, you only need to define one decorator to decorate both classes.
So, when deciding which one to use, you may first want to check if the extended functionality is only specific to this class or if the same extended functionality can be reused in other parts of your system. If it cannot be reused, then inheritance should probably do the job. Otherwise, you can think about using decorator.
Or should I just explicitly reference the superclasses whose methods I want to call?
It seems brittle to repeat the names of super classes when referencing their constructors, but this page http://fuhm.net/super-harmful/ makes some good arguments against using super().
The book Expert Python Programming has discussed the topic of "super pitfalls" in chapter 3. It is worth reading. Below is the book's conclusion:
Super usage has to be consistent: In a class hierarchy, super should be used everywhere or nowhere. Mixing super and classic calls is a confusing practice. People tend to avoid super, for their code to be more explicit.
Edit: Today I read this part of the book again. I'll copy some more sentences, since super usage is tricky:
Avoid multiple inheritance in your code.
Be consistent with its usage and don't mix new-style and
old-style.
Check the class hierarchy before calling its methods in
your subclass.
You can use super, but as the article says, there are drawbacks. As long as you know them, there is no problem with using the feature. It's like people saying "use composition, not inheritance" or "never use global variables". If the feature exists, there is a reason. Just be sure to understand the why and the what and use them wisely.
super() tries to solve for you the problem of multiple inheritance; it's hard to replicate its semantics and you certainly shouldn't create any new semantics unless you're completely sure.
For single inheritance, there's really no difference between
class X(Y):
def func(self):
Y.func(self)
and
class X(Y):
def func(self):
super().func()
so I guess that's just the question of taste.
I like super() more because it allows you to change the inherited class (for example when you're refactoring and add an intermediate class) without changing it on all the methods.
The problem people have with super is more a problem of multiple inheritance. So it is a little unfair to blame super. Without super multiple inheritance is even worse. Michele Simionato nicely wrapped this up in his blog article on super:
On the other hand, one may wonder if
all super warts aren't hints of some
serious problem underlying. It may
well be that the problem is not with
super, nor with cooperative methods:
the problem may be with multiple
inheritance itself.
So the main lesson is that you should try to avoid multiple inheritance.
In the interest of consistency I always use super, even if for single inheritance it does not really matter (apart from the small advantage of not having to know the parent class name). In Python 3+ super is more convenient, so there one should definitely use super.
Yes, you should use super() over other methods. This is now the standard object inheritance model in Python 3.
Just stick to keyword arguments in your __init__ methods and you shouldn't have too many problems. Additionally you can use **kwargs to support additional parameters that are not defined in levels of the inheritance chain.
I agree that it is brittle, but no less so than using the name of the inherited class.