This question already has answers here:
Should constructors comply with the Liskov Substitution Principle? [closed]
(3 answers)
Closed 7 years ago.
One of the recommended principles of object-oriented programming is the Liskov substitution principle: a subclass should behave in the same way as its base class(es) (warning: this is actually not a correct description of the Liskov principle: see the PS).
Is it recommended that it also apply to constructors? I mostly have Python in mind, and its __init__() methods, but this question applies to any object-oriented language with inheritance.
I am asking this question because it is sometimes useful to have a subclass inherit from one or more classes that provide some nice default behavior (like inheriting from a dictionary, in Python, so that obj['key'] works for objects of the new class). However, it is not always natural or simple to allow the subclass to be used exactly like a dictionary: it would be sometimes nicer that the constructor parameters only relate to the specific user subclass (for instance, a class that represents a set of serial ports might want to behave like a dictionary with ports['usb1'] being USB port #1, etc.). What is the recommended approach to such a situation? having subclass constructors that are fully compatible with that of their base classes, and generating instances through an object factory function that takes simple, user-friendly parameters? or simply writing a class constructor whose set of parameters cannot be directly given to the constructor of its base classes, but which is more logical from the user perspective?
PS: I misinterpreted the Liskov principle, above: Sven's comment below points out the fact that objects of a subclass should behave like objects of the superclass (the subclass itself does not have to behave like the superclass; in particular, their constructors do not have to have the same parameters [signature]).
As requested, I post as an answer what previously has been a comment.
The principle as defined in the linked Wikipedia article reads "if S is a subtype of T, then objects of type T may be replaced with objects of type S". It does not read "a subclass should behave in the same way as its base class(es)". The difference is important when thinking about constructors: The Wikipedia version only talks about objects of a subtype, not the type itself. For an object, the constructor has already been called, so the principle doesn't apply to constructors. This is also how I apply it, and the ways it seems applied in the standard lib (e.g defaultdict and dict).
Constructors in multiple inheritance probably can't be discussed in a language-agnostic way. In Python, there are two approaches. If your inheritance diagram includes diamond patterns and you need to make sure all constructors are called exactly once, you should use super() and follow the pattern described in the section "Practical advice" of Raymond Hettinger's article Python's super() considered super. If you don't have diamonds (except for the ones including object), you can also use explicit base class calls for all base class constructors.
Related
I first learned polymorphism in c++, in c++ we had types for every variable. So we used polymorphism to get a single pointer which can point to different type objects, and we could use them very nice.
But I don't get polymorphism and abstract classes in python. Here every variable can be everything. It could be an iterator, a list, a singe variable or a function. Every thing. So what makes a programmer to use an abstract class or use polymorphism here?
In c++ we used inheritance in many ways. But in python, it is just used to use another classes method or attribute. Am I right? what's the matter?
You don't understand what polymorphism is (OO polymorphic dispatch I mean). Polymorphism is the ability to have objects of different types understanding the same message, so you can use those objects the same way without worrying about their concrete type.
C++ actually uses the same concept (class) to denote two slightly different semantics: the abstract type (interface) which is the set of messages an object of this type understand) and the concrete type (implementation) which defines how this type reacts to those messages.
Java clearly distinguishes between abstract type (interface) and concrete type (class).
Python, being dynamically typed, relies mostly on "duck typing" (if it walks like a duck and quack like duck, then it's a duck - or at least it's "kind-of-a-duck" enough). You'll often find terms like "file-like" or "dict-like" in Python docs, meaning "anything that has the same interface as a file (or dict)", and quite a few "interfaces" are (or at least have long been) more or less implicit.
The issue with those implicit interfaces is that they are seldom fully documented, and one sometimes have to get to a function source code to find out exactly what the object passed needs to support. That's one of the reasons why the abc module was introduced in python 2 and improved in python 3: as a way to better document those implicit interfaces by creating an abstract base type that clearly defines the interface.
Another reason for abstract base classes (whether using the abc module or not) is to provide a common base implementation for a set of concrete subclasses. This is specially useful for frameworks, ie Django's models.Model (ORM) or forms.Form (user input collection and validation) classes - in both cases, just defining the database or form fields is enough to have something working.
Inheritance in C++ suffers from the same issue as classes: it serves both as defining the interface and implementation. This adds to the confusion... Java had the good idea (IMHO) to have separate abstract type from implementation, but failed to go all the way and restrict typing to interfaces - you can use either classes or interfaces for type declaration, so it still doesn't make the distinction clear.
In Python, since we don't have static typing, inheritance is mostly about implementation reuse indeed. The abc module allows you to register totally unrelated classes (no inheritance relationship) as also being subtypes of a defined abstract base case, but the point here is mostly to document that your class implements the same interface (and that it's not an accident...).
This question already has answers here:
Why do Python classes inherit object?
(6 answers)
Closed 5 years ago.
What is the difference between:
class ClassName(object):
pass
and
class ClassName:
pass
When I call the help function of the module of those class you can read ____builtin____.object for the first case just under the CLASS title of help. For the second case it just shows the class name. Is there any functional difference between those classes and/or possible methods thereof?
(I know that class Classname(ParentClassName) has a functional use)
In Python 2.x, when you inherit from "object" you class is a "new style" class - that was implemented back in Python 2.2 (around 2001) - The non inheriting from "object" case creates an "old style" class, that was actually maintained only for backwards compatibility.
The great benefit of "new style" classes is the unification of types across Python - prior to that, one could not subclass built-in types such as int, list, dict, properly. There was also specified a "descriptor protocol" which describes a protocol for retrieving and setting attributes in an object, giving the language a lot of flexibility. (It is more visible when one does use a Python "property" in a class).
What does make the difference is not actually "inheriting from object", but, since classes in Python are also objects, that does change the class'class itself (a class'class is known as its "metaclass"). Thus if you set the metaclass to be "type", you don't need to inherit from object to have a new style class.
It is strongly recommended that in Python 2.x, all your classes are new style - using old style classes may work for some single straightforward cases, but they can generate a lot of subtle, difficult to find, errors, when you try to use properties, pickle, descriptors, and other advanced features. Above all, when you try to check the "type" of an object, it will be the same (type "instance") for all objects from old style classes, even if they are from different user defined classes.
In Python versions 3.x all classes are new style - no need to set the metaclass.
Python's documentation "datamodel" is the "book of law" where the behavior of both
class typs is defined in detail (enough to allow one to reimplement the language):
http://docs.python.org/reference/datamodel.html
This blog post from Guido talks about the motivations behind new style classes in a lighter language:
http://python-history.blogspot.com.br/2010/06/new-style-classes.html
http://docs.python.org/release/2.5.2/ref/node33.html
ClassName(object) uses the new style class: http://docs.python.org/release/2.5.2/ref/node33.html
The second example demonstrates an old style class.
In python 3, new style classes are used by default and you will no longer need to subclass object.
This question already has answers here:
Why do Python classes inherit object?
(6 answers)
Closed 5 years ago.
What is the difference between:
class ClassName(object):
pass
and
class ClassName:
pass
When I call the help function of the module of those class you can read ____builtin____.object for the first case just under the CLASS title of help. For the second case it just shows the class name. Is there any functional difference between those classes and/or possible methods thereof?
(I know that class Classname(ParentClassName) has a functional use)
In Python 2.x, when you inherit from "object" you class is a "new style" class - that was implemented back in Python 2.2 (around 2001) - The non inheriting from "object" case creates an "old style" class, that was actually maintained only for backwards compatibility.
The great benefit of "new style" classes is the unification of types across Python - prior to that, one could not subclass built-in types such as int, list, dict, properly. There was also specified a "descriptor protocol" which describes a protocol for retrieving and setting attributes in an object, giving the language a lot of flexibility. (It is more visible when one does use a Python "property" in a class).
What does make the difference is not actually "inheriting from object", but, since classes in Python are also objects, that does change the class'class itself (a class'class is known as its "metaclass"). Thus if you set the metaclass to be "type", you don't need to inherit from object to have a new style class.
It is strongly recommended that in Python 2.x, all your classes are new style - using old style classes may work for some single straightforward cases, but they can generate a lot of subtle, difficult to find, errors, when you try to use properties, pickle, descriptors, and other advanced features. Above all, when you try to check the "type" of an object, it will be the same (type "instance") for all objects from old style classes, even if they are from different user defined classes.
In Python versions 3.x all classes are new style - no need to set the metaclass.
Python's documentation "datamodel" is the "book of law" where the behavior of both
class typs is defined in detail (enough to allow one to reimplement the language):
http://docs.python.org/reference/datamodel.html
This blog post from Guido talks about the motivations behind new style classes in a lighter language:
http://python-history.blogspot.com.br/2010/06/new-style-classes.html
http://docs.python.org/release/2.5.2/ref/node33.html
ClassName(object) uses the new style class: http://docs.python.org/release/2.5.2/ref/node33.html
The second example demonstrates an old style class.
In python 3, new style classes are used by default and you will no longer need to subclass object.
This question already has answers here:
How do I access the child classes of an object in django without knowing the name of the child class?
(8 answers)
Closed 7 years ago.
I have a model
BaseModel
and several subclasses of it
ChildModelA(BaseModel), ChildModelB(BaseModel), ...
using multi-table inheritance. In future I plan to have dozens of subclass models.
All subclasses have some implementation of method
do_something()
How can I call do_somthing from a BaseModel instance?
Almost identical problem (without solution) is posted here:
http://peterbraden.co.uk/article/django-inheritance
A simpler question: how I resolve BaseModel instnace to one of its subclasses instance without checking all possible subclasses?
If you want to avoid checking all possible subclasses, the only way I can think of would be to store the class name associated with the subclass in a field defined on the base class. Your base class might have a method like this:
def resolve(self):
module, cls_name = self.class_name.rsplit(".",1)
module = import_module(module)
cls = getattr(module, cls_name)
return cls.objects.get(pk=self.pk)
This answer does not make me happy and I too would love to see a better solution, as I will be facing a similar problem soon.
Will you ever be working with an instance of the base type or will you always be working with instances of the children? If the latter is the case then call the method, even if you have a reference to the base type since the object itself IS-A child type.
Since Python support duck typing this means that your method call will be bond appropriately since the child instance will truly have this method.
A pythonic programming style which
determines an object’s type by
inspection of its method or attribute
signature rather than by explicit
relationship to some type object (“If
it looks like a duck and quacks like a
duck, it must be a duck.”) By
emphasizing interfaces rather than
specific types, well-designed code
improves its flexibility by allowing
polymorphic substitution. Duck-typing
avoids tests using type() or
isinstance(). (Note, however, that
duck-typing can be complemented with
abstract base classes.) Instead, it
typically employs hasattr() tests or
EAFP programming.
Note that EAFP stands for Easier to Ask Forgiveness than Permission:
Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL style common to many other languages such as C.
I agree with Andrew. On a couple of sites we have a class that supports a whole bunch of methods (but not fields (this was pre-ORM refactor)) that are common to most-but-not-all of our content classes. They make use of hasattr to sidestep situations where the method doesn't make sense.
This means most of our classes are defined as:
class Foo(models.Model, OurKitchenSinkClass):
Basically it's sort of a MixIn type of thing. Works great, easy to maintain.
I was wondering if I have a couple of models which both include fields like "meta_keywords" or "slug" which have to do with the web page the model instance will be displayed on, whether it would be advisable to break those page metadata elements out into their own class, say PageMeta, and have my other models subclass those via multiple inheritance?
General advice for a lightly-specified question:
Nontrivial multiple inheritance in Python requires Advanced Techniques to deal with the metaclass/metatype conflict. Look over this recipe from the ActiveState archives and see if it looks like the kind of stuff you like:
Extract from linked recipe:
The simplest case where a metatype
conflict happens is the following.
Consider a class A with metaclass M_A
and a class B with an independent
metaclass M_B; suppose we derive C
from A and B. The question is: what is
the metaclass of C ? Is it M_A or M_B
?
The correct answer (see the book
"Putting metaclasses to work" for a
thoughtful discussion) is M_C, where
M_C is a metaclass that inherits from
M_A and M_B.
However, Python is not that magic, and
it does not automatically create M_C.
Instead, it raises a TypeError,
warning the programmer of the possible
confusion.
Consequently, I recommend limiting your use of multiple inheritance in Python to the following cases:
You must, because your problem domain requires you to combine two separately-maintained single-inheritance libraries.
You have achieved such fluency with metatype and metaclass that you can write recipe 204197 or its equivalent as easily and confidently as you can write a print statement.
Edit:
Here's Guido van Rossum in An Introduction to Python:
It is clear that indiscriminate use of
multiple inheritance is a maintenance
nightmare, given the reliance in
Python on conventions to avoid
accidental name conflicts.
Here he is again in PEP 253, which describes the ideas which were incorporated into Python, but not the implementation:
Metatypes determine various policies
for types, such as what
happens when a type is called, how dynamic types are (whether a
type's dict can be modified after it is created), what the
method resolution order is, how instance attributes are looked
up, and so on.
I'll argue that left-to-right depth-first is not the best
solution when you want to get the most use from multiple
inheritance.
I'll argue that with multiple inheritance, the metatype of the
subtype must be a descendant of the metatypes of all base types.
This does not mean you shouldn't use multiple inheritance; I'm just warning you so you won't be suprised one day to find yourself slapping your forehead and exclaiming "D'oh!
The metatype of one of my subtypes isn't a descendant of the metatypes of all its base types! Don't you hate when that happens?"