In python 2.x, super accepts the following cases
class super(object)
| super(type) -> unbound super object
| super(type, obj) -> bound super object; requires isinstance(obj, type)
| super(type, type2) -> bound super object; requires issubclass(type2, type)
| Typical use to call a cooperative superclass method:
as far as I see, super is a class, wrapping the type and (eventually) the instance to resolve the superclass of a class.
I'm rather puzzled by a couple of things:
why there is also no super(instance), with typical usage e.g. super(self).__init__(). Technically, you can obtain the type of an object from the object itself, so the current strategy super(ClassType, self).__init__() is kind of redundant. I assume compatibility issues with old-style classes, or multiple inheritance, but I'd like to hear your point.
why, on the other hand, python 3 will accept (see Understanding Python super() with __init__() methods) super().__init__() ? I see kind of magic in this, violating the explicit is better than implicit Zen. I would have seen more appropriate self.super().__init__().
super(ClassType, self).__init__() is not redundant in a cooperative multiple inheritance scheme -- ClassType is not necessarily the type of self, but the class from which you want to do the cooperative call to __init__.
In the class hierarchy C inherits B inherits A, in C.__init__ you want to call superclass' init from C's perspective, and you call B.__init__; then in B.__init__ you must pass the class type B to super -- since you want to resolve calling superclasses of B (or rather, the next in the mro after B of the class C).
class A (object):
def __init__(self):
pass
class B (A):
def __init__(self):
super(B, self).__init__()
class C (B):
def __init__(self):
super(C, self).__init__()
if you now instantiate c = C(), you see that the class type is not redundant -- super(self).__init__() inside B.__init__ would not really work! What you do is that you manually specify in which class the method calling super is (an this is solved in Python 3's super by a hidden variable pointing to the method's class).
Two links with examples of super and multiple inheritance:
Things to Know About Python Super (1 of 3)
Python's Super is nifty, but you can't use it
I can't provide a specific answer, but have you read the PEP's around the super keyword? I did a quick google search and it came up with PEP 367 and PEP 3135.
http://www.python.org/dev/peps/pep-0367/
http://www.python.org/dev/peps/pep-3135/#numbering-note
Unlike any other language I know of, most of the time you can find the answers to Python's quirks in the PEP's along with clear rational and position statements.
Update:
Having read through 3135, related emails in the Python Mailing and the language reference it kind of makes sense why it is the way it is for Python 2 vs Python 3.
http://docs.python.org/library/functions.html?highlight=super#super
I think super was implemented to be explicit/redundant just to be on the safe side and keep the logic involved as simple as possible ( no sugar or deep logic to find the parent ). Since super is a builtin function, it has to infer the correct return from what is provided without adding more complication to how Python objects are structured.
PEP 3135 changes everything because it presented and won an argument for a DRY'er approach to super.
Related
I have a problem understanding some concepts of data structures in Python, in the following code.
class Stack(object): #1
def __init__(self): #2
self.items=[]
def isEmpty(self):
return self.items ==[]
def push(self,item):
self.items.append(item)
def pop(self):
self.items.pop()
def peak(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
s = Stack()
s.push(3)
s.push(7)
print(s.peak())
print (s.size())
s.pop()
print (s.size())
print (s.isEmpty())
I don't understand what is this object argument
I replaced it with (obj) and it generated an error, why?
I tried to remove it and it worked perfectly, why?
Why do I have __init__ to set a constructor?
self is an argument, but how does it get passed? and which object does it represent, the class it self?
Thanks.
object is a class, from which class Stack inherits. There is no
class obj, hence error. However, you can define a class that does
not inherit from anything (at least, in Python 2).
self represents an object on which the method is called; for
example when you do s.pop(), self inside method pop refers to
the same object as s - it is not a class, it is an instance of the class.
1
object here is the class your new class inherits from. There is already a base class named object, but there is no class named obj which is why replacing object with obj would cause an error. Anyway in your example code it is not needed at all since all classes in python 3 implicitly extends the object class.
2
__init__ is the constructor of the object and self there represents the object that you are creating itself, not the class, just like in the other methods you made.
Point 1:
Some history required here... Originally Python had two distinct kind of types, those implemented in C (whether in the stdlib or C extensions) and those implemented in Python with the class statement. Python 2.2 introduced a new object model (known as "new-style classes") to unify both, but kept the "classic" (aka "old-style") model for compatibility. This new model also introduced quite a lot of goodies like support for computed attributes, cooperative super calls via the super() object, metaclasses etc, all of which coming from the builtin object base class.
So in Python 2.2.x to 2.7.x, you can either create a new-style class by inheriting from object (or any subclass of object) or an old-style one by not inheriting from object (nor - obviously - any subclass of object).
In Python 2.7., since your example Stack class does not use any feature of the new object model, it works as well as an 'old-style' or as a 'new-style' class, but try to add a custom metaclass or a computed attribute and it will break in one way or another.
Python 3 totally removed old-style classes support and object is the defaut base class if you dont explicitely specify one, so whatever you do your class WILL inherit from object and will work as well with or without explicit parent class.
You can read this for more details.
Point 2.1 - I'm not sure I understand the question actually, but anyway:
In Python, objects are not fixed C-struct-like structures with a fixed set of attributes, but dict-like mappings (well there are exceptions but let's ignore them for the moment). The set of attributes of an object is composed of the class attributes (methods mainly but really any name defined at the class level) that are shared between all instances of the class, and instance attributes (belonging to a single instance) which are stored in the instance's __dict__. This imply that you dont define the instance attributes set at the class level (like in Java or C++ etc), but set them on the instance itself.
The __init__ method is there so you can make sure each instance is initialised with the desired set of attributes. It's kind of an equivalent of a Java constructor, but instead of being only used to pass arguments at instanciation, it's also responsible for defining the set of instance attributes for your class (which you would, in Java, define at the class level).
Point 2.2 : self is the current instance of the class (the instance on which the method is called), so if s is an instance of your Stack class, s.push(42) is equivalent to Stack.push(s, 42).
Note that the argument doesn't have to be called self (which is only a convention, albeit a very strong one), the important part is that it's the first argument.
How s get passed as self when calling s.push(42) is a bit intricate at first but an interesting example of how to use a small feature set to build a larger one. You can find a detailed explanation of the whole mechanism here, so I wont bother reposting it here.
In Python 2.7.10
class OneMixin(object):
def __init__(self):
# super(OneMixin, self).__init__()
print "one mixin"
class TwoMixin(object):
def __init__(self):
# super(TwoMixin, self).__init__()
print "two mixin"
class Account(OneMixin, TwoMixin):
def __init__(self):
super(Account, self).__init__()
print "account"
The Account.mro() is: [<class 'Account'>, <class 'OneMixin'>, <class 'TwoMixin'>, <type 'object'>]
Although every class is listed in the MRO, "two mixin" is not printed.
If I uncomment the super calls in OneMixin and TwoMixin, the MRO is exactly the same, but the "two mixin" IS printed.
Why the difference? I would expect every thing in the MRO to be called.
This is because super is used to delegate the calls to either parent or sibling class of a type. Python documentation has following description of the second use case:
The second use case is to support cooperative multiple inheritance in a dynamic execution environment. This use case is unique to Python and is not found in statically compiled languages or languages that only support single inheritance. This makes it possible to implement “diamond diagrams” where multiple base classes implement the same method. Good design dictates that this method have the same calling signature in every case (because the order of calls is determined at runtime, because that order adapts to changes in the class hierarchy, and because that order can include sibling classes that are unknown prior to runtime).
If you remove the super call from OneMixin there's nothing delegating the call to the next type in MRO.
The reason is that you're overriding the __init__ method of the parent class. The method resolution order will be the same, regardless of what is in your __init__ method.
The way super works is that it will pass it down to the next class down the line in the method resolution order. By commenting out that line in OneMixin, you break the chain. super is designed for cooperative inheritance.
Also, __init__ is not truly a class constructor, either. This may trip you up if you think of it as you would a constructor in other languages.
In C# I would go:
myObj.base
I have a Date class which inherits from date.datetime. The Date class overrides __gt__() and __lt__() so when using the < and > operators they are called. I do not want to use these overrides - I want to use the date.datetime methods on an instance of Date.
Use super() to get the superclass object. Type help(super) in the Python command prompt.
From the manual:
class super(object)
| super(type) -> unbound super object
| super(type, obj) -> bound super object; requires isinstance(obj, type)
| super(type, type2) -> bound super object; requires issubclass(type2, type)
| Typical use to call a cooperative superclass method:
| class C(B):
| def meth(self, arg):
| super(C, self).meth(arg)
If I understand your question correctly, this doesn't make sense in Python. There's no "base instance" inside the instance of a subclass.
A Python instance is just one thing, containing a collection of attributes (any of which may have been set/modified by any of its base classes, or indeed from code outside any of its classes at all). Indeed it's possible to change the class of an instance at runtime, even transplanting it into an entirely different inheritance heirarchy (this is not frequently a good idea, but it's well-defined). No matter what, the instance remains a single unitary object, which only knows what attributes it has and which class it's an instance of (and in fact that's just an attribute: __class__).
Edit: If what you want is to be able to invoke overridden methods on an instance, then you do that by using super, as hocl answered. However it seems from your comments that you do not fully grok what super is doing (which is natural, as it's quite complex).
super(Date, myObj) doesn't return "the underlying datetime.date" instance, because there's no such thing, only the myObj object. Although for your purposes it sounds like this will fill your needs (and you can probably stop at this sentence).
What it does is return is a magical wrapper around myObj that looks up methods starting just "behind" Date; i.e. it finds the method that would be called if Date didn't override it. So in this case it will find all methods from datetime.date, because you only have single inheritance going on.
A key difference is that this supports multiple inheritance. If someone makes another class that inherits from Date and also inherits from datetime.date by another path, then super(Date, instanceOfThatClass) may not actually hit datetime.date's methods. It depends on the details of that inheritance heirarchy. This is actually the situation super was designed for though; it enabled classes in complex multiple inheritance hierarchies to cooperatively call each other's implementations, ensuring that each is called only once, and in an order that is sensible (though it may not be the same order for each ultimate leaf class, so classes in the middle of the hierarchy actually don't know which super-class implementation they're calling). My understanding is this complex situation cannot arise in C#, hence it can provide a simple .base syntax.
My understanding is also (and this is a bit of a guess), that because C# is statically typed and supports inheriting from classes defined in pre-compiled libraries, that when you have class Sub inheriting from class Base, inside an instance of Sub there really is a complete instance of Base which you can get at and then call methods on. This will affect shadowed fields; I would expect (again, as a non-C# programmer guessing a bit) that after getting the Base instance from a Sub instance, any direct reference to a field overridden by Sub would hit the field from Base, not the one from Sub.
In Python, OTOH, there is no base instance, and classes can't override fields. If the constructor and methods of Date and datetime.date both refer to the same field, it's just the one field in the instance that they're both sharing. So using super won't change what field you'll access, as you might expect if you think of it as getting the base instance.
Given that you're not using a complex multiple inheritance situation, if you wanted a simple syntax you could actually call Date.__lt__(myObj, otherObj) directly, though it looks ugly because you don't get to use the infix operator syntax when you do it that way. It's less horrible if you're considering ordinary methods; in that case it's possibly simpler than using super.
Take home message: I'm pretty sure super(Date, myObj) is what you want in this case. But if you get into more complicated situations, you don't want to think of super as the way to get "the base instance", like you would in C#. That understanding will trip you up when in multiple inheritance (which can be bloody confusing anyway), but also when you have multiple layers in the inheritance hierarchy using the same field.
I see everywhere examples that super-class methods should be called by:
super(SuperClass, instance).method(args)
Is there any disadvantage to doing:
SuperClass.method(instance, args)
Consider the following situation:
class A(object):
def __init__(self):
print('Running A.__init__')
super(A,self).__init__()
class B(A):
def __init__(self):
print('Running B.__init__')
# super(B,self).__init__()
A.__init__(self)
class C(A):
def __init__(self):
print('Running C.__init__')
super(C,self).__init__()
class D(B,C):
def __init__(self):
print('Running D.__init__')
super(D,self).__init__()
foo=D()
So the classes form a so-called inheritance diamond:
A
/ \
B C
\ /
D
Running the code yields
Running D.__init__
Running B.__init__
Running A.__init__
That's bad because C's __init__ is skipped. The reason for that is because B's __init__ calls A's __init__ directly.
The purpose of super is to resolve inheritance diamonds. If you un-comment
# super(B,self).__init__()
and comment-out
A.__init__(self)
the code yields the more desireable result:
Running D.__init__
Running B.__init__
Running C.__init__
Running A.__init__
Now all the __init__ methods get called. Notice that at the time you define B.__init__ you might think that super(B,self).__init__() is the same as calling A.__init__(self), but you'd be wrong. In the above situation, super(B,self).__init__() actually calls C.__init__(self).
Holy smokes, B knows nothing about C, and yet super(B,self) knows to call C's __init__? The reason is because self.__class__.mro() contains C. In other words, self (or in the above, foo) knows about C.
So be careful -- the two are not fungible. They can yield vastly different results.
Using super has pitfalls. It takes a considerable level of coordination between all the classes in the inheritance diagram. (They must, for example, either have the same call signature for __init__, since any particular __init__ would not know which other __init__ super might call next, or
else use **kwargs.) Furthermore, you must be consistent about using super everywhere. Skip it once (as in the above example) and you defeat the entire purpose of super.
See the link for more pitfalls.
If you have full control over your class hierarchy, or you avoid inheritance diamonds, then there is no need for super.
There's no penalty as-is, though your example is somewhat misguided. In the first example, it should be
super(SubClass, instance).method(args) # Sub, not SuperClass
and that leads me to quote the Python docs:
There are two typical use cases for super. In a class hierarchy with single inheritance, super can be used to refer to parent classes without naming them explicitly, thus making the code more maintainable. This use closely parallels the use of super in other programming languages.
The second use case is to support cooperative multiple inheritance in a dynamic execution environment. This use case is unique to Python and is not found in statically compiled languages or languages that only support single inheritance. This makes it possible to implement “diamond diagrams” where multiple base classes implement the same method. Good design dictates that this method have the same calling signature in every case (because the order of calls is determined at runtime, because that order adapts to changes in the class hierarchy, and because that order can include sibling classes that are unknown prior to runtime).
Basically, by using the first method you don't have to hard-code your parent class in there for single-class hierarchies, and you simply can't really do what you want (efficiently/effectively) using the second method when using multiple inheritance.
I have read posts like these:
What is a metaclass in Python?
What are your (concrete) use-cases for metaclasses in Python?
Python's Super is nifty, but you can't use it
But somehow I got confused. Many confusions like:
When and why would I have to do something like the following?
# Refer link1
return super(MyType, cls).__new__(cls, name, bases, newattrs)
or
# Refer link2
return super(MetaSingleton, cls).__call__(*args, **kw)
or
# Refer link2
return type(self.__name__ + other.__name__, (self, other), {})
How does super work exactly?
What is class registry and unregistry in link1 and how exactly does it work? (I thought it has something to do with singleton. I may be wrong, being from C background. My coding style is still a mix of functional and OO).
What is the flow of class instantiation (subclass, metaclass, super, type) and method invocation (
metaclass->__new__, metaclass->__init__, super->__new__, subclass->__init__ inherited from metaclass
) with well-commented working code (though the first link is quite close, but it does not talk about cls keyword and super(..) and registry). Preferably an example with multiple inheritance.
P.S.: I made the last part as code because Stack Overflow formatting was converting the text metaclass->__new__
to metaclass->new
OK, you've thrown quite a few concepts into the mix here! I'm going to pull out a few of the specific questions you have.
In general, understanding super, the MRO and metclasses is made much more complicated because there have been lots of changes in this tricky area over the last few versions of Python.
Python's own documentation is a very good reference, and completely up to date. There is an IBM developerWorks article which is fine as an introduction and takes a more tutorial-based approach, but note that it's five years old, and spends a lot of time talking about the older-style approaches to meta-classes.
super is how you access an object's super-classes. It's more complex than (for example) Java's super keyword, mainly because of multiple inheritance in Python. As Super Considered Harmful explains, using super() can result in you implicitly using a chain of super-classes, the order of which is defined by the Method Resolution Order (MRO).
You can see the MRO for a class easily by invoking mro() on the class (not on an instance). Note that meta-classes are not in an object's super-class hierarchy.
Thomas' description of meta-classes here is excellent:
A metaclass is the class of a class.
Like a class defines how an instance
of the class behaves, a metaclass
defines how a class behaves. A class
is an instance of a metaclass.
In the examples you give, here's what's going on:
The call to __new__ is being
bubbled up to the next thing in the
MRO. In this case, super(MyType, cls) would resolve to type;
calling type.__new__ lets Python
complete it's normal instance
creation steps.
This example is using meta-classes
to enforce a singleton. He's
overriding __call__ in the
metaclass so that whenever a class
instance is created, he intercepts
that, and can bypass instance
creation if there already is one
(stored in cls.instance). Note
that overriding __new__ in the
metaclass won't be good enough,
because that's only called when
creating the class. Overriding
__new__ on the class would work,
however.
This shows a way to dynamically
create a class. Here's he's
appending the supplied class's name
to the created class name, and
adding it to the class hierarchy
too.
I'm not exactly sure what sort of code example you're looking for, but here's a brief one showing meta-classes, inheritance and method resolution:
print('>>> # Defining classes:')
class MyMeta(type):
def __new__(cls, name, bases, dct):
print("meta: creating %s %s" % (name, bases))
return type.__new__(cls, name, bases, dct)
def meta_meth(cls):
print("MyMeta.meta_meth")
__repr__ = lambda c: c.__name__
class A(metaclass=MyMeta):
def __init__(self):
super(A, self).__init__()
print("A init")
def meth(self):
print("A.meth")
class B(metaclass=MyMeta):
def __init__(self):
super(B, self).__init__()
print("B init")
def meth(self):
print("B.meth")
class C(A, B, metaclass=MyMeta):
def __init__(self):
super(C, self).__init__()
print("C init")
print('>>> c_obj = C()')
c_obj = C()
print('>>> c_obj.meth()')
c_obj.meth()
print('>>> C.meta_meth()')
C.meta_meth()
print('>>> c_obj.meta_meth()')
c_obj.meta_meth()
Example output (using Python >= 3.6):
>>> # Defining classes:
meta: creating A ()
meta: creating B ()
meta: creating C (A, B)
>>> c_obj = C()
B init
A init
C init
>>> c_obj.meth()
A.meth
>>> C.meta_meth()
MyMeta.meta_meth
>>> c_obj.meta_meth()
Traceback (most recent call last):
File "metatest.py", line 41, in <module>
c_obj.meta_meth()
AttributeError: 'C' object has no attribute 'meta_meth'
Here's the more pragmatic answer.
It rarely matters
"What is a metaclass in Python". Bottom line, type is the metaclass of all classes. You have almost no practical use for this.
class X(object):
pass
type(X) == type
"What are your (concrete) use cases for metaclasses in Python?". Bottom line. None.
"Python's Super is nifty, but you can't use it". Interesting note, but little practical value. You'll never have a need for resolving complex multiple inheritance networks. It's easy to prevent this problem from arising by using an explicity Strategy design instead of multiple inheritance.
Here's my experience over the last 7 years of Python programming.
A class has 1 or more superclasses forming a simple chain from my class to object.
The concept of "class" is defined by a metaclass named type. I might want to extend the concept of "class", but so far, it's never come up in practice. Not once. type always does the right thing.
Using super works out really well in practice. It allows a subclass to defer to it's superclass. It happens to show up in these metaclass examples because they're extending the built-in metaclass, type.
However, in all subclass situations, you'll make use of super to extend a superclass.
Metaclasses
The metaclass issue is this:
Every object has a reference to it's type definition, or "class".
A class is, itself, also an object.
Therefore a object of type class has a reference to it's type or "class". The "class" of a "class" is a metaclass.
Since a "class" isn't a C++ run-time object, this doesn't happen in C++. It does happen in Java, Smalltalk and Python.
A metaclass defines the behavior of a class object.
90% of your interaction with a class is to ask the class to create a new object.
10% of the time, you'll be using class methods or class variables ("static" in C++ or Java parlance.)
I have found a few use cases for class-level methods. I have almost no use cases for class variables. I've never had a situation to change the way object construction works.