How super() implements in python programming [duplicate] - python

This question already has answers here:
How does Python's super() work with multiple inheritance?
(18 answers)
Closed 9 years ago.
I am new to python programming,
below is the example of parent,child classes,There are two direct super classes (i.e. bases) of C: A and B. A comes before B, so one would naturally think that the super class of C is A. However, A inherits its attribute a from T with value a=0: if super(C,c) was returning the superclass of C, then super(C,c).a would return 0 but its won't?
Could you please help me to understand why its returning 2.why not 0
>>> class T(object):
... a = 0
>>> class A(T):
... pass
>>> class B(T):
... a = 2
>>> class C(A,B):
... pass
>>> c = C()
>>>super(C,c).a
2
Thanks,
Hema

It has to do with Python method resolution order, or MRO. The precise definition of Python's MRO is here: Python 2.3's MRO doc. Edit: this explanation by Guido seems easier to read, and it includes an example exactly like yours.
If you call __mro__ on a class, you'll see the order in which it looks up stuff. In this case:
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.T'>, <type 'object'>)
So there you can see that it goes to B first, and only then to T. The reason is that it would otherwise be impossible to override attributes from T in B in this structure, and that's unlikely to be the desired behaviour.
Personally I just always avoid this diamond-style inheritance pattern, except of course for object which is the base class of every other class.

Related

Python OOP - explain how does work static with type(self)

I've seen examples of how I can make a static variable in a class. Here is an example:
class A:
_i = 0
#property
def i(self):
print(type(self)) # <class '__main__.A'>
return type(self)._i
#i.setter
def i(self, val):
type(self)._i = val
How does it work? How does type(self) work and make these variables static?
What does < class '__main__.A' > mean in OOP and polymorphism?
How type(self) works
It just returns the type of self. You can call type on any object to get its type:
>>> type(2)
int
>>> class C(object): pass
>>> type(C)
type
>>> c = C()
>>> type(c)
__main__.C
(The output may look slightly different on Python 2 vs. Python 3, or on different Python implementations.)
… and make that variables are static?
Well, first, these aren't static variables, they're class variables. If you don't have any inheritance, there's no difference—but if you do… I'll come back to that.
If you create an instance:
>>> a = A()
… and assign a value to i:
>>> a.i = 3
… it calls the setter for the i property, passing a as the self parameter—just like a normal method call.
So, since self is a, and type(a) is A, then type(self) is also A.
Which means type(self)._i is A._i. In other words, it's the class attribute.
So, why is this a class attribute rather than a static attribute? Well, let's add a subclass:
>>> a = A()
>>> class B(A):
... _i = 1
>>> b = B()
>>> b.i = 5
>>> A._i
0
>>> B._i
5
Each subclass can have its own _i. And because the setter is setting type(self)._i, when self is b, so type(self) is B, type(self)._i is B._i, not A._i.
What does it < class '__main__.A' > mean in OOP and polymorphism
In Python, everything has a repr, meant for programmers, that gets printed out when you evaluate it at the interactive prompt. It's also used as the str (the thing that gets printed by print) if there's nothing better to use as a human-readable (as in real humans, not us programmers) representation.
In general, a repr is either:
A string that could be pasted into your code to produce an equal value, if that makes sense and is possible/reasonable.
A string inside <> that includes the type, some kind of identifying information if there is any, and some way to distinguish the object from other instances, otherwise.
For types, what you get inside the angle brackets is the fact that it's a class (that's the class part), and the qualified name (that's the __main__.A part, telling you that it's a class named A defined at the top level of a module named __main__), which is both the useful identifier and the way to distinguish it from other classes.
What does is mean specifically in OOP and polymorphism? I can't think of a good answer to that. Even if Python didn't support polymorphism, even if it didn't have first-class types, __main__.A and __main__.B would still be different objects worthy of distinct names, right?
And if you're wondering what kind of name __main__ is: that's just the name of the special module used to run your top-level script or your interactive interpreter session. If you've ever seen a if __name__ == '__main__': guard, that's exactly what it's testing.
type() returns the class that an instance was constructed from. I.e. if you do foo = A() (create a new instance of A and assign it to foo), then type(foo) returns A again. That's what <class '__main__.A'> is, it tells you it's the A class object.
Now all you're doing with type(self)._i is the same as A._i. That _i is an attribute of the class A object, which only exists once. Et voilà, that's all that "static" attributes are.

