有没有办法得到 "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"分数吗?
numerator
和 denominator
是不可变的,原因有二:
其他 Python 数值类型是不可变的,包括同样由两个更简单的数值组成的复数,以及 arbitrary-width 数量,例如 long
和 Decimal
。可变分数是个例外。
能够单独改变分子和分母将有可能使分数无效,例如通过使其非规范化,或将分母设置为零。
换句话说,没有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
正如我在评论中暗示的那样,但 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
有没有办法让"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"分数吗?
numerator
和 denominator
是不可变的,原因有二:
其他 Python 数值类型是不可变的,包括同样由两个更简单的数值组成的复数,以及 arbitrary-width 数量,例如
long
和Decimal
。可变分数是个例外。能够单独改变分子和分母将有可能使分数无效,例如通过使其非规范化,或将分母设置为零。
换句话说,没有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
正如我在评论中暗示的那样,但 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