Yield in a recursive function

2019-03-08 07:41发布

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?

9条回答
劫难
2楼-- · 2019-03-08 08:22

The problem is this line of code:

explore(path)

What does it do?

  • calls explore with the new path
  • explore runs, creating a generator
  • the generator is returned to the spot where explore(path) was executed . . .
  • and is discarded

Why is it discarded? It wasn't assigned to anything, it wasn't iterated over -- it was completely ignored.

If you want to do something with the results, well, you have to do something with them! ;)

The easiest way to fix your code is:

for name in explore(path):
    yield name

When you are confident you understand what's going on, you'll probably want to use os.walk() instead.

Once you have migrated to Python 3.3 (assuming all works out as planned) you will be able to use the new yield from syntax and the easiest way to fix your code at that point will be:

yield from explore(path)
查看更多
霸刀☆藐视天下
3楼-- · 2019-03-08 08:22

Try this:

if stat.S_ISDIR(stat_info.st_mode):
    for p in explore(path):
        yield p
查看更多
劳资没心,怎么记你
4楼-- · 2019-03-08 08:23

Change this:

explore(path)

To this:

for subpath in explore(path):
    yield subpath

Or use os.walk, as phooji suggested (which is the better option).

查看更多
登录 后发表回答