Adding an Instance Method
00:00
The task was to add an instance method called .drive()
that takes some miles
as an argument. Then that should increment self.mileage
for how many miles
you passed in and then test it. So I want to define .drive()
, and this instance method won’t be a special method like the first two with the double underscores.
00:27
But this is just a method that is public to the Car
class and that I’m going to define now. And still, it takes self
as its first argument because I want to do something on the instance of the Car
, and then it also takes another argument.
00:42
So I put in the parameter miles
in the method definition, and that just means that when calling Car.drive()
, you have to pass in miles
. That’s going to be a number. And then what do you want to do with this?
00:56
You want to increment self.mileage
. So because you’re passing self
here and because this is a method on an instance of a Car
, you have access to this self
object.
01:08
So I can say self.mileage
and then just increment it. So I’m going to say += miles
. So this is going to take the miles
that someone passes when calling .drive()
and adds it to self.mileage
.
01:24
And you can also do just = self.mileage + miles
. That’s the same. But I’m going to go for the shorter version. This is a shortcut to saying .self.mileage + miles
.
01:42
I think that should be it. Let’s go ahead and test it. So I will press F5, run it, and go into the interactive console. And then I’m just going to call it car
.
01:57
Car()
and it will be "blue"
02:01
and have 0
miles. Actually, just for fun, this car
is going to be "white"
, 0
miles. Okay, so we have this Car
object. If I print(car)
, The white car has 0 miles.
And now I should be able to say car.drive()
.
02:20
I’m going to drive this car for a hundred miles, no output. But something happened in here because now if I print(car)
, it tells me that The white car has 100 miles.
So with this instance method here, with .drive()
, I accessed an instance attribute, .mileage
, and changed it basically with whatever I input here as an argument. So that works.
02:46
I can continue driving the white car, .drive()
for, let’s drive it for another a hundred miles, and then it should
02:57
have 200
miles on there. Perfect.
03:02 So good job if you came up with something similar to this, and if you have a different solution, post it in the comments. I’m curious to see.
Martin Breuss RP Team on Oct. 25, 2023
@DimaG thanks for sharing your code using a dataclass and the operator
module! :D
Two small notes:
You don’t need get_more_mileage()
, it has the same functionality as get_mileage
, so you could skip that and just call get_mileage()
another time in your second for
loop.
Secondly, I’d say that get_mileage()
isn’t a very descriptive name for the functionality that you’re encoding here. You’re creating a callable that’ll call .drive()
with an argument of 100
. Can you come up with a more descriptive name for it?
Nice work expanding on the topics taught in the course! 🙌
Anonymous on Feb. 18, 2024
Here is my version of the challenge:
from random import uniform
class Car:
def __init__(self,
make_car: str,
model_car: str,
year: int,
color: str,
mileage: float,
) -> None:
self.make_car = make_car
self.model_car = model_car
self.year = year
self.color = color
self.mileage = mileage
def start(self):
print(f'Starting {self.make_car} {self.model_car}...')
def stop(self):
print(f'{self.model_car} stopped...')
def drive(self, distance: float) -> None:
if Car.validate_float(distance, True):
previous_mileage = self.mileage
self.mileage += distance
return (
f'\tCurrent mileage {previous_mileage:,}km.\n'
f'\tNew mileage {self.mileage:,}km.'
)
else:
raise ValueError('Incorrect mileage has been given!')
@staticmethod
def validate_float(value: float, is_positive: bool=False) -> bool:
'''if used in the Car Class, validate if distance is not <= 0
for general use, return false if value is not an instance of type(float)'''
if isinstance(value, float):
if is_positive:
return True if value > 0 else False
else:
return True
else:
return False
def __str__(self):
return f'The {self.color} car has {self.mileage:,}km.'
ford = Car('Ford', 'Ranger', 2014, 'blue', 20_000)
citroen = Car('Citroën', 'Vision', 2030, 'red', 30_000,)
car_obj_mapping = {
'ford': ford,
'citroen': citroen,
}
entered_car_brands = set()
for i in range(2):
while True:
get_car_brand = input('Car brand: ')
if get_car_brand in entered_car_brands:
print(f'{get_car_brand} has already been driven!')
continue
elif car_obj_mapping.get(get_car_brand, None):
entered_car_brands.add(get_car_brand)
car_obj_mapping[get_car_brand].start()
break
else:
print(f'{get_car_brand} not recognized as a car brand!')
random_distance = round(uniform(1, 500), 2)
print(f'{ford.drive(random_distance)}')
car_obj_mapping[get_car_brand].stop()
else:
print('Test Drive complete!')
Anonymous on Feb. 18, 2024
Forgot to also change the last line:
# from
print(f'{ford.drive(random_distance)}')
# to
print(f'{car_obj_mapping[get_car_brand].drive(random_distance)}')
RV on Nov. 15, 2024
Hello,
I have a question, why we are not using the return statement in the .drive() method, although we are using it in the __str__
method?
If I write the drive method like this:
def drive(self, miles):
return self.mileage += miles
and try to run the code, I will get a syntax error (invalid syntax): “+” sign is marked with red. If I don’t use return
then everything is fine.
Martin Breuss RP Team on Nov. 18, 2024
@RV there are two separate situations that you’re dealing with here.
1) Returning vs Updating Data Attributes in Classes
You generally don’t need to return a data attribute of a class, when you want to apply some operation on it. Your class is keeping track of the data attribute, and you can always access the updated attribute through e.g. in this case .mileage
.
Because you have access to the instance through self
, you can directly update the value that .mileage
holds through self.mileage
.
On the other hand, when you define a .__str__()
method, then you’re not updating a data attribute of the object. Instead, you’re creating a new string representation that you need to return if you want to access it outside of the function, e.g. to print it to the console.
2) Returning Values
The second situation, which is why you’re getting the error message, is that the +=
syntax is an augmented assignment operator, which modifies a variable in place but does not produce a value that Python can return.
So, this is incorrect syntax in Python. You could return the data attribute from the method like so:
def drive(self, miles):
self.mileage += miles
return self.mileage
In this case, you use the augmented assignment statement to update self.mileage
(effectively writing self.mileage = self.mileage + miles
, which is another statement that you couldn’t return), and then you return only the value of self.mileage
in the next line.
However, like mentioned in Point 1, you probably don’t want to return self.mileage
, because it’s a data attribute on your instance, and you just want to update that attribute.
Hope that makes sense, otherwise keep asking :)
RV on Nov. 20, 2024
Thank you for your reply, Martin!
Become a Member to join the conversation.
DimaG on Oct. 19, 2023
This is my version of the Car class written using dataclass syntax and operator.methodcaller():