有没有办法得到 "mutable" 分数? - python

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

有没有办法让"mutable"Fraction

我试过了,但 Fraction 中的 numerator/denominator 似乎是不可变的。

>>> 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

我一直这样做是因为我的 numerators/denominators 来自另一个 returns 分数生成器的函数。

>>> 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)

(注意我不是在加1/9 + 2/8 + 3/7 + 4/6,我是想把分子和除以分母之和)

有"mutable"分数吗?

numeratordenominator 是不可变的,原因有二:

  1. 其他 Python 数值类型是不可变的,包括同样由两个更简单的数值组成的复数,以及 arbitrary-width 数量,例如 longDecimal。可变分数是个例外。

  2. 能够单独改变分子和分母将有可能使分数无效,例如通过使其非规范化,或将分母设置为零。

换句话说,没有public API来变异fractions.Fraction对象。如果您确实需要单个分子和分母的总和,这听起来不是很有用,那么您的第二个代码片段是一种合理的方法。第一个片段的更精确的再现可能如下所示:

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))

有趣的想法,但它可以通过一些简单 糟糕的数学来解决:

>>> x = Fraction(0,1)
>>> numerators = [1,2,3,4,5]
>>> denominators = [9,8,7,6,5]
>>> for n,d in zip(numerators, denominators):
...     x += Fraction(n,x.denominator) # "Adding" to the numerator is adding a new fraction.
...     x = x/d # "adding" to the denominator is just dividing by the operand

你可以see this in practice here.


正如我在评论中暗示的那样,但 user4815162342 说得更清楚,Fractions 是不可变的,因为 分数 是不可变的,就像 Integers 是不可变,因为整数的概念本身就是不可变的。

7 是 7 是 'seven' 是 7,因此为不可变的想法创建可变对象是荒谬的。就像 3/4 是 0.75 是 'three-quarters',无论你如何构建它,想法都是一样的,所以让一个代表静态概念的对象是可变的是没有意义的。

真正有意义的是使用数学将它们修改为 3/4,分母现在是 8,这不是一回事。分数的加法、乘法或除法更直观。

CPython 3.9.2 非public API:

>>> 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
>>> print(x)
15/36

请注意,因为这是非public的方式,将来可以更改。

https://github.com/python/cpython/blob/master/Lib/fractions.py