使用__new__更改类的基类

时间:2012-04-27 20:27:09

标签: python

我想在运行时使用__new__更改类的基类。 我尽可能地努力,但我无法理解。

class A(object): pass

class B(object): pass

class C(B): 

    some_attribute_in_c='hello'

    def __new__(cls):
        cls.__bases=(A,) #some code here to change the base class
        return super(C,cls).__new__(A)

x=C()
x.some_attribute_in_c #return Error: x has no attribute 'some_attribute_in_c'

放入__new __()的正确代码是什么,以便最后一行返回'hello',x是基类A的C实例。

ADDED
我的用例如下。

class Pet(object):
    some_attribute_in_pet='I\'m a pet.'

class Dog(Pet):
    some_attribute_in_species='My species is dog.'

class Cat(Pet):
    some_attribute_in_species='My species is cat.'

class PetBuyer(Pet):

    def __new__(cls,desired_animal):
        animal_bought=globals[desired_animal]
        cls.__bases=(animal_bought,) #some code here to change the base class
        return super(PetBuyer,cls).__new__(animal_bought)

    def __init__(self,desired_animal):
        print self.some_attribute_in_pet
        print self.some_attribute_in_species

x = PetBuyer('Dog')

我想打印最后一行。

  

我是宠物   我的物种是狗。

我的目标是在PetBuyer中使用__new __(),就像动物类的工厂一样。 我这样做的原因是语法PetBuyer('Dog')在我的程序中很方便。

ADDED2
我这样做的原因如下。对于我而言,我所需要的代码很复杂,因为根据看,我无法推断出正确的类设计。因此,无论如何,我都会使用代码来解决问题,因为我可以更好地理解它。但是,由于上面出现的情况,对我来说重构还为时过早。我还没有理解我的问题的一些组件之间的交互,并在运行时更改基类将帮助我做到这一点。之后我会更适合重构。

3 个答案:

答案 0 :(得分:3)

当你覆盖__new__该类已经存在时,无论如何__new__用于创建给定类的实例,您可以通过metaclass完成所需的操作。可以像工厂一样表现

e.g。

class A(object): pass

class B(object): pass

class M(type):
    def __new__(cls, clsname, bases, attribs):
        # change bases
        bases = (A,)
        return type(clsname, bases, attribs)

class C(B): 
    __metaclass__ = M    
    some_attribute_in_c='hello'

print C.__bases__
x = C()
print isinstance(x, A)
print x.some_attribute_in_c

输出:

(<class '__main__.A'>,)
True
hello

在看到OP的编辑后,我会说忘记以上所有,你不需要任何元类,只需要一个简单的PetBuyer类,它由(has a){{组成1}},所以问题是为什么你不能把宠物传递给PetBuyer,例如

Pet

我也不明白为什么你需要改变PetBuyer的class Pet(object): some_attribute_in_pet='I\'m a pet.' class Dog(Pet): some_attribute_in_species='My species is dog.' class Cat(Pet): some_attribute_in_species='My species is cat.' class PetBuyer(Pet): def __init__(self, pet): self.pet = pet print self.pet.some_attribute_in_pet print self.pet.some_attribute_in_species x = PetBuyer(Dog()) ,是不好的设计IMO

答案 1 :(得分:1)

根据您的新信息,您需要动态创建类型。您当然没有义务创建class套件来描述这些类型,您可以通过直接调用type函数在运行时创建它们:

def make_thingy(bases):
    new_thingy_class = type("???", bases, {})
    new_thingy_instance = new_thingy_class()
    print new_thingy_instance.some_attribute_in_pet
    print new_thingy_instance.some_attribute_in_species
    return new_thingy_instance

x = new_thingy(Dog)

答案 2 :(得分:0)

由TokenMacGuy提供并由delnan暗示的我的问题的直接答案是

class Pet(object):
    pet_attribute='I\'m a pet.'

class Dog(Pet):
    species_attribute='My species is dog.'

class Cat(Pet):
    species_attribute='My species is cat.'

class NewThingy(object):

    def __new__(cls,desired_base):
        x = type(desired_base.__name__+'NewThingy',
                 (NewThingy,desired_base),{})
        return super(NewThingy,cls).__new__(x,cls)

    def __init__(self,desired_base):
        print self.pet_attribute
        print self.species_attribute

x = NewThingy(Dog)

打印

  

我是宠物   我的物种是狗。