Class Inheritance in Python - python

I'm new to python and trying to get a list of the classes an object's class inherits from. I'm trying to do this using the bases attribute but I'm not having any success. Can someone please help me out?
def foo(C):
print(list(C.__bases__))
class Thing(object):
def f(self):
print("Yo")
class Shape(Thing):
def l(self):
print("ain't no thang")
class Circle(Shape):
def n(self):
print("ain't no shape")
test = Circle()
foo(test)

Only classes have __bases__; class instances do not. You can get the class object through an instance's __class__: use foo(test.__class__) or foo(Circle).

Use inspect, from documentation
Return a tuple of class cls’s base classes, including cls, in method
resolution order. No class appears more than once in this tuple. Note
that the method resolution order depends on cls’s type. Unless a very
peculiar user-defined metatype is in use, cls will be the first
element of the tuple.
>>> import inspect
>>> inspect.getmro(test.__class__)
(<class '__main__.Circle'>, <class '__main__.Shape'>, <class '__main__.Thing'>, <type 'object'>)
>>>
This traverses up the inheritance hierarchy & prints all classes, including object. Pretty Cool eh ?

print '\n'.join(base.__name__ for base in test.__class__.__bases__)
Or, using the inspect module:
from inspect import getmro
print '\n'.join(base.__name__ for base in getmro(test))

Your implementation of foo works. But you need to pass a class to foo, not an instance.
In [1]: def foo(C):
...: print(list(C.__bases__))
...:
In [2]: class Thing(object):
...: def f(self):
...: print("Yo")
...:
In [3]: class Shape(Thing):
...: def l(self):
...: print("ain't no thang")
...:
In [4]: class Circle(Shape):
...: def n(self):
...: print("ain't no shape")
...:
In [5]: test = Circle()
In [6]: foo(test)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-6-7b85deb1beaa> in <module>()
----> 1 foo(test)
<ipython-input-1-acd1789d43a9> in foo(C)
1 def foo(C):
----> 2 print(list(C.__bases__))
3
AttributeError: 'Circle' object has no attribute '__bases__'
In [7]: foo(Thing)
[<type 'object'>]
In [8]: foo(Circle)
[<class '__main__.Shape'>]
In [9]: foo(Shape)
[<class '__main__.Thing'>]

Related

How does Python access an objects attribute when __dict__ is overridden?

The Python docs, specify that attribute access is done via the objects __dict__ attribute.
The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance, a.x has a lookup chain starting with a.__dict__['x'], then type(a).__dict__['x'], and continuing through the base classes of type(a) excluding metaclasses. If the looked-up value is an object defining one of the descriptor methods, then Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods were defined.
In this example, I override the object's __dict__, but python can still manage to get its attribute, how does that work?:
In [1]: class Foo:
...: def __init__(self):
...: self.a = 5
...: self.b = 3
...: def __dict__(self):
...: return 'asdasd'
...:
In [2]: obj_foo = Foo()
In [3]: obj_foo.__dict__
Out[3]: <bound method Foo.__dict__ of <__main__.Foo object at 0x111056850>>
In [4]: obj_foo.__dict__()
Out[4]: 'asdasd'
In [5]: obj_foo.b
Out[5]: 3
You are implementing the __dict__ method.
If you override the __dict__ attribute you will succeed in breaking Python:
class Foo:
def __init__(self):
self.a = 1
self.__dict__ = {}
Foo().a
AttributeError: 'Foo' object has no attribute 'a'
Interestingly enough, if both are overridden everything is back to normal:
class Foo:
def __init__(self):
self.a = 1
self.__dict__ = {}
def __dict__(self):
pass
print(Foo().a)
Outputs
1
Making __dict__ a property also does not seem to break anything:
class Foo:
def __init__(self):
self.a = 1
#property
def __dict__(self):
return {}
print(Foo().a)
Also outputs 1.
I suspect the answer to the question *why* lies (probably) deep in the CPython implementation of `object`, more digging needs to be done.

Expose object properties dynamically

