Способ возврата другого типа класса при вызове класса заключается в переопределении метода __new__
, а не __init__
.Значение, возвращаемое __new__
, является значением, используемым в качестве экземпляра (в отличие от __init__
, которому даже не разрешено возвращать значение).Вы начали правильно, но попытка внутри __new__
создать экземпляр подкласса, вызвав его, просто повторно введет Monomial.__new__
- вы, вероятно, получите там ошибку рекурсии.
Итак, хотя Pythonпозволяет изменить тип возвращаемого значения __new__
, возможно, вам следует подумать о том, чтобы иметь фабричную функцию, независимую от любого класса, которая вместо этого будет возвращать экземпляр соответствующего класса.Иногда «чем проще, тем лучше».
В любом случае, код для фабричного подхода:
class Monomial(Function):
def __init__(self, coef: int, power: int, inner=Identity()):
super().__init__(inner)
self.pow = power
self.coef = coef
class Constant(Monomial):
def __init__(self, c: int):
super().__init__(self, coef=c, power=0)
...
def create_monomial(coef, power):
if power == 0:
return Constant(coef)
return Monomial(coef, power)
(create_monomial также может быть статическим или классовым методом, как вам кажется лучше)
И, есливы действительно думаете, что было бы лучше, способ распутать метод __new__
таков:
class Monomial(Function):
def __new__(cls, coef: int, power: int = 0, inner=Identity()):
if power == 0:
cls = Constant
return super().__new__(cls)
class Constant(Monomial):
def __init__(self, c: int, **kw):
super().__init__(c, 0)
Механизм создания Python будет вызывать __init__
, если возвращение __new__
является экземпляром self
- так что Monomial и Constant __init__
будут называться правильно.Вам просто нужно исправить __init__
константы, чтобы не нарушать параметр ocasional power = 0
, который он получит.
Исправление подписей потребовало бы значительно больше работы и, вероятно, потребовало бы использования метакласса для фактического проглатывания.в его __call__
методе неиспользованные power
до константы __init__
;
Также обратите внимание, что «реальное исправление» заключается в том, что вызов super().__new__
требует явной передачи класса - в отличие от других случаев использования super()
, где «self» или «cls» предоставляются Python.Это связано с тем, что __new__
на самом деле является статическим методом - к которому Python добавляет cls
при построении класса, но с помощью других механизмов, отличных от используемых "classmethods".