How to get the parents of a Python class? - python

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__)

Related

Python 3.9 MetaClass Property vs Classmethod Property

Consider the following code
from abc import ABC, ABCMeta
class MyMetaClass(ABCMeta):
#property
def metaclass_property(cls):
return "result"
# def __dir__(cls):
# return list(super().__dir__()) + ['metaclass_property']
class MyBaseClass(ABC, metaclass=MyMetaClass):
#classmethod
#property
def baseclass_property(cls):
return "result"
class MyClass(MyBaseClass, metaclass=MyMetaClass):
pass
assert MyClass.baseclass_property == "result"
assert hasattr(MyClass, 'baseclass_property')
assert 'baseclass_property' in dir(MyClass)
assert MyClass.metaclass_property == "result"
assert hasattr(MyClass, 'metaclass_property')
assert 'metaclass_property' in dir(MyClass)
I noticed that this throws an assertion error on the last line. (python v3.9.6). Why is that? Is it a bug? It can be fixed by manually adding it to __dir__ as per the two uncommented lines.
My question is, what is the best way to resolve this? Is there any fundamental difference between a classmethod property or a metaclass property? (I.e. are there any things that I can or cannot do in one but not the other?) If not, which one should I preferably use?
I think this has nothing to do with properties, metaclasses or abc.
A simple example:
>>> int.__mro__
(<class 'int'>, <class 'object'>)
>>> isinstance(int, type)
True
>>> '__mro__' in dir(int)
False
>>> '__mro__' in dir(type)
True
In this example, object is the base class of int, while type is the metaclass of int.
The official documentation of the dir function explicitly says that it
attempts to produce the most relevant, rather than complete, information
and
If the object is a type or class object, the list contains the names of its attributes, and recursively of the attributes of its bases.
and
metaclass attributes are not in the result list when the argument is a class

Method resolution order (__mro__) not available in Python3.x?

I wonder about that it seems like that the method resolution order attribute mro is not available in Python 3.x anymore. Using Python 3.5.2 and creating a random class object instance A, built-in or self-implemented, for example
A = dict()
and then calling
A.__mro__
doesnt work, raising
AttributeError: 'A' object has no attribute '__mro__'
I tried to use A.mro(), but this gives the same type of exception.
How do I receive the method resolution order now?
That doesn't work on instances. The error hints that the variable A in question is not bound to a type, but to an instance of class A. types (classes) very much do have __mro__:
>>> int.__mro__
(<class 'int'>, <class 'object'>)
>>> class Foo():
... pass
...
>>> Foo.__mro__
(<class '__main__.Foo'>, <class 'object'>)
Since A is an instance of a type and not the type itself, you can use type(A).__mro__.
Additionally, your code wouldn't have worked in Python 2 either; no, instances didn't have __mro__ there either.

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.

Why do metaclass have a type?

I've little bit test to fully understand metaclass in python.
class Test(object):
pass
print Test.__class__
print Test.__class__.__class__
print Test.__class__.__class__.__class__
All of result is same type. but each of their address is not same
I can't really understand why metaclass has a metaclass recursively.
Explain me please?
Actually, addresses are the same:
>>> id(Test.__class__)
6384576
>>> id(Test.__class__.__class__)
6384576
>>> id(Test.__class__.__class__.__class__)
6384576
Everything is an object in Python, and each object must have a class (it should belong to some type). You can access that class/type reference by __class__ attribute, e.g.:
>>> (1).__class__
<type 'int'>
Everything includes classes itself, which are of class/type called type:
>>> (1).__class__.__class__
<type 'type'>
In the same time type 'type'> is also an object and should reference to some class/type. But since this is kind of special object, its __class__ attribute refers to itself:
>>> (1).__class__.__class__.__class__ is (1).__class__.__class__
True
When you do Test.__class__, you get back the type of Test, which is type (because Test is a class identifier).
type itself is again a class identifier, so you can call __class__ (which is inherited from object) on it and you get back that its type is, again, type because it is a class identifier.
Because you will always get back type which is a class itself, you can do this infinitely many times and will always get back that the current object's type is type.
All classes are classes which means they are derived from a class called class...
All the python's class object is build by the built-in function type(). You could also try this.
>>> T.__class__ == type
True
>>> type(type)
<type 'type'>
The T.class is equal to the build-in function type which is also an object implemented the call function. It's a attribute will be interpret as class(T). As your T class have no base class so type() is used which will return the type object.
You could check the python doc about customizing class creation to get detail about class creation.
To determining the appropriate metaclass
if no bases and no explicit metaclass are given, then type() is used
if an explicit metaclass is given and it is not an instance of type(), then it is used directly as the metaclass
if an instance of type() is given as the explicit metaclass, or bases are defined, then the most derived metaclass is used

Change C object instance to Python subclass

Is it possible to change a class of a C object to a python subclass?
I am using PyGTK, and I have a ListModel that I have wrapped my own class around, but I want to turn it into a TreeModelFilter. The directions tell me to create it by doing:
class MyListStore(gtk.ListStore):
def __init__(self, title):
self.title = title
liststore = MyListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
modelfilter = liststore.filter_new()
So I thought I could just create:
class MyFilteredListStore(gtk.TreeModelFilter):
def __init__(self, title):
self.title = title
But I don't know how to use filter_new to use my class, instead of gtk.TreeModelFilter.
Inheritance can be a very fluid concept in python. For starters, you should always use new style classes. To do that, make sure your classes should always inherit from "object".
It's important to note that Classes must inherit from other classes, not instances of other classes, so your example really wouldn't work there. In fact, I don't really see the difference between inheriting from X or x1.
Inheritance in python is closely tied to the "Method Resolution Order" (MRO). You can view an objects MRO using the inspect module.
>>> import inspect
>>> import pprint
>>>
>>> class X(object):
... pass
...
>>> class Y(X):
... pass
...
>>>
>>> pprint.pprint(inspect.getmro(Y))
(<class '__main__.Y'>, <class '__main__.X'>, <type 'object'>)
>>>
The tuple at the end shows the order in which python will try to resolve method and attribute calls. You can modify the MRO at runtime by modifying a class's __bases__ attribute.
>>> Y.__bases__
(<class '__main__.X'>,)
>>>
>>> class Z(object):
... pass
...
>>> Y.__bases__ = tuple([Z])
>>> pprint.pprint(inspect.getmro(Y))
(<class '__main__.Y'>, <class '__main__.Z'>, <type 'object'>)
>>>
This can get complicated if any of your classes use multiple inheritance, or if you want to preserve certain parts of the inheritance tree but not others.
The best way to handle this problem is not to subclass the TreeModel, but to assign a variable to the object that can be the ListStore or the TreeModelFilter.
class MyListStore(object):
def __init__(self, title, filter=None):
self.title = title
self._model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
if filter_func:
self._model = self.model.filter_new()
self._model.set_visible_func(filter)
I think this is the best way to get around this.
Edit
For anyone interested, I found the following to be helpful to keep from breaking old code. It acts like inheritance, without actually doing so:
def __getattr__(self, name):
'Get the attribute from the model if possible.'
if hasattr(self._model, name):
return getattr(self._model, name)
if isinstance(self._model, gtk.TreeModelFilter):
if hasattr(self._model.get_model(), name):
return getattr(self._model.get_model(), name)

Categories

Resources