Я вызываю конструктора в 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
Для этого вам понадобится __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
). Это еще один аргумент в пользу подхода фабричных функций.
Не пытайтесь извратить цель конструкторов: используйте фабричную функцию. Вызов конструктора для одного класса и возвращение экземпляра другого класса - верный способ вызвать путаницу.
Я бы посоветовал использовать для этого фабричный шаблон . Например:
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)