Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #64725 > unrolled thread

should I transfer 'iterators' between functions?

Started byseaspeak@gmail.com
First post2014-01-24 22:37 -0800
Last post2014-01-25 14:32 +0100
Articles 6 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  should I transfer 'iterators' between functions? seaspeak@gmail.com - 2014-01-24 22:37 -0800
    Re: should I transfer 'iterators' between functions? Chris Angelico <rosuav@gmail.com> - 2014-01-25 17:43 +1100
    Re: should I transfer 'iterators' between functions? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-01-25 06:45 +0000
    Re: should I transfer 'iterators' between functions? Ned Batchelder <ned@nedbatchelder.com> - 2014-01-25 07:55 -0500
    Re: should I transfer 'iterators' between functions? Ned Batchelder <ned@nedbatchelder.com> - 2014-01-25 07:56 -0500
    Re: should I transfer 'iterators' between functions? Peter Otten <__peter__@web.de> - 2014-01-25 14:32 +0100

#64725 — should I transfer 'iterators' between functions?

Fromseaspeak@gmail.com
Date2014-01-24 22:37 -0800
Subjectshould I transfer 'iterators' between functions?
Message-ID<6ad4232c-a8d9-4195-9edd-65c0e35923a7@googlegroups.com>
take the following as an example, which could work well.
But my concern is, will list 'l' be deconstructed after function return? and then iterator point to nowhere?

def test():
    l = [1, 2, 3, 4, 5, 6, 7, 8]
    return iter(l)
def main():
    for i in test():
        print(i)
   

[toc] | [next] | [standalone]


#64726

FromChris Angelico <rosuav@gmail.com>
Date2014-01-25 17:43 +1100
Message-ID<mailman.5967.1390632242.18130.python-list@python.org>
In reply to#64725
On Sat, Jan 25, 2014 at 5:37 PM,  <seaspeak@gmail.com> wrote:
> take the following as an example, which could work well.
> But my concern is, will list 'l' be deconstructed after function return? and then iterator point to nowhere?
>
> def test():
>     l = [1, 2, 3, 4, 5, 6, 7, 8]
>     return iter(l)
> def main():
>     for i in test():
>         print(i)

Perfectly safe. Python guarantees that nothing can ever point to
"nowhere"; everything that might be looking for something else will
hold a reference to it, so the thing referred to will hang around.

ChrisA

[toc] | [prev] | [next] | [standalone]


#64727

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-01-25 06:45 +0000
Message-ID<52e35d89$0$29999$c3e8da3$5496439d@news.astraweb.com>
In reply to#64725
On Fri, 24 Jan 2014 22:37:37 -0800, seaspeak wrote:

> take the following as an example, which could work well. But my concern
> is, will list 'l' be deconstructed after function return? and then
> iterator point to nowhere?

That would be a pretty awful bug for Python, since it would like lead to 
a core dump. But no, it works fine, as you can see by trying it at the 
interactive interpreter:

py> def test():
...     L = [1, 2, 4, 8, 16]
...     return iter(L)
...
py>
py> for i in test():
...     print(i)
...
1
2
4
8
16


In fact, we don't even need a function to see the same effect:


py> L = [1, 2, 4, 8, 16]
py> it = iter(L)
py> del L
py> L = "something else"
py> for i in it:
...     print(i)
...
1
2
4
8
16


Python keeps track of when objects are in use, and does not destroy them 
so long as it is in use. In the meantime, you can exit the function, 
unbind (delete) the variable, re-assign to something else, whatever, and 
you should never get a core dump.

(I've only ever seen a single core dump in Python in 15+ years.)



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#64742

FromNed Batchelder <ned@nedbatchelder.com>
Date2014-01-25 07:55 -0500
Message-ID<mailman.5974.1390654524.18130.python-list@python.org>
In reply to#64725
On 1/25/14 1:37 AM, seaspeak@gmail.com wrote:
> take the following as an example, which could work well.
> But my concern is, will list 'l' be deconstructed after function return? and then iterator point to nowhere?
>
> def test():
>      l = [1, 2, 3, 4, 5, 6, 7, 8]
>      return iter(l)
> def main():
>      for i in test():
>          print(i)
>
>

The two things to understand here are names, and values.  When you leave 
the function test, the name l goes away, because it is a locally scoped 
name.  It referred to a value, your list.  But values have reference 
counts, and are not reclaimed until their reference count drops to zero.

Your function is returning a value, a listiterator, and that 
listiterator refers to the list, so the list won't be reclaimed.

Names have scopes but no types.  Values have types, but no scope.  They 
live as long as they are referred to by something.

This is covered in more detail here: 
http://nedbatchelder.com/text/names.html


-- 
Ned Batchelder, http://nedbatchelder.com

[toc] | [prev] | [next] | [standalone]


#64743

FromNed Batchelder <ned@nedbatchelder.com>
Date2014-01-25 07:56 -0500
Message-ID<mailman.5975.1390654808.18130.python-list@python.org>
In reply to#64725
On 1/25/14 1:37 AM, seaspeak@gmail.com wrote:
> take the following as an example, which could work well.
> But my concern is, will list 'l' be deconstructed after function return? and then iterator point to nowhere?
>
> def test():
>      l = [1, 2, 3, 4, 5, 6, 7, 8]
>      return iter(l)
> def main():
>      for i in test():
>          print(i)
>
>

One more thing: there's no need to call iter() explicitly here.  Much 
more common than returning an iterator from a function is to return an 
iterable.  Your code will work exactly the same if you just remove the 
iter() call:

     def test():
         l = [1, 2, 3, 4, 5, 6, 7, 8]
         return l
     def main():
         for i in test():
             print(i)


-- 
Ned Batchelder, http://nedbatchelder.com

[toc] | [prev] | [next] | [standalone]


#64744

FromPeter Otten <__peter__@web.de>
Date2014-01-25 14:32 +0100
Message-ID<mailman.5976.1390656750.18130.python-list@python.org>
In reply to#64725
Ned Batchelder wrote:

> On 1/25/14 1:37 AM, seaspeak@gmail.com wrote:
>> take the following as an example, which could work well.
>> But my concern is, will list 'l' be deconstructed after function return?
>> and then iterator point to nowhere?
>>
>> def test():
>>      l = [1, 2, 3, 4, 5, 6, 7, 8]
>>      return iter(l)
>> def main():
>>      for i in test():
>>          print(i)
>>
>>
> 
> One more thing: there's no need to call iter() explicitly here.  Much
> more common than returning an iterator from a function is to return an
> iterable.  Your code will work exactly the same if you just remove the
> iter() call:
> 
>      def test():
>          l = [1, 2, 3, 4, 5, 6, 7, 8]
>          return l
>      def main():
>          for i in test():
>              print(i)
 
For that specific client code, yes. In the general case the difference 
matters. Iteration over an iterable starts at the beginning while iteration 
over an iterator starts at the current item:

>>> def main():
...     items = test()
...     print(list(zip(items, items)))
... 
>>> def test(): return range(6) # an iterable
... 
>>> main()
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
>>> def test(): return iter(range(6)) # an iterator
... 
>>> main()
[(0, 1), (2, 3), (4, 5)]
 

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web