I have written this code in python 3.4 and used classes. I have implemented multiple inheritance in this code with super() function. And i want to call the init() function of library class. But i am unable, can anyone tell me the mistake?
code
class college:
def __init__(self, rollno):
print("Roll no:", rollno)
class library:
def __init__(self, libcardno):
print("Library card no:", libcardno)
class student(college, library):
def __init__(self, name):
print("Name:", name)
super().__init__(5560)
super().__init__(60)
output
>>> obj = student("John")
Name: John
Roll no: 5560
Roll no: 60
Just understand the question, it's not a duplicate of another one.
You can directly call __init__ method of respective parent class.
class student(college, library):
def __init__(self, name):
print("Name:", name)
college.__init__(self,5560)
library.__init__(self,60)
Short:
You can't and you don't need to use super() to call __init__ with different form. Of course there is a way to do, but I do not recommend that.
Long:
Python uses the list of classes to inherit from. You can see that list with
ClassName.__mro__. mro stands for Method Resolution Order
Think about you have three classes, ClassA, ClassB, ClassC and ClassC extends ClassA, and ClassB (If you are using python2, ClassA and ClassB musts extend from object)
class ClassC(ClassA, ClassB):
Then, ClassC.__mro__ will be like below:
(<class '__main__.ClassC'>, <class '__main__.ClassA'>, <class '__main__.ClassB'>, <class 'object'>)
So python inherits ClassC, ClassA, ClassB order. And it assumes that methods have same form in this list. This is why you can't use different forms of __init__ call using super().
If you need to use super() and there is no option, you can consider passing argument as **kwargs.
class ClassA():
def __init__(self, **kwargs):
super(ClassA, self).__init__(**kwargs)
print("Class A Initialized:", kwargs['a'])
class ClassB():
def __init__(self, **kwargs):
# super(ClassA, self).__init__(**kwargs)
# if you call above, you'll get type error, because above will call object.__init__ which takes only 1 argument
print("Class B Initialized:", kwargs['b'])
class ClassC(ClassA, ClassB):
def __init__(self, **kwargs):
super(ClassC, self).__init__(**kwargs)
print("Class C Initialized:", kwargs['c'])
ClassC(a="A", b="B", c="C")
And you can get below output :
Class B Initialized: B
Class A Initialized: A
Class C Initialized: C
But still, I recommend that do not use this form of inheritance, because it is very complicated
Related
I have the following code, in Django:
class Parent(models.Model):
def save(self):
# Do Stuff A
class Mixin(object):
def save(self):
# Do Stuff B
class A(Parent, Mixin):
def save(self):
super(A, self).save()
# Do stuff C
Now, I want to use the mixin without blatting the behaviour of the save in Parent. So I when I save, I want to do stuff C, B, and A. I've read Calling the setter of a super class in a mixin however I don't get it and having read the super docs it doesn't seem to answer my question.
THe question is, what do I put in the mixin to make sure it does stuff B and doesn't stop Stuff A from happening?
How about calling super in your mixin class?
class Parent(object):
def test(self):
print("parent")
class MyMixin(object):
def test(self):
super(MyMixin, self).test()
print("mixin")
class MyClass(MyMixin, Parent):
def test(self):
super(MyClass, self).test()
print("self")
if __name__ == "__main__":
my_obj = MyClass()
my_obj.test()
This will give you the output as:
$ python test.py
parent
mixin
self
The best practice for calling the implementation from the superclass is to use super():
class Mixin(object):
def save(self):
super(Mixin, self).save()
# Do Stuff B here or before super call, as you wish
What is important is that you call super() in each class (so that it propagates all the way) but not the topmost (base) class, because its superclass does not have save().
Note that when you call super(Mixin, self).save(), you don't really know what the super class would be once it is executed. That will be defined later.
Unlike some other languages, in python, the end class will always have a linear list of classes from which it inherits. That is called MRO (Method Resolution Order). From MRO Python decides what to do on super() call. You can see what the MRO is for your class this way:
>>> A.__mro__
(<class '__main__.A'>, <class '__main__.Parent'>, <class '__main__.Model'>, <class '__main__.Mixin'>, <type 'object'>)
So, A's super is Parent, Parent's super is Model, Model's super is Mixin and Mixin's super is object.
That is wrong, so you should change A's parents to:
class A(Mixin, Parent):
Then you'd have a better MRO:
>>> A.__mro__
(<class '__main__.A'>, <class '__main__.Mixin'>, <class '__main__.Parent'>, <class '__main__.Model'>, <type 'object'>)
#Click2Death answer is correct, however, when you call super().test() inside your mixin class most IDE will claim that test is unresolved, which is correct.
Here is how to make your IDE happy and your code better.
class Parent(object):
def test(self):
print("parent")
class MyMixin(object):
def test(self):
super_test = getattr(super(), 'test')
if super_test and callable(super_test):
super_test()
print("mixin")
class MyClass(MyMixin, Parent):
def test(self):
super().test()
print("self")
if __name__ == "__main__":
my_obj = MyClass()
my_obj.test()
This is Python 3 code, to make it working with Python 2 you need to pass two arguments to the super(MyClass, self) call
Django Example (Python 3+)
To expand on Vladimir Prudnikov's answer in a Django context, the template view mixin class could be structured as shown below.
from django.views.generic.base import View
class MyViewMixin:
def dispatch(self, request, *args, **kwargs):
super_dispatch = getattr(super(), 'dispatch')
if super_dispatch and callable(super_dispatch):
return super_dispatch(request, *args, **kwargs)
raise RuntimeError('MyViewMixin must be used as part of a '
'multiple inheritance chain that includes a Django template-view')
class MyCustomView(MyViewMixin, View):
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
I need to deliver something like this in my program
class the_class_name(Parent):
the_attribute = self.parent_class_method()
#the parent class method will return a value
#but I cannot use self here since there's no self
How can I carry this out? Is there any other alternative that can do the job for me?
I have tried using __init__ like this:
def __init__(self):
Parent.__init__(self)
self.attribute = self.the_method()
But then I have problem creating the object, it won't receive any parameters that the Parent class normally receives anymore
Sounds like you are looking for __init__:
class TheClassName(Parent):
def __init__(self):
# Set attribute to the result of the parent method
self.attribute = super(TheClassName, self).the_method()
EDIT
If your parent class has parameters in it's own __init__ function, include them in the child class:
class Parent(object):
def __init__(self, foo, bar):
...
#classmethod
def the_method(cls):
...
class TheClassName(Parent):
def __init__(self, foo, bar):
super(TheClassName, self).__init__(foo, bar)
self.attribute = super(TheClassName, self).the_method()
I don't quite understand why you don't just call the parent method on your child object when you need the value though.
There is no self at that point of the creation of the subclass, nor is there an instance of the Parent class. That means the only Parent class methods you could call would have to be either static or class methods.
To demonstrate:
class Parent(object):
#staticmethod
def static_method():
return 42
#classmethod
def class_method(cls):
return 43
class TheClassName(Parent):
the_attribute = Parent.static_method()
another_attribute = Parent.class_method()
print(TheClassName.the_attribute) # -> 42
print(TheClassName.another_attribute) # -> 43
You must use class methods, declared with the #classmethod decorator, or a #staticmethod. The #classmethod decorator is preferable so that inheritance is handled correctly, i.e. the method is invoked on the derived class (a bit of a technicality, if you are still learning this).
class Alpha(object):
#classmethod
def method1(cls):
return 'method1 has been called on {}'.format(cls)
class Beta(Alpha):
def __init__(self):
self.myattr = Beta.method1()
print(Beta().myattr)
method1 has been called on class <'__main__.Beta'>
Use
super(ClassName, self).methodname(arg)
inside a method
def child_method(self, arg):
super(ClassName, self).methodname(arg)
You cannot use self outside a method.
I'm having problem using super command
class s:
def __init__(self,a):
self.a=a
def show(self):
print self.a
class t:
def __init__(self,b):
self.b=b
def show2(self):
print self.b
class w(s):
def __init__(self,a,b,c):
super(w,self).__init__()
self.b=b
self.c=c
def show3(self):
super(w,self).show()
print self.b
print self.c
whenever i make an object it gives the following error
x=w(1,2,3)
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
x=w(1,2,3)
File "C:\Users\GURSAHEJ\Desktop\k.py", line 13, in __init__
super(w,self).__init__()
TypeError: must be type, not classobj
The super function will Return a proxy object that delegates method calls to a parent or sibling class of type so when you want to use it you need to pass the parent name to it,and since here your w class inherit from s you might want to pass s to super:
class w(s):
def __init__(self,a,b,c):
super(s,self).__init__()
self.b=b
self.c=c
Also don't forget to pass the object to your parent class to make it a new style class :
class s(object):
def __init__(self,a):
self.a=a
def show(self):
print self.a
Read about new style and classic classes it in python documentation https://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes
Because you are using super on an old-style class
In Python 2.x (>= 2.2), there are two type of classes. Old style classes and new-style classes. In python 3.x, old-style classes are removed and all classes are new-style class.
Python's build-in function super works properly on new-style classes.
Simply, new-style classes extends object while old style classes not.
Old Sytle Class
class s:
def __init__(self,a):
self.a=a
New Style Class
class s(object):
def __init__(self,a):
self.a=a
So, your classes which is not inherited from another class should be inherited from object to be a new style class.
You can either use new-style or use old-skool inheritance __init__
class w(s):
def __init__(self,a,b,c):
s.__init__(self, a)
This is an example of old-style solution, but I do not flag this question as a duplicate because new-style class usage is encouraged and you should avoid using old-style classes.
i had a class called CacheObject,and many class extend from it.
now i need to add something common on all classes from this class so i write this
class CacheObject(object):
def __init__(self):
self.updatedict = dict()
but the child class didn't obtain the updatedict attribute.i know calling super init function was optional in python,but is there an easy way to force all of them to add the init rather than walk all the classes and modify them one by one?
I was in a situation where I wanted classes to always call their base classes' constructor in order before they call their own. The following is Python3 code that should do what you want:
class meta(type):
def __init__(cls,name,bases,dct):
def auto__call__init__(self, *a, **kw):
for base in cls.__bases__:
base.__init__(self, *a, **kw)
cls.__init__child_(self, *a, **kw)
cls.__init__child_ = cls.__init__
cls.__init__ = auto__call__init__
class A(metaclass=meta):
def __init__(self):
print("Parent")
class B(A):
def __init__(self):
print("Child")
To illustrate, it will behave as follows:
>>> B()
Parent
Child
<__main__.B object at 0x000001F8EF251F28>
>>> A()
Parent
<__main__.A object at 0x000001F8EF2BB2B0>
I suggest a non-code fix:
Document that super().__init__() should be called by your subclasses before they use any other methods defined in it.
This is not an uncommon restriction. See, for instance, the documentation for threading.Thread in the standard library, which says:
If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.
There are probably many other examples, I just happened to have that doc page open.
You can override __new__. As long as your base classes doesn't override __new__ without calling super().__new__, then you'll be fine.
class CacheObject(object):
def __new__(cls, *args, **kwargs):
instance = super().__new__(cls, *args, **kwargs)
instance.updatedict = {}
return instance
class Foo(CacheObject):
def __init__(self):
pass
However, as some commenters said, the motivation for this seems a little shady. You should perhaps just add the super calls instead.
This isn't what you asked for, but how about making updatedict a property, so that it doesn't need to be set in __init__:
class CacheObject(object):
#property
def updatedict(self):
try:
return self._updatedict
except AttributeError:
self._updatedict = dict()
return self._updatedict
Hopefully this achieves the real goal, that you don't want to have to touch every subclass (other than to make sure none uses an attribute called updatedict for something else, of course).
There are some odd gotchas, though, because it is different from setting updatedict in __init__ as in your question. For example, the content of CacheObject().__dict__ is different. It has no key updatedict because I've put that key in the class, not in each instance.
Regardless of motivation, another option is to use __init_subclass__() (Python 3.6+) to get this kind of behavior. (For example, I'm using it because I want users not familiar with the intricacies of Python to be able to inherit from a class to create specific engineering models, and I'm trying to keep the structure of the class they have to define very basic.)
In the case of your example,
class CacheObject:
def __init__(self) -> None:
self.updatedict = dict()
def __init_subclass__(cls) -> None:
orig_init = cls.__init__
#wraps(orig_init)
def __init__(self, *args, **kwargs):
orig_init(self, *args, **kwargs)
super(self.__class__, self).__init__()
cls.__init__ = __init__
What this does is any class that subclasses CacheObject will now, when created, have its __init__ function wrapped by the parent class—we're replacing it with a new function that calls the original, and then calls super() (the parent's) __init__ function. So now, even if the child class overrides the parent __init__, at the instance's creation time, its __init__ is then wrapped by a function that calls it and then calls its parent.
You can add a decorator to your classes :
def my_decorator(cls):
old_init = cls.__init__
def new_init(self):
self.updatedict = dict()
old_init(self)
cls.__init__ = new_init
return cls
#my_decorator
class SubClass(CacheObject):
pass
if you want to add the decorators to all the subclasses automatically, use a metaclass:
class myMeta(type):
def __new__(cls, name, parents, dct):
return my_decorator(super().__new__(cls, name, parents, dct))
class CacheObject(object, metaclass=myMeta):
pass
I'd like to automatically run some code upon class creation that can call other class methods. I have not found a way of doing so from within the class declaration itself and end up creating a #classmethod called __clsinit__ and call it from the defining scope immediately after the class declaration. Is there a method I can define such that it will get automatically called after the class object is created?
You can do this with a metaclass or a class decorator.
A class decorator (since 2.6) is probably easier to understand:
def call_clsinit(cls):
cls._clsinit()
return cls
#call_clsinit
class MyClass:
#classmethod
def _clsinit(cls):
print "MyClass._clsinit()"
Metaclasses are more powerful; they can call code and modify the ingredients of the class before it is created as well as afterwards (also, they can be inherited):
def call_clsinit(*args, **kwargs):
cls = type(*args, **kwargs)
cls._clsinit()
return cls;
class MyClass(object):
__metaclass__ = call_clsinit
#classmethod
def _clsinit(cls):
print "MyClass._clsinit()"