Subclass constructor calling wrong __init__ - python

So I am having some trouble with inheritance in python. I have two classes. The first is
class Base1DHeatEquation:
def __init__(self, alpha, final_time, time_discrete):
self.alpha = alpha
self.final_time = final_time
self.time_discrete = time_discrete
#Additional Functions which aren't causing a problem
and the second is a class which inherits the first
class IntialValueTest1DHE(Base1DHeatEquation):
def __init__(self, alpha, final_time, time_discrete,intialValues,\
x_discrete ,noise):
super(IntialValueTest1DHE,self).__init__(self, alpha, final_time, time_discrete)
self.intialValues = intialValues
#Additional Functions which aren't causing a problem
The problem is when I trying to create an IntialValueTest1DHE object, I get the following
>>> import HeatEquation1D as he #The File where both classes are stored
>>> temp = he.IntialValueTest1DHE(1,1,100,np.sin,100,0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 4 arguments (7 given)
It seems like object creation is trying to access the init from the parent class in stead of the child class and I am not sure how to fix that.

You don't need to add "self" to super() declaration. Also, you should use "new style" classes:
class Base1DHeatEquation(object):
def __init__(self, alpha, final_time, time_discrete):
self.alpha = alpha
self.final_time = final_time
self.time_discrete = time_discrete
class IntialValueTest1DHE(Base1DHeatEquation):
def __init__(self, alpha, final_time, time_discrete,intialValues,
x_discrete ,noise):
super(IntialValueTest1DHE,self).__init__(alpha, final_time, time_discrete)
self.intialValues = intialValues

Related

Are you allowed to use a method inside the init method?

I just started learning about OOP in python3 and we made this little class today.
class Square:
def __init__(self, side):
self.side = side
def show_perimeter(self):
print(self.side * 4)
test_square = Square(10)
test_square.show_perimeter()
>> 40
Now I'm thinking if it's possible to get the value of the perimeter while creating the object, something like...
class Square:
def __init__(self, side):
self.side = side
self.permiter = get_perimeter(self)
def get_perimeter(self):
return self.side * 4
test_square = Square(10)
print(test_square.perimeter)
Is this something you're able to do?
If so, is it a good practice?
If not, what would be the best way to get the perimeter by just using the side?
There is nothing special about the __init__ method other than it is invoked automatically as part of the construction of an object (__new__ creates the object, and __init__ initializes it). Therefore, you can do whatever you need to do within it. However, you need to make sure that you don't inadvertently do things that would cause operations on a partially initialized object. The use of #property below can solve most of these edge cases.
The only difference here is it is better form to call self.method() rather than method(self) in most cases.
class Square:
def __init__(self, side):
self.side = side
self.permiter = self.get_perimeter()
def get_perimeter(self):
return self.side * 4
test_square = Square(10)
print(test_square.perimeter)
However, I'd like to point out that a property might be better in this case:
class Square():
def __init__(self, side):
self.side = side;
#property
def perimeter(self):
return self.side * 4
x = Square(10)
print(x.perimeter)
>>> 40
In this case, the #property decorator converts the perimeter method to a property which can be accessed just like it is another attribute, but it is calculated at the time it is asked for.
It's allowed, but it's also a lot more dangerous than people usually realize.
Say you have the following class:
class Thing:
def __init__(self):
self._cached_size = self.compute_size()
def compute_size(self):
return 1000
That seems to work fine on its own, but then if you try to subclass it:
class SubThing(Thing):
def __init__(self, more_stuff):
super().__init__()
self.more_stuff = more_stuff
def compute_size(self):
return super().compute_size() + self.more_stuff
SubThing(5)
Everything goes to pieces, because Thing.__init__ calls SubThing.compute_size, and SubThing.compute_size assumes self.more_stuff is ready, but it's not ready:
Traceback (most recent call last):
File "./prog.py", line 14, in <module>
File "./prog.py", line 9, in __init__
File "./prog.py", line 3, in __init__
File "./prog.py", line 12, in compute_size
AttributeError: 'SubThing' object has no attribute 'more_stuff'
You should essentially never call methods in __init__ that you expect to be overridden, since your object is in a very precarious, half-constructed state, especially the parts of its state that subclasses are responsible for.
If you want to use your own class's version of a method and ignore overrides (dodging the problem of subclass state), you can call it directly:
class Thing:
def __init__(self):
self._cached_size = Thing.compute_size(self)
def compute_size(self):
return 1000
Some people might recommend having subclasses initialize their state before calling super().__init__, but that leads into a really nastily coupled mess of different classes depending on specific parts of other classes being ready. It's not going to decrease the number of problems you have.
You should reference the method in the same class with self.
class Square:
def __init__(self, side):
self.side = side
self.perimeter = self.get_perimeter()
def get_perimeter(self):
return self.side * 4

Error with inheritance in python

i'm doing an UNO game using Pygame, i'm doing it with lists of cards and classes of each color, when I tried to test the inheritance for using the color class, I got this error:
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
x=example()
File "C:/Users/Tamara/Desktop/TEC/UNO/UNOclases.py", line 93, in __init__
Red.__init__(self,Redlist)
TypeError: unbound method __init__() must be called with Red instance as first argument (got example instance instead)
Here's the code (don't mind if one of the names is wrong written, I had to translate it from spanish):
class Red:
def setSpecialRedCards(self):
self.__Redlist.append(self.__steal2)
self.__Redlist.append(self.__steal2)
self.__Redlist.append(self.__Reverse)
self.__Redlist.append(self.__Reverse)
self.__Redlist.append(self.__Jump)
self.__Redlist.append(self.__Jump)
def setRedNumers (self, number,counter):
while counter<=9:
if numero!=0:
self.__Redlist.append(number)
self.__Redlist.append(number)
else:
self.__listaRoja.append(number)
number+=1
counter+=1
def getRed(self):
return self.__Redlist
def __init__(self, Redlist=[]):
self.__Redlist=Redlist
self.__number0 = "red 0"
self.__steal2 = "steal2"
self.__Reverse = "Reverse"
self.__jump = "jump"
class example:
def __init__(self, Redlist=[]):
Red.__init__(self,Redlist)
def example2(self):
return Red.__number0
Thank you for your help!
Your class example doesn't inherit from class Red.
Write
class example(Red):
....

