Recursive Generator Error?

D

David

I have a tree-like data structure, the basic elements are hash tables,
and they are grouped into lists, like [[{'a':1},[{'b':2}]]].
And I want to flat the lists and visit hash table one by one, like {'a':1}, {'b':2}.
But my program didn't work as I wish. When it entered the 2nd
flat_yield, it threw a GeneratorExit. Is there anything wrong?
Thank you very much!

#- - - - - - - - - -
def flat_yield(tbl_list):
for t in tbl_list:
if type(t) == type({}):
yield t
elif type(t) == type([]):
flat_yield(t)
a = [[{'a':1},[{'b':2}]]]
for i in flat_yield(a):
print i
 
T

Terry Reedy

I have a tree-like data structure, the basic elements are hash tables,
and they are grouped into lists, like [[{'a':1},[{'b':2}]]].
And I want to flat the lists and visit hash table one by one, like {'a':1}, {'b':2}.
But my program didn't work as I wish. When it entered the 2nd
flat_yield, it threw a GeneratorExit. Is there anything wrong?

1. The Python version is not specified.
2. You used 2.x; in 3.3 the code does exactly what I would expect, which
is to say, nothing. No output, no error, no traceback ;-)
3. The traceback is missing from this post.
#- - - - - - - - - -
def flat_yield(tbl_list):
for t in tbl_list:
if type(t) == type({}):
yield t
elif type(t) == type([]):
flat_yield(t)

4. Think harder about what that expression does.
a = [[{'a':1},[{'b':2}]]]
for i in flat_yield(a):
print i

Hint: it calls flat_yield, which returns a generator, which is then
discarded. You might have well written 'pass'.

Solution: use the recursively called generator and recursively yield
what it yields. Replace 'flat_yield(t)' with

for item in flat_yield(t):
yield item

and the output is what you want.
 
D

David

I have a tree-like data structure, the basic elements are hash tables,
and they are grouped into lists, like [[{'a':1},[{'b':2}]]].
And I want to flat the lists and visit hash table one by one, like {'a':1}, {'b':2}.
But my program didn't work as I wish. When it entered the 2nd
flat_yield, it threw a GeneratorExit. Is there anything wrong?



1. The Python version is not specified.

2. You used 2.x; in 3.3 the code does exactly what I would expect, which

is to say, nothing. No output, no error, no traceback ;-)

3. The traceback is missing from this post.


#- - - - - - - - - -
def flat_yield(tbl_list):
for t in tbl_list:
if type(t) == type({}):
elif type(t) == type([]):
flat_yield(t)



4. Think harder about what that expression does.


a = [[{'a':1},[{'b':2}]]]
for i in flat_yield(a):



Hint: it calls flat_yield, which returns a generator, which is then

discarded. You might have well written 'pass'.



Solution: use the recursively called generator and recursively yield

what it yields. Replace 'flat_yield(t)' with



for item in flat_yield(t):

yield item



and the output is what you want.

Hi Terry, thank you! I use Python 2.7, and your solution works!

I have thought harder, still not very clear.

If I have one "yield" in function, the function will become generator, and it can only be called in the form like "for item in function()" or "function.next()", and call the function directly will raise error, is it right?
 
D

David

I have a tree-like data structure, the basic elements are hash tables,
and they are grouped into lists, like [[{'a':1},[{'b':2}]]].
And I want to flat the lists and visit hash table one by one, like {'a':1}, {'b':2}.
But my program didn't work as I wish. When it entered the 2nd
flat_yield, it threw a GeneratorExit. Is there anything wrong?



1. The Python version is not specified.

2. You used 2.x; in 3.3 the code does exactly what I would expect, which

is to say, nothing. No output, no error, no traceback ;-)

3. The traceback is missing from this post.


#- - - - - - - - - -
def flat_yield(tbl_list):
for t in tbl_list:
if type(t) == type({}):
elif type(t) == type([]):
flat_yield(t)



4. Think harder about what that expression does.


a = [[{'a':1},[{'b':2}]]]
for i in flat_yield(a):



Hint: it calls flat_yield, which returns a generator, which is then

discarded. You might have well written 'pass'.



Solution: use the recursively called generator and recursively yield

what it yields. Replace 'flat_yield(t)' with



for item in flat_yield(t):

yield item



and the output is what you want.

Hi Terry, thank you! I use Python 2.7, and your solution works!

I have thought harder, still not very clear.

If I have one "yield" in function, the function will become generator, and it can only be called in the form like "for item in function()" or "function.next()", and call the function directly will raise error, is it right?
 
S

Steven D'Aprano

If I have one "yield" in function, the function will become generator,

Almost correct. The function becomes a *generator function*, that is, a
function that returns a generator object.

Sometimes people abbreviate that to "generator", but that is ambiguous --
the term "generator" can mean either the function which includes yield in
it, or the object that is returned.
and it can only be called in the form like "for item in function()" or
"function.next()", and call the function directly will raise error, is
it right?

You can call the function directly, and it will return an generator
object. You don't have to iterate over that generator object, although
you normally will.

Example:

py> def test():
.... yield 42
....
py> test
<function test at 0xb7425764>
py> type(test)
<type 'function'>
py> x = test()
py> x
<generator object test at 0xb71d4874>
py> type(x)
<type 'generator'>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top