Get overridden functions of subclass - python

Is there a way to get all overriden functions of a subclass in Python?
Example:
class A:
def a1(self):
pass
def a2(self):
pass
class B(A):
def a2(self):
pass
def b1(self):
pass
Here, I would like to get a list ["a2"] for an object of class B (or for the class object itself) since class B overrides only a single method, namely a2.

You can access the parent classes with cls.__bases__, find all attributes of the parents with dir, and access all the attributes of the class itself with vars:
def get_overridden_methods(cls):
# collect all attributes inherited from parent classes
parent_attrs = set()
for base in cls.__bases__:
parent_attrs.update(dir(base))
# find all methods implemented in the class itself
methods = {name for name, thing in vars(cls).items() if callable(thing)}
# return the intersection of both
return parent_attrs.intersection(methods)
>>> get_overridden_methods(B)
{'a2'}

You can make use of the __mro__ tuple, which holds the method resolution order.
For your example:
>>> B.__mro__
( <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
So you could loop over that tuple and check if a B method is also in one of the other classes.

class A:
def a1(self):
pass
def a2(self):
pass
class B(A):
def a2(self):
super().a2()
pass
def b1(self):
pass
obj = B()
obj.a2() # ***first give the output of parent class then child class***

Related

How would I find where a function originates in source code?

I'm having trouble actually following the source code, mostly because simply using grep on it isn't working.
Is there any way to find out from which class a certain method was inherited? For example, if there is class A, which has method foo() and bar(), and there is class B which has biz(), and class C which inherits all of it's attributes and methods from both A and B, how would I be able to determine which class foo() came from (without strictly looking at the source manually)?
You can always access the super-classes of a class by looking in the __bases__ attribute for that class. Given three simple classes A, B, C (which for Py2.7 must inherit from object) :
class A:
def foo():
pass
def bar():
pass
class B:
def biz(): pass
class C(A, B):
pass
You can then iterate through the __bases__ for C and check whether an attribute, function foo (for example), exists in one of these classes.
To do this you can check for membership of foo in the __dict__ that holds the names for each class object in __bases__:
for base in C.__bases__:
if 'foo' in base.__dict__:
print("Attribute: '{}' defined in {}".format("foo", base))
Which prints:
Attribute: 'foo' defined in <class '__main__.A'>
For a more complete and general view:
# get all attributes of class C
vars = [classVar for classVar in dir(C) if not classVar.startswith('__')]
# iterate through all bases:
for base in C.__bases__:
for attr in vars:
if attr in base.__dict__:
print("Attribute: '{}' defined in {}".format(attr, base))
Which returns:
Attribute: 'bar' defined in <class '__main__.A'>
Attribute: 'foo' defined in <class '__main__.A'>
Attribute: 'biz' defined in <class '__main__.B'>
For all classes in the chain of inheritance you can switch __bases__ to __mro__ which indicates the method resolution order; a tuple of objects python searches when trying to resolve attribute references.
If we add a function to class C and make another class D that inherits from C:
class C(A, B):
def another(): pass
class D(C): pass
To get a view of where each function is defined, just switch __bases__ with __mro__ in the loop:
# hold D's attributes (functions names, variables.)
attrs = [var for var in dir(D) if not var.startswith('__')]
# vars contents: ['another', 'bar', 'biz', 'foo']
for base in D.__mro__:
for attr in attrs:
if attr in base.__dict__:
print("Attribute: '{}' defined in {}".format(attr, base))
Now, this follows the mro tuple (equal to (__main__.D, __main__.C, __main__.A, __main__.B, object) in this specific case) and yields a similar output:
Attribute: 'another' defined in <class '__main__.C'>
Attribute: 'bar' defined in <class '__main__.A'>
Attribute: 'foo' defined in <class '__main__.A'>
Attribute: 'biz' defined in <class '__main__.B'>
You can do checking through the parent classes as determined by the method resolution order and checking the members of each parent class:
for i in C.__mro__:
if 'bar' in i.__dict__:
print 'bar is in class ' + i.__name__
So, given the following classes definitions:
class A(object):
def foo(self): pass
def bar(self): pass
class B(object):
def biz(self): pass
class C(A,B): pass
Running the above code will give
bar is in class A

How do I get the instance method's next-in-line parent class from `super()` in Python

I'd like to know the type of an instance obtained from super() function. I tried print(super()) and __print(type(super()))__
class Base:
def __init__(self):
pass
class Derive(Base):
def __init__(self):
print(super())
print(type(super()))
super().__init__()
d = Derive()
The result is
<super: <class 'Derive'>, <Derive object>>
<class 'super'>
With those result, I was wondering how super().__init__() calls the correct constructor.
You can't do what you want with super() directly. Go to the class MRO (see class.__mro__) instead:
class Derive(Base):
def __init__(self):
mro = type(self).__mro__
parent = mro[mro.index(__class__) + 1]
print(parent)
Here __class__ is the magic closure variable* that references the class the current function was defined in; the above continues to work even when you subclass or mix in additional classes with Derive, even when you produce a diamond inheritance pattern.
Demo:
>>> class Base: pass
...
>>> class Derive(Base):
... def __init__(self):
... mro = type(self).__mro__
... parent = mro[mro.index(__class__) + 1]
... print(parent)
...
>>> Derive()
<class '__main__.Base'>
<__main__.Derive object at 0x10f7476a0>
>>> class Mixin(Base): pass
...
>>> class Multiple(Derive, Mixin): pass
...
>>> Multiple()
<class '__main__.Mixin'>
<__main__.Multiple object at 0x10f747ba8>
Note how the Multiple class inherits from both Derive and Mixin, and the next class in the MRO is thus found to be Mixin, not Base, because Mixin also derives from Base.
This copies what super() does; find the next class in the MRO for the instance, relative to the current class.
* For background, see Why is Python 3.x's super() magic?
From your comments, you want to know how super knows which method to call next. Super inspects the mro of the instance, knows the current class method it's in, and calls the next one in line. The following demo will work in Python 2 and 3, and in Python 2, it prints the name of each class thanks to the metaclass, so I'll use that output:
First the imports and setup to make the printing nicer:
import inspect
class Meta(type):
def __repr__(cls):
return cls.__name__
Next, we define a function to tell us what's going on based on the super object itself
def next_in_line(supobj):
print('The instance class: {}'.format(supobj.__self_class__))
print('in this class\'s method: {}'.format(supobj.__thisclass__))
mro = inspect.getmro(supobj.__self_class__)
nextindex = mro.index(supobj.__thisclass__) + 1
print('super will go to {} next'.format(mro[nextindex]))
Finally, we declare a class hierarchy based on the example from the wikipedia entry on C3 linearization, for a sufficiently complex example, note the metaclass repr doesn't work in Python3, but the attribute assignment won't break it. Also note that we use the full super call of super(Name, self) which is equivalent to super() in Python 3, and will still work:
class O(object):
__metaclass__ = Meta
def __init__(self):
next_in_line(super(O, self))
super(O, self).__init__()
class A(O):
def __init__(self):
next_in_line(super(A, self))
super(A, self).__init__()
class B(O):
def __init__(self):
next_in_line(super(B, self))
super(B, self).__init__()
class C(O):
def __init__(self):
next_in_line(super(C, self))
super(C, self).__init__()
class D(O):
def __init__(self):
next_in_line(super(D, self))
super(D, self).__init__()
class E(O):
def __init__(self):
next_in_line(super(E, self))
super(E, self).__init__()
class K1(A, B, C):
def __init__(self):
next_in_line(super(K1, self))
super(K1, self).__init__()
class K2(D, B, E):
def __init__(self):
next_in_line(super(K2, self))
super(K2, self).__init__()
class K3(D, A):
def __init__(self):
next_in_line(super(K3, self))
super(K3, self).__init__()
class Z(K1, K2, K3):
def __init__(self):
next_in_line(super(Z, self))
super(Z, self).__init__()
Now when we print the mro of Z, we get the method resolution order defined by this algorithm applied to the inheritance tree:
>>> print(inspect.getmro(Z))
(Z, K1, K2, K3, D, A, B, C, E, O, <type 'object'>)
And when we call Z(), because our function uses the mro, we'll visit each method in order:
>>> Z()
The instance class: Z
in this class's method: Z
super will go to K1 next
The instance class: Z
in this class's method: K1
super will go to K2 next
The instance class: Z
in this class's method: K2
super will go to K3 next
The instance class: Z
in this class's method: K3
super will go to D next
The instance class: Z
in this class's method: D
super will go to A next
The instance class: Z
in this class's method: A
super will go to B next
The instance class: Z
in this class's method: B
super will go to C next
The instance class: Z
in this class's method: C
super will go to E next
The instance class: Z
in this class's method: E
super will go to O next
The instance class: Z
in this class's method: O
super will go to <type 'object'> next
And we stop at object.__init__. From the above we can see that super always knows what class of the instance it is in, the class's method that it is currently in, and can deduce from the instance class's MRO where to go next.
I'd like to know the name of the base class?
If you only want the direct base (or more than one, in the case of multiple inheritance), you can use the __bases__ attribute, which returns a tuple
>>> Derive.__bases__
(<class __main__.Base at 0xffeb517c>,)
>>> Derive.__bases__[0].__name__
'Base'
I recommend the inspect module for getting the Method Resolution Order (which super follows based on the original caller's class):
>>> import inspect
>>> inspect.getmro(Derive)
(<class __main__.Derive at 0xffeb51dc>, <class __main__.Base at 0xffeb517c>)
Getting it from super
super().__self_class__ gives the instance class, and super().__thisclass__ gives us the current class. We can use the instance's MRO and look up the class that comes next. I presume you wouldn't do this in the final parent, so I'm not catching an index error:
class Base:
def __init__(self):
print(super().__self_class__)
print(super().__thisclass__)
class Derive(Base):
def __init__(self):
print(super().__self_class__)
print(super().__thisclass__)
mro = inspect.getmro(super().__self_class__)
nextindex = mro.index(super().__thisclass__) + 1
print('super will go to {} next'.format(mro[nextindex]))
super().__init__()
>>> d = Derive()
<class '__main__.Derive'>
<class '__main__.Derive'>
super will go to <class '__main__.Base'> next
<class '__main__.Derive'>
<class '__main__.Base'>

Naming conventions for class method vs instance method

I have two methods, one for the individual Instance, and one for every Instance in that class:
class MasterMatches(models.Model):
#classmethod
def update_url_if_any_matches_has_one(cls):
# apply to all instances, call instance method.
def update_url_if_any_matches_has_one(self):
# do something
Should I name these the same? Or, what is a good naming convention here?
The question of using the same names can be clarified by understanding how decorators work.
#dec
def foo(x):
print(x)
translates to
def foo(x):
print(x)
foo = dec(foo)
In your example the decorator syntax can be expanded to
class MasterMatches(models.Model):
def update_url_if_any_matches_has_one(cls):
# apply to all instances, call instance method.
update_url_if_any_matches_has_one = classmethod(update_url_if_any_matches_has_one)
def update_url_if_any_matches_has_one(self):
# do something
The former implementation of update_url_if_any_matches_has_one will be overwritten by the latter.
Usually use self declaration style. #classmethod use only if method not works with class instance fields.
Function decorated as #classmethod takes the first argument is the class type, while normal method takes instance of object.
class A:
#classmethod
def a(cls):
print(cls)
def b(self):
print(self)
a = A()
a.a()
a.b()
# Output:
# <class '__main__.A'>
# <__main__.A object at 0x03FC5DF0>
It can be useful if you have a static class fields. The to access therm you don't need explicitly specify the class name. But you don't get access to instance fields. Example:
class A:
field = 1
#classmethod
def a(cls):
print(cls.field)
def b(self):
self.field = 2
print(self.field, A.field)
a = A()
a.a()
a.b()
# Outputs:
# 1
# 2 1

How does multiple inheritance work in descriptors?

I watched a great video on YouTube about Python metaprogramming. I tried to write the following code (which is almost the same from the video):
class Descriptor:
def __init__(self, name):
self.name = name
def __get__(self, instance, cls):
return instance.__dict__[self.name]
def __set__(self, instance, val):
instance.__dict__[self.name] = val
def __delete__(self, instance):
del instance.__dict__[self.name]
class Type(Descriptor):
ty = object
def __set__(self, instance, val):
if not isinstance(val, self.ty):
raise TypeError("%s should be of type %s" % (self.name, self.ty))
super().__set__(instance, val)
class String(Type):
ty = str
class Integer(Type):
ty = int
class Positive(Descriptor):
def __set__(self, instance, val):
if val <= 0:
raise ValueError("Must be > 0")
super().__set__(instance, val)
class PositiveInteger(Integer, Positive):
pass
class Person(metaclass=StructMeta):
_fields = ['name', 'gender', 'age']
name = String('name')
gender = String('gender')
age = PositiveInteger('age')
So PositiveInteger is inherited from Integer and Positive, and both classes have __get__ method defined to do some validation. I wrote some test code to convince myself that both methods will run:
class A:
def test(self):
self.a = 'OK'
class B:
def test(self):
self.b = 'OK'
class C(A, B):
pass
c = C()
c.test()
print(self.a)
print(self.b)
Only to find that only the first print statement works. The second will raise an AttributeError, which indicates that when there's name conflict, the first base class wins.
So I wonder why both validations work? It's even more weird that when only the Integer check passes (e.g. person.age = -3), it's super().__set__(instance, val) has no effect, leaving person.age untouched.
The validation logic of both Positive and Integer runs because both Type and Positive have this line in __set__:
super().__set__(instance, val)
This doesn't skip to Descriptor.__set__. Instead, it calls the next method in method resolution order. Type.__set__ gets called, and its super().__set__(instance, val) calls Positive.__set__. Positive.__set__ runs its validation and calls Descriptor.__set__, which does the setting. This behavior is one of the reasons we have super.
If you wanted your test methods to behave like that, you would need to do two things. First, you would need to make A and B inherit from a common base class with a test method that doesn't do anything, so the super chains end at a place with a test method instead of going to object:
class Base:
def test():
pass
Then, you would need to add super().test() to both A.test and B.test:
class A(Base):
def test(self):
self.a = 'OK'
super().test()
class B(Base):
def test(self):
self.b = 'OK'
super().test()
For more reading, see Python's super() considered super.
Sorry, my bad.
The video gave perfect explanation just minute after where I paused and asked this question.
So when multiple inheritance happends, there's MRO thing (Method Resolution Order) defined in each class that determines the resolution order of methods in the super() chain.
The order is determined by depth-first search, e.g.
class A:
pass
class B(A):
pass
class C(B):
pass
class D(A):
pass
class E(C, D):
pass
E.__mro__ will be:
(<class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
One thing to notice is that A will appear in the inheritance tree multiple times, and in the MRO list it will only be in the last place where all A's appear.
Here's the trick: the call to super() won't necessarily go to its base. Instead, it'll find in the MRO list what comes next.
So to explain what happens in the code:
The super() call in Integer.__get__ (which is inherited from Type.__get__) won't go to Descriptor.__get__, because Descriptor appears last in the MRO list. It will fall into Positive.__set__, and then its super() will fall into Descriptor, which will eventually set the value of the attribute.

Copy a property-decorated member to a new class

I am trying to copy all the methods and attributes from a class to an instance of another class. Unfortunately I am having issues with properties. Here's an example:
class ToAdd(object):
#property
def foo(self):
return 'foo!'
class Base(object):
pass
b = Base()
for item, val in ToAdd.__dict__.iteritems():
if not item.startswith('__'):
setattr(b, item, val)
When calling b.foo I expect to get 'foo!', but instead it returns <property at 0x104a73d08>.
Note that this is akin to a mixin, but I want it to work on instances instead of classes.
There is probably a way to accomplish what you want with less "magic", but it is possible to change an instance's class...
class ToAdd(object):
#property
def foo(self):
return 'foo!'
class Base(object):
pass
b = Base()
NewBase = type('NewBase', (Base, ToAdd), {})
b.__class__ = NewBase
print(b.foo)
# foo!
Properties (and more generally, descriptors) only work on types, not on instances, so this won't work. You will not only get problems with the properties, but also with the methods, because your approach breaks the implict passing of the self parameter.

Categories

Resources