今天,带大家做一个浮点数生成器,主要用到的知识点有:
1.实现自定义类的__iter__()和__reversed()__方法
2.Decimal对于十进制数据的精度控制
我们知道,通过实现一个自定义类的__iter__()魔法方法,我们可以自定义一个可迭代对象。那么,需求来了,我们能否实现一个类似range(start, end, step)函数的浮点数生成器。
思路是这样的:自定义一个类,添加其属性start、end、step,分别表示浮点数起始值、结束值、步长值。然后,实现其内置魔法方法__iter__(),每次调用时检查返回的数据是否小于结束值,如果小于,则增加步长后返回一个浮点数;下一次将该数值增加步长后返回即可;同理,返回逆序浮点数时,判断是否大于起始值,如果大于,则减少步长后返回一个浮点数。
Python是这样实现的。
class FloatRange:
def __init__(self, start=0.0, end=1.0, step=0.1):
self.start = start
self.end = end
self.step = step
def __iter__(self):
t = self.start
while t <= self.end:
yield t
t += self.step
def __reversed__(self):
t = self.end
while t >= self.start:
yield t
t -= self.step
这里我们使用了yield将该方法变成了一个生成器,每次调用只返回一个符合要求的浮点数。这样,当我们生成大量数据时,可以优化性能。
现在,我们自定义一个浮点数生成器看下效果。
for f in FloatRange():print(f, end='\t')
这样就会生成一个默认0.0开始,1.0结束,步长为0.1的浮点数序列。但是,我们得到的序列是这样的:
0.0 0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7 0.7999999999999999 0.8999999999999999 0.9999999999999999
是不是大大出乎我们的意料?编译器在进行输出时,暴露出浮点数的一个普遍问题,就是它们并不能精确表示一个十进制数。这跟Python中浮点数的内部实现机制有关。浮点数在表示时即使是一个最简单的十进制浮点数也不能将其精确表示,数学运算也会产生小的误差。这里,我们给出一个解决方案,使用一个用于十进制数学计算decimal模块可以解决该问题。
from decimal import Decimal
class FloatRange:
def __init__(self, start=0.0, end=1.0, step=0.1):
self.start = start
self.end = end
self.step = step
def __iter__(self):
t = Decimal(str(self.start))
while t <= Decimal(str(self.end)):
yield Decimal(t)
t = Decimal(t) + Decimal(str(self.step))
def __reversed__(self):
t = Decimal(self.end)
while t >= Decimal(self.start):
yield Decimal(t)
t = Decimal(t) + Decimal(self.step)
使用decimal将浮点数更加精确的打印出来,从而实现了一个浮点数生成器。Decimal类对于使用Python进行金融计算是一个很有用的模块,感兴趣的朋友们可以了解一下,这里就不再赘述了。
好了,今天的内容就到这里了,本篇主要讲解了Python制作浮点数生成器的过程,并从中引出了解决浮点数不精确展示的办法。欢迎大家留言讨论,持续关注,后续会推出一些更加精彩实战内容。