2013-08-13 2 views
2

У меня есть родительский класс и два подкласса child1 (parent) и child2 (parent) вроде следующего кода. (отредактировано более правильно показать, что родительский класс делает что-то)Как вернуть подкласс из параметра __new__

class parent(object): 
    name = None 

    def __init__(self,e): 
    # process the common attributes 
    name = e.attrib['name'] 

    def __new__(cls,e): 
    if e.attrib['type'] == 'c1': 
     return child1(e) 
    elif e.attrib['type'] == 'c2': 
     return child2(e) 
    else: 
     raise 

class child1(parent): 
    extra1 = None 
    def __init__(self,e): 
    super(e) 
    # set attributes from e that are specific to type c1 

class child2(parent): 
    extra2 = None 
    def __init__(self,e): 
    super(e) 
    # set attributes from e that are specific to type c2 

Цель состоит в том, чтобы иметь возможность получить класс «правильного» на основе значения параметра. Поэтому, если я могу сказать, obj = parent(element) и obj будет либо child1, либо child2 в зависимости от того, что такое значение element.attrib['type'].

+0

И какая у вас проблема? – kindall

+0

Что означает 'super (e)'? Вы хотите 'super (child1, self) .__ init __ (e)' или что-то другое? (И если вы _did_ хотите, чтобы ... вам понадобится 'parent .__ init__', который принимает этот аргумент' e' ...) – abarnert

+0

Да, должен был быть 'parent .__ init__', чтобы принять аргумент e. – ctjctj2

ответ

3

Проблема заключается в том, что внутри parent.__new__, вы звоните child1(e), в то время как звонки child1.__new__, который находит реализацию в parent.__new__ и называет его с той же e, который вызывает child1(e), который ... так что вы получите бесконечную рекурсию.

Есть более эффективные способы проектируют, но если вы просто хотите, чтобы исправить ваш дизайн, есть три варианта:


Если определить __new__ во всех ваших подклассов, он не сорвется parent.__new__. Вы можете сделать это за один шаг, помещая класс intermediate между parent и childN, поэтому вам нужно только intermediate.__new__. Или используйте смесь, которую они все наследуют, или ...


Избавьтесь от наследства. Есть ли действительно какая-то причина child1 is-a parent здесь?

Вы, кажется, ищете то, что в терминах Smalltalk/ObjC называется кластером классов, и вам не нужно, чтобы «видимое лицо» кластера было базовым классом в Python, чем вы на этих языках.

Например:

class base(object): 
    pass 

class parent(base): 
    def __new__(cls, e): 
     # same as before 

class child1(base): 
    # etc. 

В Python, вы можете даже сделать parent БАТ и register каждый childN с ним, так что вы можете использовать isinstance и друзей с ним.


Наконец, вы можете просто поймать рекурсию лишь обработку __new__ на parent, а не его подклассы:

def __new__(cls, e): 
    if cls is not parent: 
     return super(parent, cls).__new__(cls) 
3

Это намного проще, если вы не имеете parent быть класс на всех , а просто нормальная функция.

Использование базового класса - это образец из языков, где это единственный реальный способ сделать это. Это не обязательно или полезно в Python.

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