在Python中从基类对象创建对象
我有一个基础类:
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)
还有一个从它扩展出来的类:
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()
假设我有一个 Animal
对象,是这样创建的:
>>> fluffy_as_animal = Animal('dog', 'kibbles')
有没有简单的方法可以在 Python 中从 fluffy_as_animal
创建一个 Pet
对象,而不需要实际写出:
>>>> fluffy_as_pet = Pet(fluffy_as_animal.name, fluffy_as_animal.food)
更新
我这样做的原因是我有一个类,它有一个函数可以返回一组 Animal
类型的对象,而我希望这些对象实际上能作为 Pet
对象使用:
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
和 PetStore
在不同的模块中。AnimalStore
是标准 Animal
API 的一部分,并且不会改变。基本上,我想通过使用与动物相同的机制来获取宠物列表,从而扩展 Animal
API,并且我希望能够利用 Animal
API 已经为它的 Animal
和 AnimalStore
类提供的所有其他内置功能。
4 个回答
你可以这样做:
fluffy_as_pet = object.__new__(Pet)
fluffy_as_pet.__dict__ = fluffy_as_animal.__dict__.copy()
或者这样:
from copy import copy
fluffy_as_pet = copy(fluffy_as_animal)
fluffy_as_pet.__class__ = Pet
不过这两种方法可能都不是很规范,更像是临时解决办法,而不是一个干净利落的解决方案。
你可以为 Pet
类写一个 __init__()
方法,让它可以接受一个 Animal
的实例(或者说任何有必要属性的对象——这就是鸭子类型!)以及其他单独的属性。这样你就可以直接用 fluffy_as_pet = Pet(fluffy_as_animal)
来创建一个宠物了。或者你也可以提供一个类方法,比如 Pet.from_object()
,来实现同样的功能,如果你不想让 __init__()
方法变得复杂。即使你不能控制 Animal
和 Pet
这两个类,你也可以创建它们的子类,按照你的需求来实现。
不过,最好的做法是更进一步,干脆不要写那种只接受 Animal
而不接受 Pet
的代码。这样你就不需要进行转换了。再次强调,鸭子类型——只要一个对象有正确的属性,不管它是什么类型,你都可以使用它。
最后我选择使用了委托(应该感谢 S.Lott):
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)
class Pet(object):
def __init__(self, animal=None):
self.animal = animal
def __getattr__(self, key):
return getattr(self.animal, key)
def __setattr__(self, key, value):
return setattr(self.animal, key, value)
def eat(self):
return self.animal.eat()
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()
我只希望我实现得没问题;不管怎样,它是有效的!