Reputation: 33
here is an example of what I'm trying to do, using Python 3:
If an owner
method of a wheel
object, that is part of a car
object were to return its owner's name - which in this case should be the same as the car
owner - how would it access the car
object's owner
attribute in Python?
The structure is as follows:
object car
- has: owner attribute
- has: owner getter method
- has: list of wheel objects
-- contains: wheel object
--- has: owner getter method
What I want to (edit: must) avoid, is providing the car
object as a parameter (self
) to the constructor when instantiating the wheel
object.
Meaning: The wheel
object should make itself aware of the context / car
class object it is being instantiated within and keep a reference to it.
How do I do that?
Example code might look like:
class car:
def __init__(self):
self.owner = "testowner"
self.wheels = list()
self.wheels.append(wheel()) # wheel must not be called with "self" as a parameter
def get_owner(self):
return self.owner
class wheel:
def __init__(self):
self.car_mounted_to = self.get_instantiating_object() # the object "mycar" in this example
def get_instantiating_object(self):
# ... ? ...
def get_owner(self):
self.car_mounted_to.get_owner()
mycar = car()
mycar.wheels.append(wheel()) # this should still result in the object "mycar"
Upvotes: 0
Views: 85
Reputation: 522076
A wheel can only know it’s a wheel, it can’t know what structure it is a part of. Since the wheel is an object that can be passed around, it’s possible for the wheel to be part of more than one structure at once. Typically you don’t want objects to know too much about their “surroundings”, as that creates needless dependencies and makes objects more complex and brittle than need be. An object should only know about things that it received as constructor or method arguments and not try to infer anything about its environment.
I see two possible approaches:
Create your car object and give it wheel objects, but don’t make the wheels aware of the car at all. You then have some external code that traverses your object hierarchy, and while doing so it will discover the wheels on the car and hence know what belongs to what.
Implement the descriptor protocol, and any time you try to access a wheel of the car, the car object will return a “bound” wheel in some way or another (e.g. like methods receive self
as their first argument). So the car object is still being passed to the wheel explicitly (since that’s the only sane way to make the wheel aware of the car), but it happens not at construction time but when you access the specific car’s wheel. That also solves the problem of possibly assigning one wheel to another car and messing up the relationships.
Upvotes: 2
Reputation: 6114
Technically, the following could be a solution that meets your demand: We keep track of all cars
, so we can find the car
a certain wheel
is mounted on by checking every car
whether the wheel is mounted on it.
NB that this is far away from straight forward of implementing what you need. You should very well know why you do it that way and not just simply have the car_mounted_on
as an instance variable of wheel
. That said, if you really know why and want to do this, this is how it could be done:
import typing
class Car:
instances = []
def __init__(self, wheels: typing.List["Wheel"], owner: "Person"):
Car.instances.append(self)
self.wheels = wheels
self.owner = owner
class Wheel:
def __init__(self):
pass
@property
def car_mounted_on(self) -> typing.Union["Car", None]:
for car in Car.instances:
if self in car.wheels:
return car
@car_mounted_on.setter
def car_mounted_on(self, car: "Car"):
# Remove the wheel from its current car and mount it on the given car.
self.car_mounted_on.wheels.remove(self)
car.wheels.append(self)
@property
def owner(self):
if self.car_mounted_on is not None:
return self.car_mounted_on.owner
Upvotes: 1