Как заменить экземпляр в __ init __ () с другим объектом?

Я вызываю конструктора в ClassA и хочу иметь полученный объект быть другого класса (ClassB), если определенное условие соблюдено. Я попытался заменить первый аргумент __ init __ () ('сам' в примере ниже) в __ init __ (), но это, кажется, не делает то, что я хочу.

в основном:

import ClassA

my_obj = ClassA.ClassA(500)
# unfortunately, my_obj is a ClassA, but I want a ClassB!

в ClassA / __ init __. py:

import ClassB

class ClassA:
    def __init__(self,theirnumber):
        if(theirnumber > 10):
            # all big numbers should be ClassB objects:
            self = ClassB.ClassB(theirnumber)
            return
        else:
            # numbers under 10 are ok in ClassA.
            return

в ClassB / __ init __. py:

class ClassB:
    pass
17
задан sneak 9 July 2010 в 01:25
поделиться

3 ответа

Для этого вам понадобится __new__(). (И вам также нужно сделать его классом нового стиля, если вы используете Python 2, путем подклассификации object.)

class ClassA(object):
    def __new__(cls,theirnumber):
        if theirnumber > 10:
            # all big numbers should be ClassB objects:
            return ClassB.ClassB(theirnumber)
        else:
            # numbers under 10 are ok in ClassA.
            return super(ClassA, cls).__new__(cls, theirnumber)

__new__() выполняется как часть процесса инстанцирования класса перед __init__(). В основном __new__() - это то, что фактически создает новый экземпляр, а __init__() затем вызывается для инициализации его свойств. Вот почему вы можете использовать __new__(), но не __init__() для изменения типа создаваемого объекта: как только запускается __init__(), объект уже создан, и менять его тип слишком поздно. (Ну... не совсем так, но это относится к очень заумной черной магии Python.) См. документацию.

В этом случае, однако, я бы сказал, что больше подходит фабричная функция, что-то вроде

def thingy(theirnumber):
    if theirnumber > 10:
        return ClassB.ClassB(theirnumber)
    else:
        return ClassA.ClassA(theirnumber)

Кстати, обратите внимание, что если вы сделаете то, что я сделал с __new__() выше, если будет возвращен ClassB, метод __init__() экземпляра ClassB не будет вызван! Python вызывает __init__() только если объект, возвращенный из __new__(), является экземпляром класса, в котором содержится метод __new__() (здесь ClassA). Это еще один аргумент в пользу подхода фабричных функций.

33
ответ дан 30 November 2019 в 10:18
поделиться

Не пытайтесь извратить цель конструкторов: используйте фабричную функцию. Вызов конструктора для одного класса и возвращение экземпляра другого класса - верный способ вызвать путаницу.

12
ответ дан 30 November 2019 в 10:18
поделиться

Я бы посоветовал использовать для этого фабричный шаблон . Например:

def get_my_inst(the_number):
   if the_number > 10:
       return ClassB(the_number)
   else:
       return ClassA(the_number)

class_b_inst = get_my_inst(500)
class_a_inst = get_my_inst(5)
15
ответ дан 30 November 2019 в 10:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: