On Wed, Apr 29, 2015 at 1:03 PM, Peter Otten <__pete...@web.de> wrote: > I was judging from the look of your MovingAverage. > > I don't like the interface, it really should take an iterable so that you > can write > >>>> list(moving_average([1,2,3], 2)) > [1.5, 2.5]
The problem with this is that many use cases for moving averages need to access the current average before future items become available. For example, a download speed indicator: it needs to average the transfer rate over the last few seconds. There will be more transfer rate data in the future, but it's not available yet, so you can't add it to the iterable unless the iterable is actually some sort of read/write buffer that can be appended to once iteration has already started. That seems overly complex, though; for one, you need to be careful not to exhaust the buffer, since the iteration protocol requires that once next() raises StopIteration, it will always raise StopIteration. But also, why add the data to object A so that it can be consumed by object B if you could just add it to object B directly? So I think the iterable interface that you're describing really needs to be a coroutine of some sort: >>> from collections import deque >>> def moving_average(length): ... values = deque([(yield)], maxlen=length) ... while True: ... values.append((yield sum(values) / len(values))) ... >>> mavg = moving_average(5) >>> next(mavg) >>> mavg.send(1) 1.0 >>> mavg.send(2) 1.5 >>> mavg.send(3) 2.0 >>> mavg.send(4) 2.5 >>> mavg.send(5) 3.0 >>> mavg.send(6) 4.0 >>> mavg.send(7) 5.0 This works, but I don't really like it. For one, our moving_average "iterable" isn't really an iterable any more; we need to call send instead of next, which means we can't just stick it inside a for loop. And if we can't iterate over it, then what's the point of using a generator? If we make it a class, then we can give it a more flexible API. class MovingAverage(object): def __init__(self, length): self.values = deque(maxlen=length) def append(self, value): self.values.append(value) def average(self): return sum(self.values) / len(self.values) Which is pretty much back to where we started. -- https://mail.python.org/mailman/listinfo/python-list