Re: [Python-Dev] os.path.walk() lacks 'depth first' option

At 09:44 PM 5/12/03 -0400, Guido van Rossum wrote:
This sounds like a much more advanced use, typical to a certain style of programming.
Framework programming, for maximal adaptability of third-party code, yes.
Others would do this using hasattr() or three-argument getattr()
I use three-argument getattr() most of the time, actually. However, doesn't 'getattr()' rely on catching AttributeError? I just wanted my example to be explicit.
Your example argues for allowing to distringuish between AttributeError and TypeError, but doesn't convince me that they are totally different beasts.
Sure. My point is more that using exceptions to indicate failed lookups is a tricky business. I almost wish there was a way to declare the "normal" exceptions raised by an operation; or perhaps to easily query where an exception was raised. Nowadays, when designing interfaces that need to signal some kind of exceptional condition, I tend to want to have them return sentinel values rather than raise exceptions, in order to distinguish between "failed" and "broken". I'm sure that this is an issue specific to framework programming and to large team-built systems, though, and not something that bothers the mythical "average developer" a bit. :)

How about this patch? Index: os.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/os.py,v retrieving revision 1.70 diff -c -c -r1.70 os.py *** os.py 25 Apr 2003 07:11:48 -0000 1.70 --- os.py 13 May 2003 15:40:21 -0000 *************** *** 203,209 **** __all__.extend(["makedirs", "removedirs", "renames"]) ! def walk(top, topdown=True): """Directory tree generator. For each directory in the directory tree rooted at top (including top --- 203,209 ---- __all__.extend(["makedirs", "removedirs", "renames"]) ! def walk(top, topdown=True, onerror=None): """Directory tree generator. For each directory in the directory tree rooted at top (including top *************** *** 232,237 **** --- 232,243 ---- dirnames have already been generated by the time dirnames itself is generated. + By default errors from the os.listdir() call are ignored. If + optional arg 'onerror' is specified, it should be a function; + it will be called with one argument, an exception instance. It + can report the error to continue with the walk, or raise the + exception to abort the walk. + Caution: if you pass a relative pathname for top, don't change the current working directory between resumptions of walk. walk never changes the current directory, and assumes that the client doesn't *************** *** 259,265 **** # Note that listdir and error are globals in this module due # to earlier import-*. names = listdir(top) ! except error: return dirs, nondirs = [], [] --- 265,273 ---- # Note that listdir and error are globals in this module due # to earlier import-*. names = listdir(top) ! except error, err: ! if onerror is not None: ! onerror(err) return dirs, nondirs = [], [] *************** *** 274,280 **** for name in dirs: path = join(top, name) if not islink(path): ! for x in walk(path, topdown): yield x if not topdown: yield top, dirs, nondirs --- 282,288 ---- for name in dirs: path = join(top, name) if not islink(path): ! for x in walk(path, topdown, onerror): yield x if not topdown: yield top, dirs, nondirs --Guido van Rossum (home page: http://www.python.org/~guido/)

Guido van Rossum wrote:
How about this patch?
I like the increased flexibility. But how about the following version? --- def walk(top, order=".d", recursive=True, onerror=None): from os.path import join, isdir, islink, normpath try: names = listdir(top) except error, err: if onerror is not None: onerror(err) return dirs, nondirs = [], [] for name in names: if isdir(join(top, name)): dirs.append(name) else: nondirs.append(name) for c in order: if c==".": yield top, dirs, nondirs elif c=="f": for nd in nondirs: yield normpath(join(top, nd)), [], [] elif c=="d": for name in dirs: path = join(top, name) if not islink(path): if recursive: for x in walk(path, order, recursive, onerror): yield (normpath(x[0]), x[1], x[2]) else: yield path else: raise ValueError, "unknown order %r" % c --- It combines recursive and non-recursive walks, topdown and bottomup walks, walks with and without files or directories. E.g. Getting a list of all files, topdown: [x[0] for x in os.walk(top, order="fd")] or a list of directories bottom up: [x[0] for x in os.walk(top, order="d.")] or a list of files and directories, topdown, with files before subdirectories: [x[0] for x in os.walk(top, order=".fd")] Bye, Walter Dörwald
participants (3)
-
Guido van Rossum
-
Phillip J. Eby
-
Walter Dörwald