Subclass of Django Model Not Accessible from Superclass - python

I'm trying to create an inherited model in Django like that below. I should be able to call, for an instance superclass = Superclass(), I should be able to call superclass.subclass, and access the requisite fields. When I do that, I'm told that '1 argument was expected, and 8 were given': any idea where I'm going wrong?
class Superclass(models.Model):
pass
class Subclass(Superclass):
def __init__(self):
super(Subclass, self).__init__()

The problem here is that you need *args and **kwargs in the subclass constructor and superclass constructor. These two fields will take in the arguments and objects: these include the field information for the superclass, as well as the object manager, among other things. This should do the trick:
class Subclass(Superclass):
def __init__(self, *args, **kwargs):
super(Subclass, self).__init__(*args, **kwargs)

Related

How can I add an additional class inheritance to an existing one, but with different number of arguments to existing inheritance?

I have an existing class TSEparser that inherits from a parent class Subparser, but now I want to add another parent class (SubparserMixin) to class TSEparser. However, the problem is that the arguments passed by the initial inheritance gets in the way of this new inheritance- how can I fix this?
i.e:
class Subparser:
def __init__(self, filename, data_group, **kwargs):
self.data_group = data_group
self.filename = filename
self.__dict__.update(kwargs)
class TSEparser(Subparser):
def __init__(self, filename, data_group, **kwargs):
super().__init__(filename, data_group, **kwargs)
Now I want to add another parent class SubparserMixin so we have class TSEparser(Subparser, SubparserMixin), however Subparsermixin looks like this:
class SubparserMixin:
def __init__(self):
self.subparsers = {}
self.context = PacketContext
Is there some way I can inherit separately from both Parent Classes? Something like this:
class TSEparser(Subparser):
def __init__(self, filename, data_group, **kwargs):
super(Subparser).__init__(filename, data_group, **kwargs)
super(SubparserMixin).__init__()
I know the syntax is not correct but I hope it is clear what I am trying to do!
You can specify which class' constructor gets called by simply using its name. So in your example you can just do
class TSEparser(Subparser, SubparserMixin):
def __init__(self, filename, data_group, **kwargs):
Subparser.__init__(self, filename, data_group, **kwargs)
SubparserMixin.__init__(self)
There is no good and easy way to make this work using super. You can check out this question for more detail. super normally takes care of calling the proper classes for you. If you want to call the __init__ of a specific class manually (e.g. because the required arguments are different), you need to call it directly using its name as shown above.
Edit: My code example mistakenly didn't pass self when calling the base __init__ methods. Note that this is a difference between calling by super and directly by base class. super doesn't require self, while direct calling does.
# without self
super().__init__()
# with self
Base.__init__(self)

What is the proper way to deal with Python overriding of class methods with a mixin in multiple inheritance without redundant code?

