sanyassh
sanyassh

Reputation: 8540

"We're immutable, so use __new__ not __init__"

I found this phrase in module fraction.py of standard library:

class Fraction(numbers.Rational):
    ...

    # We're immutable, so use __new__ not __init__
    def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
        """Constructs a Rational.
        ...

I am confused with it because Fraction instance, strictly speaking, is not immutable:

import fractions

fraction = fractions.Fraction(3, 2)
fraction._numerator = 1  # it works
print(fraction)  # 1/2

So, I'm asking for more clarification why __new__ is used instead of __init__ and what does this phrase mean here.

Upvotes: 2

Views: 112

Answers (1)

user2357112
user2357112

Reputation: 281748

It's logically immutable, not enforced. It's basically impossible to really enforce immutability in Python. Crazier enforcement attempts can always be met with crazier bypasses. For example, there's a bit of "enforcement" in that numerator and denominator are properties with no setter, but you've already found the bypass for that.

If you really want to screw with a Fraction object, you can, and you can do a lot worse than setting _numerator, but you're asking for problems.

Upvotes: 2

Related Questions