Is it possible to skip classes in the method resolution order when calling for methods?
For example,
super().super()
I read the docs here: https://docs.python.org/3/library/functions.html#super
that lead me to this code
class A:
def show(self):
print("A")
class B(A):
def __init__(self):
print("B")
def s(self):
return super()
class C(B):
def __init__(self):
super().s().show()
c = C()
c
See that super returns a proxy object that seems not to have the super method (because i tried and the interpreter told me it doesn't). But you do have the others methods from the class, so this way I could get a proxy from its grandparent to use its methods
super() in the class definition for FooClass is shorthand for super(FooClass, self). Using this, we can do this:
class Grandparent:
def test(self):
print('grandparent gets called')
class Parent(Grandparent):
def test(self):
super().test()
print('parent gets skipped')
class Child(Parent):
def test(self):
super(Parent, self).test()
print('child gets called')
This "cheats" the MRO by checking the parent's superclass instead of the child's superclass.
Related
Usually super works like the following in Python:
class SubClass(MyParentClass):
def __init__(self):
super(**SubClass**, self).__init__()
But recently I found something like the following also works? No crash, behaviors as expected:
class SubClass(MyParentClass):
def __init__(self):
super(**MyParentClass**, self).__init__()
How come? What does the second case mean?
super(MyParentClass, self).__init__() Will call grandparent class (If it has one)
class BaseClass:
def __init__(self):
print("BaseClass")
class MyParentClass(BaseClass):
def __init__(self):
print("MyParentClass")
class SubClass(MyParentClass):
def __init__(self):
super(SubClass, self).__init__()
class SubClassTwo(MyParentClass):
def __init__(self):
super(MyParentClass, self).__init__()
SubClass() # output: MyParentClass
SubClassTwo() # output: BaseClass
Actually, the behaviour it's not the same.
From the documentation of super() (docs here):
Return a proxy object that delegates method calls to a parent or
sibling class of type.
So if you have:
class MyParentClass:
def __init__(self):
print('MyParentClass.__init__ called!')
class SubClass(MyParentClass):
def __init__(self):
super(MyParentClass, self).__init__()
The call:
super(MyParentClass, self).__init__()
has no effect, because MyParentClass has no parents but object.
If you call:
super(SubClass, self).__init__()
It will print:
MyParentClass.__init__ called!
Because SubClass has one parent, MyParentClass.
The documentation for super says (in part):
super([type[, object-or-type]])
Return a proxy object that delegates method calls to a parent or
sibling class of type. This is useful for accessing inherited methods
that have been overridden in a class. The search order is same as that
used by getattr() except that the type itself is skipped.
So super(MyParentClass, self) resolves to a proxy object that will pass method calls through to the parents and siblings of MyParentClass. It shouldn't be surprising that this works. If your parent class is
class MyParentClass:
def __init__(self, **kwargs):
...
super(MyParentClass, self).__init__(kwargs)
Then when you make a SubClass object, the self in the MyParentClass super call is a SubClass instance.
I would like for child process to have certain properties, but since you can't force child methods to inherit the property decorator, I want to at least assert that these attributes of the child are properties of the class.
Something like this:
class Parent:
def __init__(self):
assert isinstance(self.foo, property)
def foo(self):
raise NotImplementedError
class Child(Parent):
def __init__(self):
super().__init__()
#property
def foo(self):
return 'bar'
But of course by the time Parent.__init__() is run, self.foo has become 'bar' and there is an AssertionError. Is there a way to accomplish what I'm going for using meta classes? If so, can it be that the Parent class is the one that inherits the metaclass, not the Child?
I found a solution. Instead of testing whether self.foo is a property, I tested whether it was not a bound method:
from inspect import ismethod
class Parent:
def __init__(self):
assert not ismethod(self.foo, property)
def foo(self):
raise NotImplementedError
This will work for most cases, but will fail if the property being returned by Child.foo is itself a bound method. Still open to more complete answers.
If I have this situation:
class Foo(object):
def __init__(self):
self.bar = Bar()
def do_something(self):
print 'doing something'
class Bar(object):
def __init(self):
self.a = 'a'
def some_function(self):
I want to call do_something function inside some_function function but this function doesn't belong to the class, what can I do to call this function?
I don't want to use it with Foo().do_something, there are another option?
I don't want to create new instance
another example:
class A(object):
def __init__(self):
self.content = 'abcdabcabcabc'
self.b = self.B()
self.c = self.C()
def some_function(self):
print self.content
class B(object):
def foo(self):
A.some_function()
class C(object):
def foo(self):
A.some_function()
There is no practical use case for nested classes in Python, but for scoping some class attributes with namespaces. And in that case, you should not create instances of them at all.
All you get if you have instances of nested classes is a headache - there is no benneffit. The "Outter" class won't see them as anything special - that is unlike in C++, from where it looks like this pattern originated, that the nested class is, in its whole, private to the container class.
The concept of being private in Python is done purely by convention, and if no other code than Foo should use instances of Bar, indicate that by calling it _Bar and in the documentation.
Other than that being nested won't help Bar to get a reference to Foo by any other means than through its name (ok, there are ways using the descriptor protocol, but it is not meant for this) - and them, if you want to run Foo.do_something without having a Foo instance, do_something should be a classmethod anyway.
Now, if you want to have aggregated objects, that is another thing. You have to do is:
class Bar(object):
def __init(self, parent):
self.parent = parent
self.a = 'a'
def some_function(self):
self.parent.do_something(...)
class Foo(object):
def __init__(self):
self.bar = Bar(self)
def do_something(self):
print 'doing something'
I know this question might be pointless but there is a reason why I am looking to do it this way. I want to call something exactly opposite to super()
class A(object):
def use_attack(self, damage, passive, spells):
#do stuff with passed parameters
#return something
def use_spell(self, name , enemy_hp):
#other code
if name == 'Enrage':
#call child method use_attack right here
class B(A):
def use_attack(self):
#bunch of code here
return super(B, self).use_attack(damage, passive, spells)
def use_spell(self, name , enemy_hp):
return super(B , self).use_attack(name ,enemy_hp)
b = B()
b.use_spell('Enrage', 100)
I have a bunch of code in class B's use_attack() method that I would not like to replicate in the parent method of use_spell() .
I would like to call the child method use_attack() in the line indicated.
I have a bunch of code in class B's use_attack() method that I would not like to replicate in the parent method of use_spell() .
Then factor that code out into a method on the parent class. This is exactly what inheritance is for. Children inherit code from parents, not the other way around.
From the python docs: "The mro attribute of the type lists the method resolution search order used by both getattr() and super()"
https://docs.python.org/3/library/functions.html#super
This should help shed some light on Inheritance and Method Resolution Order (mro).
class Foo(object):
def __init__(self):
print('Foo init called')
def call_child_method(self):
self.child_method()
class Bar(Foo):
def __init__(self):
print('Bar init called')
super().__init__()
def child_method(self):
print('Child method called')
bar = Bar()
bar.call_child_method()
If I am inheriting from a class and not changing anything in a method, is it required to use super to initialize the method from the parent class?
class A:
def __init__(self):
self.html = requests.get("example.com").text
class B(A):
def __init__(self):
# is this needed?
super(B, self).__init__()
def new_method(self):
print self.html
Because you created a __init__ method in your class B, it overrides the method in class A. If you want it executed, you'll have to use super(), yes.
However, if you are not doing anything else in B.__init__, you may as well just omit it:
class A:
def __init__(self):
self.html = requests.get("example.com").text
class B(A):
def new_method(self):
print self.html
If you want to do anything in addition to what A.__init__() does, then it makes sense to create a B.__init__() method, and from that method, invoke the parent __init__.
It's not needed to define the overriding method at all. Python's default behavior is to call the method on the parent class (the next class in the method resolution order) if the current class doesn't override it.
>>> class Foo(object):
... def __init__(self):
... print("Foo")
...
>>> class Bar(Foo): pass
...
>>> Bar()
Foo
<__main__.Bar object at 0x7f5ac7d1b990>
Notice "Foo" got printed when I initialized a Bar instance.
If you do define the method, you need to call the super class's method (either explicitly or via super) if you want to make sure that it gets called.