Using iterators to write in the structure being iterated through?

Peter Otten __peter__ at web.de
Wed Jul 26 12:54:39 EDT 2006


Pierre Thibault wrote:

> Hello!
> 
> I am currently trying to port a C++ code to python, and I think I am stuck
> because of the very different behavior of STL iterators vs python
> iterators. What I need to do is a simple arithmetic operations on objects
> I don't know. In C++, the method doing that was a template, and all that
> was required is that the template class has an iterator conforming to the
> STL forward iterator definition. Then, the class would look like:
> 
> template <class H>
> class MyClass
> {
> public:
> 
> MyClass(H& o1, H& o2) : object1(o1), object2(o2) {}
> 
> void compute();
> 
> private:
> H& object1;
> H& object2;
> 
> };
> 
> template <class H>
> void MyClass::compute()
> {
> typedef typename H::iterator I;
> 
> I o1_begin = object1.begin();
> I o2_begin = object2.begin();
>         I o1_end = object1.end();
> 
> for(I io1 = o1_begin, io2 = o2_begin; io1 != o1_end; ++io1, ++io2)
>  {
> // Do something with *io1 and *io2, for instance:
> // *io1 += *io2;
> }
> }
> 
> This is all nice: any object having a forward iterator works in there.
> 
> Then I discovered python and wanted to use all its goodies. I thought it
> would be easy to do the same thing but I can't: the iterator mechanism is
> read-only, right? So it does no make sense to write:
> 
> io1 = iter(object1)
> io2 = iter(object2)
> 
> try:
>   while 1:
>     io1.next() += io2.next()
> except StopIteration:
>   pass
> 
> That won't work:
> SyntaxError: can't assign to function call
> 
> Here is my question: how could I do that and retain enough generallity?

You need a temporary variable (out in the example below):

>>> accus = [[] for i in range(3)]
>>> ins = ("abc" for i in range(3))
>>> outs = iter(accus)
>>> while 1:
...     out = outs.next()
...     out += ins.next()
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
StopIteration

In idiomatic Python that becomes

>>> accus = [[] for i in range(3)]
>>> ins = ("abc" for i in range(3))
>>> outs = iter(accus)
>>> from itertools import izip
>>> for out, in_ in izip(outs, ins):
...     out += in_
...
>>> accus
[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]


Peter




More information about the Python-list mailing list