Yield in a recursive function

Ali picture Ali · Jul 20, 2011 · Viewed 13.3k times · Source

I am trying to do something to all the files under a given path. I don't want to collect all the file names beforehand then do something with them, so I tried this:

import os
import stat

def explore(p):
  s = ''
  list = os.listdir(p)
  for a in list:
    path = p + '/' + a
    stat_info = os.lstat(path )
    if stat.S_ISDIR(stat_info.st_mode):
     explore(path)
    else:
      yield path

if __name__ == "__main__":
  for x in explore('.'):
    print '-->', x

But this code skips over directories when it hits them, instead of yielding their contents. What am I doing wrong?

Answer

Jeremy picture Jeremy · Jul 20, 2011

Iterators do not work recursively like that. You have to re-yield each result, by replacing

explore(path)

with something like

for value in explore(path):
    yield value

Python 3.3 added the syntax yield from X, as proposed in PEP 380, to serve this purpose. With it you can do this instead:

yield from explore(path)

If you're using generators as coroutines, this syntax also supports the use of generator.send() to pass values back into the recursively-invoked generators. The simple for loop above would not.