2012-04-27 7 views
0

Я хотел бы изменить базовый класс класса во время выполнения с помощью __new__. Я выглядел так сильно, как только мог, но я не мог понять.Изменение базового класса класса с помощью __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 __(), так что последняя строка возврат «привет» и х является экземпляром 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') 

Мне нужна последняя строка для печати.

Я домашнее животное.
Мои виды - собака.

Моя цель - использовать __new __() в PetBuyer как завод для класса животных. Моя причина для этого заключается в том, что синтаксис PetBuyer («Собака») удобен в моей программе.

ADDED2
Моя причина для этого заключается в следующем. То, что я должен кодировать, является сложным для меня в том смысле, что, видите ли, я не могу вывести правильный дизайн класса. Поэтому я прибегаю к коду моей проблемы в любом случае, я могу рефакторировать, поскольку я лучше понимаю это. Однако с ситуацией, которая возникает выше, мне будет слишком рано рефакторировать. Мне еще предстоит понять взаимодействие между некоторыми компонентами моей проблемы, и изменение базового класса во время выполнения поможет мне это сделать. После этого я буду более удобен для рефакторинга.

+1

У вас нет. Вы указываете правильные основания на момент создания класса. – delnan

+0

'PetBuyer' почти наверняка не является своего рода« любимым », вы обычно составляете два типа, добавляя экземпляры' Pet' в качестве атрибутов в 'PetBuyer'. «Бабушка * имеет * собаку», а не «Бабушка * - это особый вид собаки» – SingleNegationElimination

+0

@TokenMacGuy Пожалуйста, см. ADDED2 для моей мотивации для этого. –

ответ

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) 
+0

Когда я делаю 'type ('new_type', Dog, dict)' можно ли объединить метод 'PetBuyer' в' dict', чтобы я мог иметь эффект, который я хочу? –

+1

Просто добавьте его в базовые классы, вы можете указать более одного: 'type ('???', ((FooClass, BarClass) + tuple (other_classes), {})' – SingleNegationElimination

+0

Благодарим за помощь. см. решение, которое я нашел ниже, с вашим вводом. –

3

При переопределении __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 класс, который состоит из (имеет a) 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()) 

Я также не понимаю, почему вы должны изменить class из PetBuyer, плохой дизайн IMO

+0

Я добавил свой прецедент. Я попробовал ваше решение, но я не мог изменить свой код, чтобы сделать работу по моему делу. Я не мог передать какие-либо аргументы в метаклассе M. –

+0

Я выбрал пост TokenMacGuy, так как он отвечает на мой ближайший вопрос (см. Мой пост ниже). Но как только смогу, я реорганизую свой код за ваш пост. Спасибо. –

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) 

печатается

Я животное.
Мои виды - собака.

Смежные вопросы