There are almost infinite ways to "solve" this, but I'll present a few.
None are "right", all involve tradeoffs and over time you'll learn which make sense where.
Passthrough arguments
class Vehicle():
"""To model a basic vehicle"""
def __init__(self, name, max_speed, millage, tyre_size, tyre_pressure):
"""Initiate class variables"""
self.name = name
self.max_speed = max_speed
self.millage = millage
self.tyre = Tyre(tyre_size, tyre_pressure)
def vehicle_details(self):
"""display vehicle details"""
return f"\nName: {self.name.title()}, Max speed: {self.max_speed}MPH, Millage: {self.millage} "
class Tyre():
"""A class specific for vehicle tyres"""
def __init__(self, size, pressure):
self.size = size
self.pressure = pressure
def tyre_details(self):
"""Print tyre details."""
print(f'Tyre size: {self.size} inches.')
print(f"Tyre pressure {self.pressure} PSI.")
v1 = Vehicle("VehicleName", 120, 50_000, 16, 36)
# Or, with named arguments
v2 = Vehicle(
name = "VehicleName",
max_speed = 120,
millage = 50_000,
tyre_size = 16,
typre_pressure = 36
)
Here, you're just passing the Tyre constructor's arguments through from the Vehicle constructor to your construction of Tyre. If every time you construct a Vehicle you'll know the Tyre specifications, this is fine. If not, you'll likely want an alternative.
Construct Vehicle with Tyre instance as argument
class Vehicle():
"""To model a basic vehicle"""
def __init__(self, name, max_speed, millage, tyre):
"""Initiate class variables"""
self.name = name
self.max_speed = max_speed
self.millage = millage
self.tyre = tyre
def vehicle_details(self):
"""display vehicle details"""
return f"\nName: {self.name.title()}, Max speed: {self.max_speed}MPH, Millage: {self.millage} "
class Tyre():
"""A class specific for vehicle tyres"""
def __init__(self, size, pressure):
self.size = size
self.pressure = pressure
def tyre_details(self):
"""Print tyre details."""
print(f'Tyre size: {self.size} inches.')
print(f"Tyre pressure {self.pressure} PSI.")
v = Vehicle(
name = "VehicleName",
max_speed = 120,
millage = 50_000,
tyre = Tyre(16, 36)
)
Similar to the previous option, but in the previous option each Vehicle had their own Tyre instance. Here you can "share" Tyre objects. Probably not a huge deal in this case, but something to keep in mind, especially when you work with larger or more complex objects and/or where sharing becomes a benefit.
Sharing Tyre instances might look like:
standard_tyre = Tyre(16, 36)
v1 = Vehicle(
name = "VehicleOne",
max_speed = 120,
millage = 50_000,
tyre = standard_tyre,
)
v2 = Vehicle(
name = "VehicleTwo",
max_speed = 140,
millage = 20_000,
tyre = standard_tyre,
)
Setting tyre later, outside of the constructor
class Vehicle():
"""To model a basic vehicle"""
def __init__(self, name, max_speed, millage):
"""Initiate class variables"""
self.name = name
self.max_speed = max_speed
self.millage = millage
self.tyre = None
def vehicle_details(self):
"""display vehicle details"""
return f"\nName: {self.name.title()}, Max speed: {self.max_speed}MPH, Millage: {self.millage} "
class Tyre():
"""A class specific for vehicle tyres"""
def __init__(self, size, pressure):
self.size = size
self.pressure = pressure
def tyre_details(self):
"""Print tyre details."""
print(f'Tyre size: {self.size} inches.')
print(f"Tyre pressure {self.pressure} PSI.")
v = Vehicle(
name = "VehicleName",
max_speed = 120,
millage = 50_000,
)
v.tyre = Tyre(16,36)
Maybe you don't know what the specifics of the Tyre are when you're creating the Vehicle, but you still want a Vehicle instance.