__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)
Другие вопросы по тегам