I have a base class:
class Animal(object):
def __init__(self, name=None, food=None):
self.name = name
self.food = food
def eat(self):
print "The %s eats some %s" % (self.name, self.food)
And a class that extends it:
class Pet(Animal):
def pet(self):
print "You pet the %s." % self.name
def feed(self):
print "You put some %s into the bowl." % self.food
self.eat()
Let's say I have an Animal object, created thusly:
>>> fluffy_as_animal = Animal('dog', 'kibbles')
Is there a straightforward way in python to create a Pet object from fluffy_as_animal, short of actually writing out:
>>>> fluffy_as_pet = Pet(fluffy_as_animal.name, fluffy_as_animal.food)
The reason I'm doing this implementation is that I have a class with a function that returns a set of objects of type Animal all which I want to actually use as Pet objects:
class AnimalStore(object):
def fetch(count, query=None, server=None, *args, **kwargs):
connection = connect_to_server(server)
resp = connection.fetch_animals(query)
objects = parse_response(resp)
animals = []
for a in objects[:count]:
animals.append(Animal(a['name'], a.['food']))
return animals
class PetStore(AnimalStore):
def fetch(count, query=None, server=None, *args, **kwargs):
query = 'type=pet AND %s' % query
animals = super(PetFactory, self).fetch(count, query, server, *args, **kwargs)
pets = []
for animal in animals:
pets.append(magic_function(animal))
return pets
AnimalStore and PetStore are in separate modules. AnimalStore is part of a standard Animal API and doesn't change. Basically I want to extend the Animal API by fetching a list of pets using the same mechanism used for animals, and I want to be able to take advantage of all of the other built-in functions that the Animal API already provides for its Animal and AnimalStore classes.
You can write the __init__() for Pet to accept an instance of Animal (or really, any ojbect with the necessary attributes -- duck typing!) as well as the individual attributes. Then you could just do fluffy_as_pet = Pet(fluffy_as_animal). Or provide a class method (e.g. Pet.from_object()) to do the same, if you don't want to overload __init__(). Even if you don't control the Animal and Pet classes, you could make your own subclasses of them that behave as you need.
However, it would be best to go a step further and simply don't write code that accepts Animal but not Pet. Then you don't have to convert it. Again, duck typing -- if an object has the right attributes, you can use it regardless of its type.
You could do
fluffy_as_pet = object.__new__(Pet)
fluffy_as_pet.__dict__ = fluffy_as_animal.__dict__.copy()
or
from copy import copy
fluffy_as_pet = copy(fluffy_as_animal)
fluffy_as_pet.__class__ = Pet
but both those ways are probably more of a hack than a clean solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With