I'm having a minor, I hope, issue with theory and the proper way to deal with a problem. It's easier for me to show an example then to explain as I seem to fail with my vocabulary.
class Original_1:
def __init__(self):
pass
def meth1(self):
pass
def meth2(self):
pass
class Original_2(Original_1):
def __init__(self):
Original_1.__init__(self)
def meth3(self):
pass
class Mixin:
def __init__(self):
pass
def meth4(self):
...
meth1(self)
meth2(self)
class NewClass_1(Original_1, Mixin):
def __init__(self):
Original_1.__init__(self)
Mixin.__init__(self)
class NewClass_2(Original_2, Mixin):
def __init__(self):
Original_2.__init__(self)
Mixin.__init__(self)
Now the goal is to extend Original_1 or Original_2 with new methods in the Mixin, but I run into some questions if I use meth1(), meth2(), or meth3() in the mixin. 1. I'm not referencing Original_1 or Origninal_2 in the mixin. (At this point it runs but I don't like it.) 2. If I make Mixin a child of Original_1, it breaks. I could make two separate NewClass_X but then I'm duplicating all of that code.
Mixins are used to add functionality (usually methods) to classes by using multiple inheritance.
For example, let's say you want to make a class's __str__ method return everything in uppercase. There are two ways you can do this:
Manually change every single class's __str__ method:
class SomeClass(SomeBase):
def __str__(self):
return super(SomeClass, self).__str__().upper()
Create a mixin class that does only this and inherit from it:
class UpperStrMixin(object):
def __str__(self):
return super(UpperStrMixin, self).__str__().upper()
class SomeClass(SomeBase, UpperStrMixin):
...
In the second example, notice how UpperStrMixin is completely useless as a standalone class. Its only purpose is to be used with multiple inheritance as a base class and to override your class's __str__ method.
In your particular case, the following will work:
class Mixin:
def __init__(self, option):
...
def meth4(self):
...
self.meth1()
self.meth2()
class NewClass_1(Original_1, Mixin):
def __init__(self, option):
Original_1.__init__(self)
Mixin.__init__(self, option)
...
class NewClass_2(Original_2, Mixin):
def __init__(self, option):
Original_2.__init__(self)
Mixin.__init__(self, option)
...
Even though Mixin.meth1 and Mixin.meth2 aren't defined, this isn't an issue because an instance of Mixin is never created directly and it's only used indirectly through multiple inheritance.
Since Mixin is not a standalone class, you can just write it to assume that the necessary methods exist, and it will find them on self assuming the self in question provides, or derives from another class which provides, meth1 and meth2.
If you want to ensure the methods exist, you can either document it in the Mixin docstring, or for programmatic enforcement, use the abc module to make Mixin an ABC and specify what methods must be defined; if a given class doesn't provide them (directly or via inheritance) then you'll get an error if you attempt to instantiate it (because the class is still abstract until those methods are defined):
from abc import ABCMeta, abstractmethod
class Mixin(metaclass=ABCMeta):
def __init__(self):
pass
#abstractmethod
def meth1(self): pass
#abstractmethod
def meth2(self): pass
def meth4(self):
...
self.meth1() # Method call on self will dispatch to other class's meth1 dynamically
self.meth2() # Method call on self will dispatch to other class's meth2 dynamically
Beyond that, you can simplify your code significantly by using super appropriately, which would remove the need to explicitly call the __init__s for each parent class; they'd be called automatically so long as all classes use super appropriately (note: for safety, in cooperative inheritance like this, you usually accept the current class's recognized arguments plus varargs, passing the varargs you don't recognize up the call chain blindly):
class Original_1:
def __init__(self, orig1arg, *args, **kwargs):
self.orig1val = orig1arg # Use what you know
super().__init__(*args, **kwargs) # Pass what you don't
def meth1(self):
pass
def meth2(self):
pass
class Original_2(Original_1):
def __init__(self, orig2arg, *args, **kwargs):
self.orig2val = orig2arg # Use what you know
super().__init__(self, *args, **kwargs) # Pass what you don't
def meth3(self):
pass
class Mixin(metaclass=ABCMeta):
# If Mixin, or any class in your hierarchy, doesn't need to do anything to
# be initialized, just omit __init__ entirely, and the super from other
# classes will skip over it entirely
def __init__(self, mixinarg, *args, **kwargs):
self.mixinval = mixinarg # Use what you know
super().__init__(self, *args, **kwargs) # Pass what you don't
#abstractmethod
def meth1(self): pass
#abstractmethod
def meth2(self): pass
def meth4(self):
...
self.meth1() # Method call on self will dispatch to other class's meth1
self.meth2() # Method call on self will dispatch to other class's meth1
class NewClass_1(Original_1, Mixin):
def __init__(self, newarg1, *args, **kwargs):
self.newval1 = newarg1 # Use what you know
super().__init__(self, *args, **kwargs) # Pass what you don't
class NewClass_2(Original_2, Mixin):
def __init__(self, newarg2, *args, **kwargs):
self.newval2 = newarg2 # Use what you know
super().__init__(self, *args, **kwargs) # Pass what you don't
Note that using super everywhere means you don't need to explicitly call each __init__ for your parents; it automatically linearizes the calls, so for example, in NewClass_2, that single super().__init__ will delegate to the first parent (Original_2), which then delegates to Original_1, which then delegates to Mixin (even though Original_1 knows nothing about Mixin).
In more complicated multiple inheritance (say, you inherit from Mixin through two different parent classes that both inherit from it), using super is the only way to handle it reasonably; super naturally linearizes and deduplicates the parent class tree, so even though two parents derive from it, Mixin.__init__ would still only be called once, preventing subtle errors from initializing Mixin more than once.
Note: You didn't specify which version of Python you're using. Metaclasses and super are both better and simpler in Python 3, so I've used Python 3 syntax. For Python 2, you'd need to set the metaclass a different way, and call super providing the current class object and self explicitly, which makes it less nice, but then, Python 2 is generally less nice at this point, so consider writing new code for Python 3?

Inheritance in Python

