【问题标题】:Changing the base class of a class with __new__使用 __new__ 更改类的基类
【发布时间】:2012-04-27 20:27:08
【问题描述】:

我想在运行时使用 __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 实例。

添加
我的用例如下。

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') 在我的程序中很方便。

添加2
我这样做的原因如下。我必须编写的代码对我来说很复杂,因为我无法推断出正确的类设计。因此,无论如何我都可以对我的问题进行编码,因为我可以更好地理解它。但是,鉴于上述情况,我现在重构还为时过早。我还没有理解我的问题的某些组件之间的交互,在运行时更改基类将帮助我做到这一点。之后我会更适应重构。

【问题讨论】:

  • 你没有。您在创建类时命名正确的基础。
  • a PetBuyer 几乎肯定不是Pet 的一种,您通常可以通过在PetBuyer 上添加Pet 实例作为属性来组合这两种类型。 “奶奶有一只狗”而不是“奶奶是一只特殊的狗”
  • @TokenMacGuy 请参阅 ADDED2 了解我这样做的动机。
  • __new__ 是一个类方法,所以你应该调用它的参数cls 而不是self
  • @ChrisMorgan 谢谢。我不清楚何时使用 cls 和 self.我更正了我的帖子。

标签: python


【解决方案1】:

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

例如

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 类,它由(具有)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())

我也不明白为什么你需要更改 PetBuyer 的 class,IMO 设计不好

【讨论】:

  • 我添加了我的用例。我尝试了您的解决方案,但我无法更改您的代码以使我的用例正常工作。我无法将任何参数传递给元类 M。
  • 我选择了 TokenMacGuy 的帖子,因为它更多地回答了我的直接问题(请参阅下面的帖子)。但我会尽快根据您的帖子重构我的代码。谢谢。
【解决方案2】:

根据您的新信息,听起来您需要动态创建类型。您当然没有义务创建 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)

【讨论】:

  • 当我做type('new_type', Dog, dict)时,是否可以将PetBuyer的方法合并到dict中,这样就可以达到我想要的效果?
  • 添加到基类中即可,可以提供多个。:type('???', ((FooClass, BarClass) + tuple(other_classes), {})
  • 感谢您的帮助。请根据您的输入查看我在下面找到的解决方案。
【解决方案3】:

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)

打印出来

我是一只宠物。
我的物种是狗。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    • 1970-01-01
    • 2010-11-22
    • 2014-06-28
    • 1970-01-01
    • 2021-10-12
    • 1970-01-01
    相关资源
    最近更新 更多