Issue #23605: os.walk() now calls os.scandir() instead of os.listdir().
The usage of os.scandir() reduces the number of calls to os.stat(). Initial patch written by Ben Hoyt.
This commit is contained in:
parent
283f3f8ab3
commit
524a5ba111
|
@ -2618,6 +2618,11 @@ features:
|
||||||
for name in dirs:
|
for name in dirs:
|
||||||
os.rmdir(os.path.join(root, name))
|
os.rmdir(os.path.join(root, name))
|
||||||
|
|
||||||
|
.. versionchanged:: 3.5
|
||||||
|
The function now calls :func:`os.scandir` instead of :func:`os.listdir`.
|
||||||
|
The usage of :func:`os.scandir` reduces the number of calls to
|
||||||
|
:func:`os.stat`.
|
||||||
|
|
||||||
|
|
||||||
.. function:: fwalk(top='.', topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None)
|
.. function:: fwalk(top='.', topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None)
|
||||||
|
|
||||||
|
|
51
Lib/os.py
51
Lib/os.py
|
@ -323,7 +323,7 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
|
||||||
the value of topdown, the list of subdirectories is retrieved before the
|
the value of topdown, the list of subdirectories is retrieved before the
|
||||||
tuples for the directory and its subdirectories are generated.
|
tuples for the directory and its subdirectories are generated.
|
||||||
|
|
||||||
By default errors from the os.listdir() call are ignored. If
|
By default errors from the os.scandir() call are ignored. If
|
||||||
optional arg 'onerror' is specified, it should be a function; it
|
optional arg 'onerror' is specified, it should be a function; it
|
||||||
will be called with one argument, an OSError instance. It can
|
will be called with one argument, an OSError instance. It can
|
||||||
report the error to continue with the walk, or raise the exception
|
report the error to continue with the walk, or raise the exception
|
||||||
|
@ -352,7 +352,9 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
islink, join, isdir = path.islink, path.join, path.isdir
|
dirs = []
|
||||||
|
nondirs = []
|
||||||
|
symlinks = set()
|
||||||
|
|
||||||
# We may not have read permission for top, in which case we can't
|
# We may not have read permission for top, in which case we can't
|
||||||
# get a list of the files the directory contains. os.walk
|
# get a list of the files the directory contains. os.walk
|
||||||
|
@ -360,27 +362,46 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
|
||||||
# minor reason when (say) a thousand readable directories are still
|
# minor reason when (say) a thousand readable directories are still
|
||||||
# left to visit. That logic is copied here.
|
# left to visit. That logic is copied here.
|
||||||
try:
|
try:
|
||||||
# Note that listdir is global in this module due
|
# Note that scandir is global in this module due
|
||||||
# to earlier import-*.
|
# to earlier import-*.
|
||||||
names = listdir(top)
|
for entry in scandir(top):
|
||||||
except OSError as err:
|
try:
|
||||||
|
is_dir = entry.is_dir()
|
||||||
|
except OSError:
|
||||||
|
# If is_dir() raises an OSError, consider that the entry is not
|
||||||
|
# a directory, same behaviour than os.path.isdir().
|
||||||
|
is_dir = False
|
||||||
|
|
||||||
|
if is_dir:
|
||||||
|
dirs.append(entry.name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if entry.is_symlink():
|
||||||
|
symlinks.add(entry.name)
|
||||||
|
except OSError:
|
||||||
|
# If is_symlink() raises an OSError, consider that the
|
||||||
|
# entry is not a symbolik link, same behaviour than
|
||||||
|
# os.path.islink().
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
nondirs.append(entry.name)
|
||||||
|
except OSError as error:
|
||||||
|
# scandir() or iterating into scandir() iterator raised an OSError
|
||||||
if onerror is not None:
|
if onerror is not None:
|
||||||
onerror(err)
|
onerror(error)
|
||||||
return
|
return
|
||||||
|
|
||||||
dirs, nondirs = [], []
|
# Yield before recursion if going top down
|
||||||
for name in names:
|
|
||||||
if isdir(join(top, name)):
|
|
||||||
dirs.append(name)
|
|
||||||
else:
|
|
||||||
nondirs.append(name)
|
|
||||||
|
|
||||||
if topdown:
|
if topdown:
|
||||||
yield top, dirs, nondirs
|
yield top, dirs, nondirs
|
||||||
|
|
||||||
|
# Recurse into sub-directories
|
||||||
for name in dirs:
|
for name in dirs:
|
||||||
new_path = join(top, name)
|
if followlinks or name not in symlinks:
|
||||||
if followlinks or not islink(new_path):
|
new_path = path.join(top, name)
|
||||||
yield from walk(new_path, topdown, onerror, followlinks)
|
yield from walk(new_path, topdown, onerror, followlinks)
|
||||||
|
|
||||||
|
# Yield after recursion if going bottom up
|
||||||
if not topdown:
|
if not topdown:
|
||||||
yield top, dirs, nondirs
|
yield top, dirs, nondirs
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #23605: os.walk() now calls os.scandir() instead of os.listdir().
|
||||||
|
The usage of os.scandir() reduces the number of calls to os.stat().
|
||||||
|
Initial patch written by Ben Hoyt.
|
||||||
|
|
||||||
|
|
||||||
What's New in Python 3.5 alpha 2?
|
What's New in Python 3.5 alpha 2?
|
||||||
=================================
|
=================================
|
||||||
|
|
Loading…
Reference in New Issue