所以在提供的场景中 - 有没有办法对列表进行操作,例如
dirs.remove_items(e for e in EXCLUDES if e in dirs)
没有。列表没有内置的 remove_items 或 remove_all 函数。对于集合,您可以使用 intersection_update 或 -= 来完成这项工作:
>>> EXCLUDES = {"a", "b", "c"}
>>> dirs = {"a", "x", "y"}
>>> dirs -= EXCLUDES
>>> dirs == {'x', 'y'}
True
或者更笼统地说:是否有(推荐的)方式以“for each”语义运行命令,例如 fn(e) for e in container
是的:如果fn(e) 是纯的,则使用列表推导式,否则,编写:
for e in container:
fn(e)
一些说明
编辑下面的@ShadowRanger 评论。
doc 声明:
当 topdown 为 True 时,调用者可以就地修改 dirnames 列表(可能使用 del 或 slice 赋值),并且 walk() 只会递归到名称保留在 dirnames 中的子目录;这可用于修剪搜索,强制执行特定的访问顺序,甚至在调用者再次恢复 walk() 之前通知 walk() 有关调用者创建或重命名的目录。当 topdown 为 False 时修改 dirnames 对 walk 的行为没有影响,因为在自底向上模式下,dirnames 中的目录是在 dirpath 本身生成之前生成的。
我不明白 OP 的目标是修剪搜索。以下评论不适用于这种情况,但总体上仍然适用。请参阅@ShadowRanger 的答案以使用切片分配修剪搜索。
编辑结束
正如您所说,使用列表推导(或map)产生副作用是个坏主意。列表推导返回一个列表,句号。
但是没有什么能阻止你将你写的列表理解分配给 dirs 本身:
dirs = [e for e in dirs if e not in EXCLUDES]
您不是在删除项目,而是在创建一个新列表(如果我没记错的话,这就是列表理解的重点)。如果您担心创建新列表的成本,可以使用生成器:
>>> EXCLUDES = {"a", "b", "c"}
>>> dirs = ["a", "x", "y"]
>>> dirs = (e for e in dirs if e not in EXCLUDES)
>>> dirs
<generator object <genexpr> at ...>
>>> list(dirs)
['x', 'y']
生成器惰性,因此将从dirs 读取元素并即时过滤。不会创建新列表。 filter 也是如此:
>>> dirs = filter(lambda f: f not in EXCLUDES, dirs)
>>> dirs
<filter object at ...>
>>> list(dirs)
['x', 'y']
但不适用于reduce:
>>> from functools import reduce
>>> dirs = reduce(lambda acc, f: acc if f in EXCLUDES else acc + [f], dirs, [])
>>> dirs
['x', 'y']