Search code examples
pythongeneratormutablefractions

Is there a way to have "mutable" Fractions? - python


Is there a way to have a "mutable" Fraction?

I've tried this but seem like the numerator/denominator in Fraction is not mutable.

>>> from fractions import Fraction
>>> x = Fraction(0,1)
>>> numerators = [1,2,3,4,5]
>>> denominators = [9,8,7,6,5]
>>> for n,d in zip(numerators, denominators):
...     x.numerator+= n
...     x.denominator+= d
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: can't set attribute

I've been doing it as such because my numerators/denominators are from another function that returns a generator of Fractions.

>>> inputs = [Fraction(1,9), Fraction(2,8), Fraction(3,7), Fraction(4,6)]
>>> numerators, denominators = zip(*[(f.numerator, f.denominator) for f in inputs])
>>> x = Fraction(sum(numerators), sum(denominators))
>>> x
Fraction(7, 23)

(Note that I'm not adding 1/9 + 2/8 + 3/7 + 4/6, I'm trying to sum the numerators and divide by the sum of the denominators)

Is there a "mutable" Fraction?


Solution

  • The numerator and denominator are immutable for two reasons:

    1. Other Python numeric types are immutable, including complex numbers which also consist of two simpler numeric values, and arbitrary-width quantities such as long and Decimal. Mutable fractions would be an exception.

    2. Being able to individually mutate the numerator and the denominator would have the potential to invalidate the fraction, e.g. by making it denormalized, or by setting the denominator to zero.

    In other words, there is no public API to mutate a fractions.Fraction object. If you really need a sum of individual numerators and denominators, which doesn't sound very useful, your second code snippet is a reasonable way to do it. A more exact rendition of the first snippet could look like this:

    x = Fraction(sum(f.numerator for f in inputs),
                 # add 1 since we start out with 0/1
                 1 + sum(f.denominator for f in inputs))