__new__ в модуле дробей
Я пытался понять __new__
и метапрограммирование. Итак, я взглянул на официальный исходный код Python.
http://hg.python.org/cpython/file/2.7/Lib/fractions.py
Их __new__
Функция для дроби выглядит так:
class Fraction(Rational):
def __new__(cls, numerator=0, denominator=None):
"""Constructs a Fraction. ... """
self = super(Fraction, cls).__new__(cls)
...
if isinstance(numerator, float):
# Exact conversion from float
value = Fraction.from_float(numerator)
self._numerator = value._numerator
self._denominator = value._denominator
return self
@classmethod
def from_float(cls, f):
"""Converts a finite float to a rational number, exactly. ..."""
# ...
return cls(*f.as_integer_ratio())
Почему они return self
, скорее, чем
return Fraction.from_float(numerator)
Я думал, что понял это, но теперь я в замешательстве.
(Редактировать)
Для поддержки подклассов, будет ли иметь какое-либо значение изменить на
return cls.from_float(numerator)
1 ответ
Код во фракциях был сложным местом для начала. Лучше всего строить понимание шаг за шагом.
1) объект.__ new__ является корневым инструментом для создания экземпляров классов нового стиля:
o = object()
2) Класс, который определяет __new__, обычно вызывает объект.__ new__ для выполнения своей работы:
class A(object):
def __new__(cls):
return object.__new__(cls)
a = A()
3) Метод класса обычно использует класс __new__ для выполнения своей работы:
class A(object):
def __new__(cls):
return object.__new__(cls)
@classmethod
def from_something(cls):
return cls.__new__()
Имея это понимание, вы можете увидеть, что делает модуль фракций:
1) вызовы from_float() cls(numerator, denominator)
делегировать создание экземпляра методу Fraction.__new__().
2) Метод Fraction.__new__() использует super() для вызова объекта.__ new __ () для фактического создания экземпляра.
Addenda
@Blckknght хочет знать, почему value
не возвращается напрямую (после создания его числитель и демонинатор копируются в self
перед value
это одноразовый Ответ в том, что Fraction.from_float
создает экземпляр Fraction, а не cls. Другими словами, код обеспечивает поддержку для подклассов:
>>> from fractions import Fraction
>>> class MyFraction(Fraction):
pass
>>> f = MyFraction(2, 3)
>>> f
Fraction(2, 3)
>>> f.__class__ # this MUST be MyFraction, not a Fraction
<class '__main__.MyFraction'>
редактировать
@richard хочет знать "почему бы не использовать: вернуть cls.from_float (числитель)"?
Это называется принцип Открыто-Закрыто. Подклассер должен иметь возможность переопределять from_float() без непреднамеренного прерывания __init __ ():
>>> class MyFraction(Fraction):
def from_float(cls, *args):
raise NotImplemented
>>> f = MyFraction(5.75)
>>> f
Fraction(23, 4)