In [1]: class Foo():
...: pass
...:
In [2]: class Qux():
...: def __init__(self):
...: item = Foo()
...:
In [3]: a = Foo()
In [4]: setattr(a, 'superpower', 'strength')
In [5]: a.superpower
Out[5]: 'strength'
In [6]: b = Qux()
In [7]: b.item = a
In [8]: b.superpower
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-8-cf0e287006f1> in <module>()
----> 1 b.superpower
AttributeError: Qux instance has no attribute 'superpower'
What I would like is to define some way of calling any attribute on Qux and have it return getattr(Qux.item, <attributename>). In other words, to have b.superpower work without explicitly defining:
#property
def superpower(self):
return getattr(self.item, 'superpower')
I don't want to lose access to any properties defined on Qux itself as well, but rather to expose properties defined on Foo if they are not also on Qux.
Define a __getattr__:
class Qux(Foo):
def __init__(self):
self.item = Foo()
def __getattr__(self, attr):
return getattr(self.item, attr)
__getattr__ gets called whenever someone tries to look up an attribute of the object, but fails through normal means.
It has an evil twin called __getattribute__, which always gets called and must be used with extreme caution.
You do that by defining __getattr__, not with a property. For any attribute that cannot be found with the standard protocol, Python will call the __getattr__ method of a class.
Moreover, to store the item, you have to assign it to self.item, otherwise it is thrown at the end of Qux.__init__.
Finally, inheriting from Foo seems unecessary in that case.
class Foo:
def __init__(self, superpower):
self.superpower = superpower
class Qux:
def __init__(self, foo_item):
self.item = foo_item
def __getattr__(self, name):
return getattr(self.item, name)
Example
f = Foo('strenght')
q = Qux(f)
print(q.superpower) # 'strenght'
Inheritance
Although, it seems you half-tried to implement this with inheritance. If your intent was to extend Qux behaviour with Foo, then inheritance would be the way to go.
class Foo:
def __init__(self, superpower):
self.superpower = superpower
class Qux(Foo):
def __getattr__(self, name):
return getattr(self.item, name)
Example
q = Qux('strenght')
print(q.superpower) # 'strenght'

Second parameter of super()?

A colleague of mine wrote code analogous to the following today, asked me to have a look, and it took me a while to spot the mistake:
class A():
def __init__(self):
print('A')
class B(A):
def __init__(self):
super(B).__init__()
b = B()
The problem here is that there's no self parameter to super() in B's constructor. What surprised me is that absolutely nothing happens in this case, i.e. no error, nothing. What does the super object created by super(B) contain? As an object, it clearly has a constructor, so that's what gets called, but how is that object related to B? In particular, why is this valid code and doesn't throw an exception somewhere? Is super(B) an object with some actual use and what would that be?
The only thing that causes all these ambiguities is that "why obj = super(B).__init__() works?". That's because super(B).__self_class__ returns None and in that case you're calling the None objects' __init__ like following which returns None:
In [40]: None.__init__()
Regarding the rest of the cases, you can simply check the difference by calling the super's essential attributes in both cases:
In [36]: class B(A):
def __init__(self):
obj = super(B, self)
print(obj.__class__)
print(obj.__thisclass__)
print(obj.__self_class__)
print(obj.__self__)
....:
In [37]: b = B()
<class 'super'>
<class '__main__.B'>
<class '__main__.B'>
<__main__.B object at 0x7f15a813f940>
In [38]:
In [38]: class B(A):
def __init__(self):
obj = super(B)
print(obj.__class__)
print(obj.__thisclass__)
print(obj.__self_class__)
print(obj.__self__)
....:
In [39]: b = B()
<class 'super'>
<class '__main__.B'>
None
None
For the rest of the things I recommend you to read the documentation thoroughly. https://docs.python.org/3/library/functions.html#super and this article by Raymond Hettinger https://rhettinger.wordpress.com/2011/05/26/super-considered-super/.
Moreover, If you want to know why super(B) doesn't work outside of the class and generally why calling the super() without any argument works inside a class you can read This comprehensive answer by Martijn https://stackoverflow.com/a/19609168/2867928.
A short description of the solution:
As mentioned in the comments by #Nathan Vērzemnieks you need to call the initializer once to get the super() object work. The reason is laid behind the magic of new super object that is explained in aforementioned links.
In [1]: class A:
...: def __init__(self):
...: print("finally!")
...:
In [2]: class B(A):
...: def __init__(self):
...: sup = super(B)
...: print("Before: {}".format(sup))
...: sup.__init__()
...: print("After: {}".format(sup))
...: sup.__init__()
...:
In [3]: B()
Before: <super: <class 'B'>, NULL>
After: <super: <class 'B'>, <B object>>
finally!
The confusion here comes from the fact that (in a class definition context) super() gives a bound super object which then delegates __init__ to its __self_class__, while super(B) creates an unbound super object which, because its __self_class__ is None, does not delegate.
In [41]: class Test(int):
...: def __init__(self):
...: print(super().__self_class__)
...: print(super().__init__)
...: print(super(Test).__self_class__)
...: print(super(Test).__init__)
...:
In [42]: Test()
<class '__main__.Test'>
<method-wrapper '__init__' of Test object at 0x10835c9c8>
None
<method-wrapper '__init__' of super object at 0x10835c3c8>
So when you call super(B).__init__(), it creates an unbound super but then immediately calls __init__ on it; that, because of the magic described in the various links in this other answer, binds that unbound super. There are no references to it, so it disappears, but that's what's happening under the hood.