Change the behavior of the type() function on a user-created class

So I want to change how the type() function works on a class that I create. I'll create two classes, one "old style" class and one "new style" which inherits from object, to demonstrate what I mean:
class Foo:
pass
class Bar(object):
pass
Now I'll create an instance of each of those:
spam = Foo()
eggs = Bar()
What happens if I use the type() function on each of these classes?
>>> type(spam)
<type 'instance'>
>>> type(eggs)
<class '__main__.Bar'>
I'm looking for a way to alter the behavior of this so that it appears more like this:
>>> type(spam)
<type 'foo'>
I've seen many other objects do this (besides the default data types obviously). For example:
>>> x = iter(['a', 'b', 'c'])
>>> type(x)
<type 'listiterator'>
>>> y = (i for i in range(10))
>>> type(y)
<type 'generator'>
Something like this would come pretty close, but I would prefer not to have the membership dot in the middle if I can help it. (Yes, the code I am using this in will be an imported file.)
>>> from itertools import *
>>> z = imap(pow, (2, 3, 4), (5, 2, 4))
>>> type(z)
<type 'itertools.imap'>
I'm sure the answer to this question is really simple, but for whatever reason I can't figure out how to word a search query on this. Any help would be appreciated.
What type returns when called with a single is the class of an object. The string you see printed there is its "representation", and it is generated by a call to repr for the class. itself - the repr is called by the interactive prompt. Python objects customize their representation by defining a __repr__ method.
Since you want to customize the __repr__ of the class, and not of its instances, you have to overide the method in the class's class itself. In Python that is called metaclass.
The base metaclass for all Python "new style" objects is type itself. type is much more than a simple function to return an object's class - it is actually that thing: the "base metaclass" for everything. (Old style classes have a different metaclass - but them you should not be using old style classes for anything. At all. Seriously. Actually, you should be using Python 3 by now - but if you aren't changing, please just forget old style classes exist)
So, to customize a class's class, you create a new class inheriting from type itself. You will find several blog posts and documentation explaining how to do that and override __new__, or __init__. But in this case, you
don't need to change the actual behavior of your classes cretion - just the way they are represented.
You can just do:
class MyType(type):
def __repr__(cls):
return "<type '{}'>".format (cls.__name__)
class Foo(object):
__metaclass__ = MyType
And it will work as you want. Note that I put the argument for the metaclass' __repr__ as cls instead of self - that is jsut for semantic purposes - it will receive an "instance" of itself - but the instance is a class. It would just work if "self" was used.
And finally, that will also change how your instances are represented by default - and that represenation can get ugly. If you dislike it, just write the __repr__ method for your class as well (not just for the metaclass) , further customizing how it renders its representation to string form.

Inheritance Networks in Python

I am new to python and I am trying to draw the inheritance network for a number of classes. I want to number each class in the drawing showing in what order the class objects are searched for attributes (1=first, 2=second, etc.) in object g = G(). Here is what am trying to simulate:
class A : pass
class C : pass
class B(A,C) : pass
class D(A) : pass
class E(B,C) : pass
class F(C) : pass
class G(D,E,F): pass
I went and made the following network. Is there any way to improve upon it, and have I done it this correctly?
Your diagram is almost right as far as showing the inheritance relationships between the classes you've shown. The arrow from B to E should run in the other direction, but everything else is right.
As for numbering the classes in the diagram based on the order they'll be checked in a lookup on an instance of class G, I suggest calling G.mro(). This will give you a list of the classes in the order they'll be searched.
Here's what I get for your example classes:
[<class '__main__.G'>,
<class '__main__.D'>,
<class '__main__.E'>,
<class '__main__.B'>,
<class '__main__.A'>,
<class '__main__.F'>,
<class '__main__.C'>,
<class 'object'>]
If you want to understand how this order is found, you should read up about the C3 linearization algorithm that Python uses. A good place to start is this article written about the new algorithm when it was introduced in Python 2.3.

