在Python中从基类对象创建对象

3 投票
4 回答
6318 浏览
提问于 2025-04-16 14:54

我有一个基础类:

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

AnimalStorePetStore 在不同的模块中。AnimalStore 是标准 Animal API 的一部分,并且不会改变。基本上,我想通过使用与动物相同的机制来获取宠物列表,从而扩展 Animal API,并且我希望能够利用 Animal API 已经为它的 AnimalAnimalStore 类提供的所有其他内置功能。

4 个回答

1

你可以这样做:

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

不过这两种方法可能都不是很规范,更像是临时解决办法,而不是一个干净利落的解决方案。

4

你可以为 Pet 类写一个 __init__() 方法,让它可以接受一个 Animal 的实例(或者说任何有必要属性的对象——这就是鸭子类型!)以及其他单独的属性。这样你就可以直接用 fluffy_as_pet = Pet(fluffy_as_animal) 来创建一个宠物了。或者你也可以提供一个类方法,比如 Pet.from_object(),来实现同样的功能,如果你不想让 __init__() 方法变得复杂。即使你不能控制 AnimalPet 这两个类,你也可以创建它们的子类,按照你的需求来实现。

不过,最好的做法是更进一步,干脆不要写那种只接受 Animal 而不接受 Pet 的代码。这样你就不需要进行转换了。再次强调,鸭子类型——只要一个对象有正确的属性,不管它是什么类型,你都可以使用它。

1

最后我选择使用了委托(应该感谢 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()

我只希望我实现得没问题;不管怎样,它是有效的!

撰写回答