Assign external function to class variable in Python

I am trying to assign a function defined elsewhere to a class variable so I can later call it in one of the methods of the instance, like this:
from module import my_func
class Bar(object):
func = my_func
def run(self):
self.func() # Runs my function
The problem is that this fails because when doing self.func(), then the instance is passed as the first parameter.
I've come up with a hack but seems ugly to me, anybody has an alternative?
In [1]: class Foo(object):
...: func = lambda *args: args
...: def __init__(self):
...: print(self.func())
...:
In [2]: class Foo2(object):
...: funcs = [lambda *args: args]
...: def __init__(self):
...: print(self.funcs[0]())
...:
In [3]: f = Foo()
(<__main__.Foo object at 0x00000000044BFB70>,)
In [4]: f2 = Foo2()
()
Edit: The behavior is different with builtin functions!
In [13]: from math import pow
In [14]: def pow_(a, b):
....: return pow(a, b)
....:
In [15]: class Foo3(object):
....: func = pow_
....: def __init__(self):
....: print(self.func(2, 3))
....:
In [16]: f3 = Foo3()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-16-c27c8778655e> in <module>()
----> 1 f3 = Foo3()
<ipython-input-15-efeb6adb211c> in __init__(self)
2 func = pow_
3 def __init__(self):
----> 4 print(self.func(2, 3))
5
TypeError: pow_() takes exactly 2 arguments (3 given)
In [17]: class Foo4(object):
....: func = pow
....: def __init__(self):
....: print(self.func(2, 3))
....:
In [18]: f4 = Foo4()
8.0
Python functions are descriptor objects, and when attributes on a class accessing them an instance causes them to be bound as methods.
If you want to prevent this, use the staticmethod function to wrap the function in a different descriptor that doesn't bind to the instance:
class Bar(object):
func = staticmethod(my_func)
def run(self):
self.func()
Alternatively, access the unbound function via the __func__ attribute on the method:
def run(self):
self.func.__func__()
or go directly to the class __dict__ attribute to bypass the descriptor protocol altogether:
def run(self):
Bar.__dict__['func']()
As for math.pow, that's not a Python function, in that it is written in C code. Most built-in functions are written in C, and most are not descriptors.

What is difference between A.fun and A().fun?

class A(object):
def fun(self):
pass
ins_a = A.fun
ins_b = A().fun
I came across this piece of code and I am unable to understand the difference between the 2 objects.
Just try the above code in the interactive interpreter:
>>> class A(object):
... def fun(self):
... pass
...
>>> ins_a = A.fun
>>> ins_b = A().fun
>>> ins_a
<unbound method A.fun>
>>> ins_b
<bound method A.fun of <__main__.A object at 0x7f694866a6d0>>
As you can see, it is a matter of bound/unbound methods. A bound method is a method "tied" to an object. You can have a more thorough explanation in this SO answer.
The biggest difference is if you try to call the methods:
If we add a print "hello world", it will make it more obvious.
class A(object):
def fun(self):
print ("hello world")
ins_a = A.fun
ins_b = A().fun
Now try calling both:
In [10]: ins_a()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-52906495cc43> in <module>()
----> 1 ins_a()
TypeError: unbound method fun() must be called with A instance as first argument (got nothing instead)
In [11]: ins_b()
hello world
In python 3 they are different types as the unbound method type is gone:
In [2]: type(ins_a)
Out[2]: builtins.function
In [3]: type(ins_b)
Out[3]: builtins.method

Categories

Resources