what is diff between both of class definition [duplicate]

This question already has answers here:
Why do Python classes inherit object?
(6 answers)
Closed 5 years ago.
In Python 2, classes should explicitly be defined as subclasses of object. In Python 3, this will be the
default.
>>> class A(object):
pass
>>> class B():
pass
>>> type(B)
<type 'classobj'>
>>> type(A)
<type 'type'>
I use Python 2.7 and as I know in 2.7 class inherits from object.
That is a so-called "new style object", introduced in python 2.2.
New style objects have a different object model to classic objects, and some things won't work properly with old style objects, for instance, super(), #property and descriptors.
More on it in the famous question:
Python class inherits object
Please also refer to:
https://docs.python.org/release/2.2.3/whatsnew/sect-rellinks.html
Also, please note that there is a difference between them only in Python 2. In Python 3 you have no difference between these two types of declaration anymore (I know that your question is about Python 2, just a small note).

How to get the parents of a Python class?

How can I get the parent class(es) of a Python class?
Use the following attribute:
cls.__bases__
From the docs:
The tuple of base classes of a class
object.
Example:
>>> str.__bases__
(<type 'basestring'>,)
Another example:
>>> class A(object):
... pass
...
>>> class B(object):
... pass
...
>>> class C(A, B):
... pass
...
>>> C.__bases__
(<class '__main__.A'>, <class '__main__.B'>)
If you want all the ancestors rather than just the immediate ones, use cls.__mro__.
For versions of Python earlier than 3.5, use inspect.getmro:
import inspect
print inspect.getmro(cls)
Usefully, this gives you all ancestor classes in the "method resolution order" -- i.e. the order in which the ancestors will be checked when resolving a method (or, actually, any other attribute -- methods and other attributes live in the same namespace in Python, after all;-).
The fastest way to get all parents, and in order, is to just use the __mro__ built-in.
For instance, repr(YOUR_CLASS.__mro__).
The following:
import getpass
getpass.GetPassWarning.__mro__
...outputs, in order:
(<class 'getpass.GetPassWarning'>, <type 'exceptions.UserWarning'>, <type 'exceptions.Warning'>, <type 'exceptions.Exception'>, <type 'exceptions.BaseException'>, <type 'object'>)
There you have it. The "best" answer may have more votes but this is so much simpler than some convoluted for loop, looking into __bases__ one class at a time, not to mention when a class extends two or more parent classes. Importing and using inspect just clouds the scope unnecessarily.
New-style classes have an mro method you can call which returns a list of parent classes in method resolution order.
Use bases if you just want to get the parents, use __mro__ (as pointed out by #naught101) for getting the method resolution order (so to know in which order the init's were executed).
Bases (and first getting the class for an existing object):
>>> some_object = "some_text"
>>> some_object.__class__.__bases__
(object,)
For mro in recent Python versions:
>>> some_object = "some_text"
>>> some_object.__class__.__mro__
(str, object)
Obviously, when you already have a class definition, you can just call __mro__ on that directly:
>>> class A(): pass
>>> A.__mro__
(__main__.A, object)
If you want to ensure they all get called, use super at all levels.
If you have a variable and want to get its class and parent classes use type() method which will give class for a variable
val="happy coding"
print(type(val).__mro__)
Output:
(<class 'str'>, <class 'object'>)
This funciton will print the all the classes of an object, while in each step the next object will the left most parent.
def print_root_left(class_):
while True:
print(class_)
# Check there if are no bases then we have reached the root class
if not class_.__bases__:
break
class_=class_.__bases__[0] # use the left most parent
example = "hello"
print_root_left(example.__class__)

Categories

Resources