overiding class attributes but not methods in the child class

Viewed 39

I have this problem, for example I define a Vehicle class as such.

class Vehicle():
    speed = 0
    def __init__(self):
        pass
    def get_speed(self):
        return Vehicle.speed

I have a class attribute speed which I will override in the Bike child class

class Bike(Vehicle):
   speed = 20

if I instantiate a new object of type Bike I get this

>>> a = Bike()
>>> a.get_speed()
0

How do I make it to get without having to override parent class methods.

>>> a.get_speed()
20

I do have a solution but I don't know if it is a good programming practice or not, because instance variables should be unique to that instance, so now I am very much confused.

class Vehicle():
   def __init__(self):
      self.speed = 0

   def get_speed(self):
      return self.speed

class Bike(Vehicle):
   def __init__(self):
      self.speed = 20

should I re-declare it as an instance variable so that if I override self.speed = 20 in the constructor then I get

>>> a = Bike()
>>> a.get_speed()
20

Any help would be much appreciated, thanks a lot in advance.

2 Answers

If an attribute cannot be found in an object's __dict__, i.e. when it is not an instance attribute, Python will look for that attribute in the class next.

That's why you can simply do:

>>> class Vehicle:
...     speed = 0
...     def get_speed(self):
...         return self.speed
...     
>>> class Bike(Vehicle):
...     speed = 20
...     
>>> a = Bike()
>>> a.get_speed()
20

Additionally, I would get rid of that get_speed method. Writing getters and setters is not idiomatic Python. Simply use a.speed.

If you want to protect the attribute against being set, consider using properties.

If you need get_speed to be a class-wide property (not an instance-wide), you could use @classmethod decorator:

class Vehicle():
    speed = 0
    def __init__(self):
        pass

    @classmethod
    def get_speed(cls):
        return cls.speed

It would still be possible to override speed attribute inside a class instance though.

Related