Python Multiple Inheritance: Argument passing (**kwargs) and super()

I am trying to understand Python multiple inheritance and I kind of understand MRO, super() and passing arguments in MI, but while I was reading the below example it kind of confused me.
class Contact:
all_contacts = []
def __init__(self, name=None, email=None, **kwargs):
super().__init__(**kwargs)
self.name = name
self.email = email
self.all_contacts.append(self)
class AddressHolder:
def __init__(self, street=None, city=None, state=None, code=None, **kwargs):
super().__init__(**kwargs)
self.street = street
self.city = city
self.state = state
self.code = code
class Friend(Contact, AddressHolder):
def __init__(self, phone='', **kwargs):
super().__init__(**kwargs)
self.phone = phone
Now what I fail to understand is why use super() in Contact and AddressHolder class. I mean super() is used when we are inheriting from a parent class but both Contact & AddressHolder are not inheriting from any other class. (technically they are inheriting from object). This example confuses me with the right use of super()
All (new style) classes have a linearized method resolution order (MRO). Depending on the inheritance tree, actually figuring out the MRO can be a bit mind-bending, but it is deterministic via a relatively simple algorithm. You can also check the MRO through a class's __mro__ attribute.
super gets a delegator to the next class in the MRO. In your example, Friend has the following MRO:
Friend -> Contact -> AddressHolder -> object
If you call super in one of Friend's methods, you'll get a delegator that delegates to Contact's methods. If that method doesn't call super, you'll never call the methods on AddressHolder. In other words, super is responsible for calling only the next method in the MRO, not ALL the remaining methods in the MRO.
(If you call super in one of Friend's methods and Contact doesn't have its own implementation of that method, then super will delegate to AddressHolder, or whichever class has the next implementation for that method in the MRO.)
This is all well and good since object has a completely functional __init__ method (so long as **kwargs is empty at that point). Unfortunately, it doesn't work if you are trying to resolve the call chain of some custom method. e.g. foo. In that case, you want to insert a base class that all of the base classes inherit from. Since that class is a base for all of the classes (or at least base classes) to inherit from. That class will end up at the end of the MRO and can do parameter validation1:
class FooProvider:
def foo(self, **kwargs):
assert not kwargs # Make sure all kwargs have been stripped
class Bar(FooProvider):
def foo(self, x, **kwargs):
self.x = x
super().foo(**kwargs)
class Baz(FooProvider):
def foo(self, y, **kwargs):
self.y = y
super().foo(**kwargs)
class Qux(Bar, Baz):
def foo(self, z, **kwargs):
self.z = z
super().foo(**kwargs)
demo:
>>> q = Qux()
>>> q.foo(x=1, y=2, z=3)
>>> vars(q)
{'z': 3, 'y': 2, 'x': 1}
>>> q.foo(die='invalid')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() missing 1 required positional argument: 'z'
>>>
>>> q.foo(x=1, y=2, z=3, die='invalid')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/google/home/mgilson/sandbox/super_.py", line 18, in foo
super().foo(**kwargs)
File "/usr/local/google/home/mgilson/sandbox/super_.py", line 8, in foo
super().foo(**kwargs)
File "/usr/local/google/home/mgilson/sandbox/super_.py", line 13, in foo
super().foo(**kwargs)
File "/usr/local/google/home/mgilson/sandbox/super_.py", line 3, in foo
assert not kwargs # Make sure all kwargs have been stripped
AssertionError
Note, you can still have default arguments with this approach so you don't lose too much there.
1Note, this isn't the only strategy to deal with this problem -- There are other approaches you can take when making mixins, etc. but this is by far the most robust approach.

