Is there any difference between this:
class Vehicle():
def __init__(self, x, y):
self.y = y
self.x = x
class Car(Vehicle):
def __init__(self, x, y):
Vehicle.__init__(self, x, y)
class Scooter(Vehicle):
def __init__(self, x, y):
Vehicle.__init__(self, x, y)
and this:
class Vehicle():
def __init__(self, x, y):
self.y = y
self.x = x
class Car(Vehicle):
pass
class Scooter(Vehicle):
pass
Because without def __init__ in child classes I got the same thing, I mean __init__ doesn't provide any effect.
You should't do either of them. The best way to do it is using super.
class Vehicle():
def __init__(self, x, y):
self.y = y
self.x = x
class Car(Vehicle):
def __init__(self, x, y):
super(Car, self).__init__(x, y)
# super().__init__(x, y) # for python3
Check this blog post by Raymond Hettinger (core python contributor) on why you should be using super
You need __init__ method when you want to do child specific initialisation. Assume your child classes require another argument to be passed to the constructor and is unique to that class, in that case __init__ method is really required.
class Vehicle():
def __init__(self, x, y):
self.y = y
self.x = x
class Car(Vehicle):
def __init__(self, x, y, z):
Vehicle.__init__(self, x, y)
self.z = z
class Scooter(Vehicle):
def __init__(self, x, y, z):
Vehicle.__init__(self, x, y)
self.z = z
I think this would be best explained with an example.
Now take this scenario:
>Vehicle ---> Car,Bike,Boat,Aeroplane,Train
>[All are vehicles right]
>Things they have in common would be (say for ex.) **Price** and **Color**
However things they won't have in common would be?
>**Wheels**. The total number of wheels may differ.
>
> Car-4 Bike-2 Boat-0 Aeroplane-(**Not sure**) Train-(**Many I
guess**?)
But you get the point right? So When I want to just have a Vehicle object I don't want (or I can't tell the number of wheels) In that case I can initialize only with just price and color
However when I know the specific type of Vehicle say Car now I can __init__ it with number of wheels. Now this is where object specific initializations play a major role.
A full example code of the above sample:
class Vehicle():
def __init__(self, x, y):
self.color = y
self.price = x
def Horn(self):
print("Pommm...Pommmmm!!")
class Car(Vehicle):
def __init__(self, x, y,wheel):
Vehicle.__init__(self, x, y)
self.wheel = "Four Wheels man: 4"
class Scooter(Vehicle):
def __init__(self, x, y,wheel):
Vehicle.__init__(self, x, y)
self.wheel = "Just Two man : 2"
VehObj = Vehicle("5000$","Black")
VehObj.Horn()
print(VehObj.color,VehObj.price)
#However note this
carObj = Car("5000$","Black",4)
print(carObj.color,carObj.price,carObj.wheel)
#Look at this
sObj = Scooter("5000$","Black",2)
print(sObj.color,sObj.price,sObj.wheel)
Output:
Pommm...Pommmmm!!
Black 5000$
Black 5000$ Four Wheels man: 4
Black 5000$ Just Two man : 2
Hope that cleared you up.
If you don't provide an __init__ method in the child classes, they will just use the __init__ method defined in their parent class (aka inheritance). In the former case, you are overriding the __init__ method for the child classes but you are simply calling the __init__ method of the parent class. So if you don't do that (like the later case) it will be the same. The later case automatically inherits the __init__ method.
Other ways to write the same thing would be:
class Car(Vehicle): #This is the best way to do it though
def __init__(self, x, y):
super()__init__(x, y)
Or
class Car(Vehicle):
def __init__(self, x, y):
self.x = x
self.y = y
TLDR; They are equivalent.
Calling the init method of super class is optional if you don't wont to edit the __init__ method of superclass.
but if you want to edit the superclass method you need custom init
class Vehicle():
def __init__(self, x, y):
self.y = y
self.x = x
class Car(Vehicle):
def __init__(self, x, y, z):
Vehicle.__init__(self, x, y)
self.z = z
Related
I am trying to make a subclass, Square, from a superclass, Shape.
class Shape :
def __init__ (self, x, y) :
self.x = x
self.y = y
self.description = "This shape has not been described yet"
def area (self) :
return self.x * self.y
def describe (self, text) :
self.description = text
I have tried
class Square (Shape) :
def __init__ (self, x) :
self.x = x
self.y = x
self.description = "This shape has not been described yet"
which seems to work, but the only thing that actually changes in Square is self.y = x, so I wonder if I could do the same thing without having to write self.x and self.description again.
(I tried doing something like this:
class Square (Shape) :
def __init__ (self, x) :
self.y = x
super().__init__()
but, when I create a Square object, a type error occurs:
TypeError: init() missing 2 required positional arguments: 'x' and 'y')
A Square is a Shape whose x and y are the same. Hence:
class Square(Shape):
def __init__(self, x):
super().__init__(x, x)
You just need to call Shape.__init__(self, x, y) with your x as both the x and y parameters.
Just call the super function inside __init__. Put both the arguments equal to x.
class Square(Shape):
def __init__(self, x):
super().__init__(x, x)
I have a Python class with complicated initialization. I would like to mock the class initialization to avoid writing too much scaffolding code. I want to test its non-mocked method.
A simple example:
class Person:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def do_work(self):
return self.x + self.y
There's an answer which shows how to get it done and it works - https://stackoverflow.com/a/21771920/3346915.
Here's a passing test:
from unittest.mock import patch
with patch.object(Person, '__init__', lambda self: None):
person = Person()
person.x = 3
person.y = 4
assert person.do_work() == 7
I wonder, however, if it would be possible to pass x and y as part of the Person initialization to avoid assigning the fields after the construction to reduce the amount of code?
I wonder if this would be possible?
from unittest.mock import patch
with patch.object(Person, '__init__', lambda self, x, y: None):
person = Person(x=3, y=4)
assert person.do_work() == 7
This doesn't work of course because the x and y values are not assigned to the person instance.
lambdas do not support assignment, but you do not have to use lambda as third argument - normal (named) function will work too, so you can do:
class Person:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def do_work(self):
return self.x + self.y
from unittest.mock import patch
def newinit(self, x, y):
self.x = x
self.y = y
with patch.object(Person, '__init__', newinit):
person = Person(x=3, y=4)
assert person.do_work() == 7
(tested in Python 3.7.3)
Suppose I have some Python class:
class A:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
And now, I want to define a child class whose y value is set by default, say with value 1. The only change in this new class is this default for y, then I guess this formulation will work
class B(A):
def __init__(self, **kwargs):
y = kwargs.pop("y", 1)
assert y == 1
super.__init__(y=y, **kwargs)
What is the classic form to pass defaults in inheritance?
It depends on what you want. Your current code throws an error if y is anything other than 1, so it's pointless to make it a parameter at all. Just do:
class B(A):
def __init__(self, *args, **kwargs):
super().__init__(*args, y=1, **kwargs)
This passes all parameters through to A, whether passed positionally or as keywords, and fixes y to 1. You'll get an error if you try to pass y to B.
Alternatively, if you want y to default to 1 but still be able to supply it as an argument to B:
class B(A):
def __init__(self, *args, y=1, **kwargs):
super().__init__(*args, y=y, **kwargs)
The second code sample won't work. It requires keyword arguments which is surprising compared to the first sample and with assert it requires y == 1, it doesn't default to it. Also super must be called.
Usual way (with reordering of parameters) is:
class B(A):
def __init__(self, x, z, y=1):
super().__init__(x, y, z)
Alternatively without reordering:
class B(A):
def __init__(self, x, yz, z=None):
if z is None:
super().__init__(x, 1, yz)
else:
super().__init__(x, yz, z)
I am knew at this and not sure the exact syntax to use to add x,y in python using this class definition
class Add(values):
def __init__(self, x, y):
values.__init__(self, [x, y])
def forward(self):
return self.values[x] + values[1]
I am not able to figure out how to access x,y to add them together. I have tried all the possibilities that I can think of. Thank you.
I think you want a function and not a class.
def add(x, y):
return x+y
If you're sure that this really has to be a class for whatever you're doing, it can look like this:
class Add:
def __init__(self, x, y):
self.x = x
self.y = y
def forward(self):
return self.x+self.y
Then
>>>add(5, 6)
11
>>>a = Add(5, 6)
>>>a.forward()
11
i think that is what you need
class Values():
def __init__(self, x = 0, y=0):
self.x_value = x
self.y_value = y
class Add(Values):
def __init__(self, x = 0, y=0):
Values.__init__(self, x, y)
def forward(self):
return (self.x_value + self.y_value)
add = Add(x = 20, y=20)
print (add.forward())
To add something to other answers, I would say that :
class Add(values):
means that you create class 'Add' who inherits from the class 'values'. Class 'values' must be defined somewhere otherwise you will have the NameError.
More info about inheritance here :
https://docs.python.org/3.6/tutorial/classes.html#inheritance
Actually the answer I was looking for is :
self.x =[0]
self.y = [1]
Thanks for the tries.
If we have class A, defined as follows,
class A:
def __init__(self, x):
self.x = x
why do most people use
class B(A):
def __init__(self, x, y):
super().__init__(x)
self.y = y
instead of
class B(A):
def __init__(self, x, y):
A.__init__(self, x)
self.y = y
? I think A.__init__(self, x) is better then super().__init__(x) because it supports multiple inheritance (and I didn't find a way to do it with super()):
class A:
def __init__(self, x):
self.x = x
class B:
def __init__(self, y):
self.y = y
class C(A, B):
def __init__(self, x, y, z):
A.__init__(self, x)
B.__init__(self, y)
self.z = z
When I try to use super() in the previous example, like this:
class A:
def __init__(self, x):
self.x = x
class B:
def __init__(self, y):
self.y = y
class C(A, B):
def __init__(self, x, y, z):
super().__init__(self, x)
super().__init__(self, y)
self.z = z
class C doesn't have attribute y (try: c = C(1, 2, 3) and print(c.y) in next line).
What am I doing wrong?
I you use super().__init__(), Python will automatically call all constructors of your base classes on its own in the right order (in your second example first A, then Bconstructors).
This is one of the beauty of Python, it handles multiple inheritance nicely :).