В качестве учебного упражнения я пытаюсь реализовать класс, который будет эмулировать поведение встроенного комплекса
Python, но с другим поведение методов __str__
и __repr__
: я хочу, чтобы они печатались в формате...
(1.0,2.0)
...вместо:
(1+2j)
Сначала я попытался просто создать подкласс из complex
и переопределение __str__
и __repr__
, но это имеет проблему, заключающуюся в том, что при вызове непереопределенных методов возвращается стандартный комплекс
, и печатается в стандартном формате:
>>> a = ComplexWrapper(1.0,1.0)
>>> a
(1.0,1.0)
>>> b = ComplexWrapper(2.0,3.0)
>>> b
(2.0,3.0)
>>> a + b
(3+4j)
Когда желаемый вывод (3.0,4.0)
.
Я читал о метаклассах и думал, что они решат мою проблему.Начиная с ответа в Python Class Decorator, моя текущая реализация выглядит следующим образом:
def complex_str(z):
return '(' + str(z.real) + ',' + str(z.imag) + ')'
def complex_repr(z):
return '(' + repr(z.real) + ',' + repr(z.imag) + ')'
class CmplxMeta(type):
def __new__(cls, name, bases, attrs):
attrs['__str__'] = complex_str
attrs['__repr__'] = complex_repr
return super(CmplxMeta, cls).__new__(cls, name, bases, attrs)
class ComplexWrapper(complex):
__metaclass__ = CmplxMeta
К сожалению, это похоже на то же поведение, что и предыдущее решение (например, когда два экземпляра ComplexWrapper
добавляются друг к другу).
Признаюсь, я не совсем понимаю метаклассы. Может быть, мою проблему можно решить по-другому?
Конечно, я мог бы вручную переопределить соответствующие методы, такие как __add__
, __subtract__
и т. д. Но это было бы очень повторяющимся, поэтому я бы предпочел более элегантное решение.
Любая помощь приветствуется.
Итак, ряд вещей, которые я не понимаю в вашем коде:
Где метод __new__
метода ReturnTypeWrapper
метакласс получает свои аргументы? Если они передаются автоматически, я бы ожидал, что в этом случае name = "Complex", bases = (complex), dict = {}
. Это правильно? Является ли этот метод автоматической передачи данных класса специфичным для метаклассов?
Почему вы используете
cls = type.__new__(mcs, name, bases, dct)
вместо
cls = type(mcs, name, bases, dct)
?
Это просто для того, чтобы избежать путаницы с «другим значением» type()
?
Я скопировал ваш код и добавил свои специальные реализации __str__
и __repr__
в ваш класс ComplexWrapper
. Но это не работает; печать любого объекта типа Complex
просто печатается в стандартном формате Python.Я этого не понимаю, так как два метода должны были быть выбраны в цикле for метакласса, но впоследствии должны были быть переопределены моими определениями.
Соответствующий раздел моего кода:
class Complex(complex):
__metaclass__ = ReturnTypeWrapper
wrapped_base = complex
def __str__(self):
return '(' + str(self.real) + ',' + str(self.imag) + ')'
def __repr__(self):
return '(' + repr(self.real) + ',' + repr(self.imag) + ')'
И его поведение:
>>> type(a)
>>> a.__str__
>>> a.__str__()
'(1+1j)'
>>>
Еще раз спасибо за ваш ответ и не стесняйтесь редактировать/удалять приведенное выше, если вы решите их в своем ответе!