Python asking for two arguments when one needs to be passed

I'm new to python and was working on this code:
class Shape:
def __init__(self, shape):
self.shape = shape
def shapeName(self):
print(self.shape)
class Rectangle(Shape): # Rectangle class inherits Shape
count = 0 # static variable
def __init__(self, name):
Shape.__init__(self.name)
print('In Rectangle')
Rectangle.count = Rectangle.count + 1
rec1 = Rectangle('Rectangle')
rec2 = Rectangle('Rectangle')
rec1.shapeName()
rec2.shapeName()
print( Rectangle.count )
I'm getting the following error:
C:\Python32\python.exe C:/Users/ashutosh/PycharmProjects/Test/InheritanceTest.py
Traceback (most recent call last):
File "C:/Users/ashutosh/PycharmProjects/Test/InheritanceTest.py", line 17, in <module>
rec = Rectangle('Rectangle')
File "C:/Users/ashutosh/PycharmProjects/Test/InheritanceTest.py", line 13, in __init__
Shape.__init__(name)
TypeError: __init__() takes exactly 2 arguments (1 given)
Process finished with exit code 1
The first argument to constructor is the current object and second is the name of the shape. Then why it is saying that I have to pass 2 arguments?
Shape is a class, not an object, so when you call Shape.__init__ there's no self variable. In other words, there is no instance of Shape to call init on. The instance you want is the subclass instance of Shape that you have, i.e. self (the Rectangle). You could simply pass self, like this:
Shape.__init__(self, name)
or make use of the super keyword:
super(Rectangle, self).__init__(name)
The super keyword allows you to implicitly refer to your superclass, without using the name.
In Python 3.0 you can simply write super().__init__(name) without even the child reference.
You have to pass self explicitly to Shape.__init__.
So your rectangle class should look like this:
class Rectangle(Shape): # Rectangle class inherits Shape
count = 0
def __init__(self, name):
Shape.__init__(self, name)
print('In Rectangle')

Simple Inherit from class in Python throws error

Hi I just started with Python, I'm currently developing a UI testing application for mobile devices and I have to work on a custom rendered Softkeyboard.
Button.py
class Button():
def __init__(self, name, x, y, x2=None, y2=None):
self.name = name
self.x = x
self.y = y
self.x2 = x2
self.y2 = y2
KeyboardKey.py
import Button
class KeyboardKey(Button):
def __init__(self, name, x, y):
super(self.__class__, self).__init__(name, x, y)
That's my error:
Traceback (most recent call last):
File "/home/thomas/.../KeyboardKey.py", line 2, in
class KeyboardKey(Button):
TypeError: Error when calling the metaclass bases
module.__init__() takes at most 2 arguments (3 given)
The way you do in your code, you inherit from module Button, not a class. You should inherit class Button.Button instead.
In order to avoid this in future, I strongly suggest to name modules with lowercase, and capitalize classes. So, better naming would be:
import button
class KeyboardKey(button.Button):
def __init__(self, name, x, y):
super(self.__class__, self).__init__(name, x, y)
Modules in python are normal objects (of type types.ModuleType), can be inherited, and have __init__ method:
>>> import base64
>>> base64.__init__
<method-wrapper '__init__' of module object at 0x00AB5630>
See usage:
>>> base64.__init__('modname', 'docs here')
>>> base64.__doc__
'docs here'
>>> base64.__name__
'modname'

Categories