I'm having a small amount of difficulty understanding inheritance in Python. I was under the impression that when Class B inherits from Class A it inherits all of the values that were initialized in A. I've made up an example to demonstrate what I mean:
Class A():
def __init__(self,parameter):
self.initialize_parameter=4*parameter
Class B(A):
def __init__(self):
pass
def function(self,another_parameter):
return self.initialize_parameter*another_parameter
But in this case, calling:
B_instance=B()
print B_instance.function(10)
Returns an AttributeError saying that class B doesn't not have self.initialized_parameter
So my question is, do I have to copy and paste all the initializations from A to B manually or is there a way that I can use them from within B without calling the A class itself? (I hope this is clear).
If you want to use the behaviour in the superclass' constructor you should either not override it:
Class B(A):
def function(self,another_parameter):
return self.initialize_parameter*another_parameter
Or if you want to extend the initialization behaviour you can use super()
Class B(A):
def __init__(self, parameter)
super(B, self).__init__(2*parameter)
def function(self,another_parameter):
return self.initialize_parameter*another_parameter
In Python 3 super() doesn't need explicit arguments (super().__init__()).
This general override behaviour and super() applies to all methods, not just constructors.
You have to use the super builtin in order to do the required initialisation for the parent class, like so:
class B(A):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
If you're not using Python 3, you might have to do it like this:
class B(A):
def __init__(self, *args, **kwargs):
super(A, self).__init__(*args, **kwargs)
Basically this calls A's __init__ function which is required if you want to reference A's methods and attributes.
The only way to initialize the base class is to use super().__init__() in B __init__() method. See: Understanding Python super() with __init__() methods
You are overriding the constructor from the super class here:
def __init__(self):
pass
So, self.initialize_parameter is never being initialized.
Delete that method, and it should work.
The __init__ of the superclass is only called automatically when you do not specify an __init__ in the subclass. So you should not define __init__ in class B unless you need to.
If you specify __init__ in class B you have to call __init__ in the superclass by hand. I prefer calling it this way: A.__init__(self,'provide_initialize_parameter_here'). Other people prefer using super.

why do we need to call current class in override method in django

I am new to Django. I just move from c++. I have a question when I want to override a class method. Why do we need to call the current class name? for example
class MyStuff( models.Model ):
def __init__(self, *args, **kwargs):
super(MyStuff, self).__init__(*args, **kwargs) #calling super "MyStuff" instead of "Model"
I am not sure how does Django work deep inside. Why don't we call super(Model, self)? How can I call Grandparent method?
See this answer
when you do super(MyStuff, self).__init__(*args, **kwargs) you are calling a instance method of the 'parent'
In python, you have multiple inherance, so when you call super(), the Method Resolution Order is not to just one parent, because you have multiples parents.
See here
hope helps

Python class inheritance: AttributeError: '[SubClass]' object has no attribute 'xxx'

I have the following base class and subclass:
class Event:
def __init__(self, sr1=None, foobar=None):
self.sr1 = sr1
self.foobar = foobar
self.state = STATE_NON_EVENT
# Event class wrappers to provide syntatic sugar
class TypeTwoEvent(Event):
def __init__(self, level=None):
self.sr1 = level
self.state = STATE_EVENT_TWO
Further on in my code, I am inspecting an instance of a TypeTwoEvent class, checking for a field I know exists in the base class - I expected it to be defaulted to value None. However, my code raises the following exception:
AttributeError: 'TypeTwoEvent' object has no attribute 'foobar'
I was under the impression that the base class fields would be inherited by the subclass and that creating an instance of a subclass will instantiate the base class (and thus invoke its constructor) ...
What am I missing here? Why does TypeTwoEvent not have a foobar attribute - when the base class from which it is derived has a foobar attribute?
Your subclass should be:
class TypeTwoEvent(Event):
def __init__(self, level=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sr1 = level
self.state = STATE_EVENT_TWO
Because you override the __init__ method, so you need to call the parent method if you want the parent behavior to happen.
Remember, __init__ is not a special method dispite its strange name. It's just the method automatically called after the object is created. Otherwise it's an ordinary method, and ordinary inheritance rules apply.
super().__init__(arguments, that, goes, to, parents)
is the syntax to call the parent version of the method.
For *args and **kwargs, it just ensures we catch all additional arguments passed to __init__ and pass it to the parent method, as you child method signature didn't do it and the parent need these arguments to work.
You're overriding the constructor (__init__) of the parent class. To extend it, you need to explicitly call the constructor of the parent with a super() call.
class TypeTwoEvent(Event):
def __init__(self, level=None, **kwargs):
# the super call to set the attributes in the parent class
super().__init__(**kwargs)
# now, extend other attributes
self.sr1 = level
self.state = STATE_EVENT_TWO
Note that the super call is not always at the top of the __init__ method in your sub-class. Its location depends on your situation and logic.
When the instance is created, its __init__ method is called. In this case, that is TypeTwoEvent.__init__. Superclass methods will not be called automatically because that would be immensely confusing.
You should call Event.__init__(self, ...) from TypeTwoEvent.__init__ (or use super, but if you're not familiar with it, read up on it first so you know what you're doing).
You need to call the __init__ method of the base class from the __init__ method of the inherited class.
See here for how to do this.
I've had the same problem, but in my case I put super().__init__() on the bottom of my derived class and that's why it doesn't work. Because I tried to use attributes that are not initialized.

Categories