Agregar dinámicamente una propiedad a una clase con el fin de devolver un nuevo objeto en cada llamada.
Tengo una clase Car:
class Car:
def __init__(self, speed):
self.speed = speed
También tengo un diccionario cars que contiene nombres y velocidades de algunos coches:
cars = {"bmw" : 250, "ferrari": 350, ...}
Ahora quiero tener una clase contenedora que tenga una propiedad para cada uno de estos coches predefinidos, de modo que llamar a la propiedad cree un nuevo objeto Car cada vez; algo así:
class PredefinedCars:
@property
def bmw(self):
return Car(250)
@property
def ferrari(self):
return Car(350)
...
Pero no quiero escribir una propiedad para cada coche en el diccionario, porque hay demasiados y además el diccionario puede cambiar. En su lugar, quiero añadir dinámicamente todas esas propiedades durante la instanciación.
He intentado esto:
class PredefinedCars:
def init(self, cars):
for name, speed in cars.items():
setattr(self, name, Car(speed))
Esto crea los objetos según lo previsto:
predef_cars = PredefinedCars(dic)
predef_cars.bmw.speed
250
predef_cars.ferrari.speed
350
Sin embargo, cada vez que llamo a predef_cars.bmw, por ejemplo, se devuelve el mismo objeto:
predef_cars.ferrari
<main.car at=”” 0x1145cba30=””>
predef_cars.ferrari
<main.car at=”” 0x1145cba30=””>
Además, los atributos pueden ser reasignados, lo cual no es lo que quiero:
predef_cars.ferrari = 0
predef_cars.ferrari
0
Otra solución que intenté fue esta:
class PredefinedCars:
def init(self, cars):
for name, speed in cars.items():
setattr(PredefinedCars, name, property(lambda self: Car(speed)))
Esto soluciona ambos problemas anteriores, es decir, ahora en cada llamada se devuelve un nuevo objeto:
predef_cars = PredefinedCars(dic)
predef_cars.ferrari
<main.car at=”” 0x1145e76a0=””>
predef_cars.ferrari
<main.car at=”” 0x1145ea3d0=””>
y la propiedad no puede ser reasignada:
predef_cars.ferrari = 1
AttributeError: can’t set attribute
Sin embargo, ahora hay un nuevo problema, y es que todos los coches están siendo instanciados con el último valor de velocidad:
predef_cars.ferrari.speed
350
predef_cars.bmw.speed # Debería devolver 250, pero devuelve también 350:
350
“`
¿Cómo puedo solucionar esto?</main.car></main.car></main.car></main.car>
davy.ai
Puedes usar un cierre para capturar el valor de
speed
para cada coche durante la instanciación dePredefinedCars
, y luego usar ese valor en la función lambda dentro del métodoproperty
. Aquí tienes una implementación actualizada:En esta implementación, creamos una función lambda que toma el valor de
speed
y devuelve un nuevo objetoproperty
que crea un nuevo objetoCar
con esa velocidad cada vez que se llama. Llamamos inmediatamente esta función lambda con el valor despeed
para crear el objetoproperty
, y luego lo establecemos como un atributo de la clase usandosetattr
. Ten en cuenta que usamosself.__class__
en lugar dePredefinedCars
para establecer el atributo en el objeto de la clase en sí, en lugar de en las instancias de la clase.Con esta implementación, puedes crear un objeto
PredefinedCars
y obtener un nuevo objetoCar
cada vez que accedes a una propiedad:Y no puedes reasignar las propiedades: