【问题标题】:Recursive globbing of fast-changing directories快速更改目录的递归通配符
【发布时间】:2021-12-17 21:33:54
【问题描述】:

我偶然发现了一个不直观的问题:如果您递归地 glob(使用 pathlib)快速更改目录,在其中创建和删除其他目录,您有机会获得FileNotFoundException。如果找不到目录,那为什么要打扰我呢?为什么不跳过虚假目录并继续?以及如何以紧凑的方式解决这个问题?

这里是如何重现这个:

用这个 sh 命令启动一个终端

while true; do mkdir deleteme && rmdir deleteme; done

另一个使用这个 python 脚本:

from pathlib import Path
p = Path()
while True:
    list(p.rglob('*'))

或者,作为oneliner:

while true; do mkdir 1 && rmdir 1; done & python3 -c "from pathlib import Path; from itertools import count; p = Path(); [list(p.rglob('*')) for i in count(start=1)]"; fg

【问题讨论】:

  • 你试过try: list(p.rglob('*')) except FileNotFoundException: continue
  • 这不是一个选项,我需要所有可以给我 rglob 的东西。如果它会被中断,我需要重新启动它。
  • 因为听起来你需要 speec pathlib 并不是最快的。如果你不是一定要使用 rglob,看看这个github.com/juancarlospaco/thatlib#thatlib
  • 也许这是 serverfault 或 unix 上的人们更熟悉的情况

标签: python python-3.x glob pathlib


【解决方案1】:

产生异常的原语是os.scandir。

正在发生的事情是 pathlib.Path.rglob() 方法创建了一个选择器对象(pathlib._WildcardSelector 通过 pathlib._make_selector,给定您的模式),然后在 rglob() 生成器的执行期间进行延迟迭代。

pathlib 模块似乎没有提供任何挂钩来轻松自定义或覆盖此行为。

最好的解决方案可能是子类化Path 或PosixPath 类,覆盖rglob() 方法,以一种能够适应这种错误模式的方式重建实现。

似乎可以作为概念证明的猴子补丁方法:

import contextlib
import pathlib

def my_scandir(path=None):
     while True:
         try:
             result = list(os.scandir(path))
         except FileNotFoundError:
             continue
         @contextlib.contextmanager
         def wrapped_result():
             try:
                 yield result
             finally:
                 pass
         return wrapped_result()

pathlib._NormalAccessor.scandir = staticmethod(my_scandir)

应用此补丁后,您的示例中带有rglob('*') 的while 循环不会再因FileNotFoundError 而失败。

这适用于 Python v3.8.5。因为它使用了 pathlib 模块的实现细节,所以它可能不适用于其他 python 版本。

【讨论】:

    猜你喜欢
    • 2021-09-02
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    相关资源
    最近更新 更多