【问题标题】:How to take a pathname string with wildcards and resolve the glob with pathlib?如何使用通配符获取路径名字符串并使用 pathlib 解析 glob?
【发布时间】:2018-06-29 19:27:59
【问题描述】:

如果我得到一个字符串形式的路径,例如“~/pythoncode/*.py”,那么在pathlib 中将其全局化的最佳方式是什么?

使用 pathlib,有一种方法可以使用 glob 附加到路径:

p = pathlib.Path('~/pythoncode/').expanduser().glob('*.py')

但是,例如,这不起作用,因为用户没有展开:

p = pathlib.Path().glob('~/pythoncode/*.py')

这会产生一个异常,因为我没有向 glob() 提供任何参数:

p = pathlib.Path('~/pythoncode/*.py').expanduser().glob()

有没有办法在pathlib 中做到这一点,还是我必须先解析字符串?

【问题讨论】:

  • 我认为你的问题本身就可以回答,但我可能是错的
  • 查看PurePath.parts
  • 我相信os.path.expanduser() 是一个无操作直通,如果没有什么可扩展的,所以你可以做类似Path().glob(os.path.expanduser('~/pythoncode/*.py')) 的事情
  • @jedwards: NotImplementedError: Non-relative patterns are unsupported
  • @MadPhysicist:我认为它只有在我没有忽略某些东西的情况下才会自行解决——这似乎是因为我缺乏使用这个库的经验。 pathlib 非常完整,我希望通过正确的调用顺序,它可以更接近地模仿 shell 并进行完整的扩展。

标签: python python-3.x glob pathlib


【解决方案1】:

如果您从字符串"~/pythoncode/*.py" 开始并且想要扩展和全局,则需要先拆分路径。幸运的是 pathlib 提供了.name.parent 来帮助you out

def expandpath(path_pattern) -> Iterable[Path]:
    p = Path(path_pattern)
    return Path(p.parent).expanduser().glob(p.name)

expandpath("~/pythonpath/*.py")

请注意,这个简单的解决方案仅在只有 name 包含 glob 时才有效,它不适用于路径其他部分的 glob,例如:~/python*/*.py。一个更通用但更复杂一点的解决方案:

def expandpath(path_pattern) -> Iterable[Path]:
    p = Path(path_pattern).expanduser()
    parts = p.parts[p.is_absolute():]
    return Path(p.root).glob(str(Path(*parts)))

expandpath("~/python*/*.py")

注意 2:上述函数 失败 (IndexError: tuple index out of range) 具有以下退化路径:'''.''/'

【讨论】:

  • 这似乎工作只要通配符在路径的name 部分,如我的示例所示。在一般情况下,使用expanduser() 然后按照@MadPhysicist 的建议迭代parts() 或者parents() 然后进行合并会更好吗?
  • @Omegaman 好电话。值得庆幸的是,不需要迭代和合并。我在原始解决方案中添加了一个稍微复杂一点的版本,该版本通常针对具有多个级别的 glob 的相对和绝对路径解决此问题。
  • 第二个解决方案很好,有趣的是这在pathlib 开始时没有实现,当我希望它是一个非常常见的glob用例时......有人关心打开功能请求?
  • Booooo 路径库!
【解决方案2】:

pathlib.Path.glob 不支持绝对(非相对)路径模式,但 glob.glob 支持:

from glob import glob
from pathlib import Path

paths = [Path(p) for p in glob('/foo/*/bar')]

或与Path.expanduser有关:

paths = [Path(p) for p in glob(str(Path('~/.bash*').expanduser()))]

【讨论】:

    【解决方案3】:

    我发现我真的想要内联扩展。这并不像我想象的那么容易。

    无论如何,这就是我所拥有的。只是进行了简单的测试,但请告诉我它适合你的地方,我会对其进行编辑。

    def expand_pathglobs(pathparts, basepaths=None):
        # Logic:
        # 0. Argue with a Path(str).parts and optional ['/start','/dirs'].
        # 1. for each basepath, expand out pathparts[0] into "expandedpaths"
        # 2. If there are no more pathparts, expandedpaths is the result.
        # 3. Otherwise, recurse with expandedpaths and the remaining pathparts.
        # eg: expand_pathglobs('/tmp/a*/b*')
        #   --> /tmp/a1/b1
        #   --> /tmp/a2/b2
    
        if isinstance(pathparts, str) or isinstance(pathparts, Path):
            pathparts = Path(pathparts).parts
    
        if basepaths == None:
            return expand_pathglobs(pathparts[1:], [Path(pathparts[0])])
        else:
            assert pathparts[0] != '/'
    
        expandedpaths = []
        for p in basepaths:
            assert isinstance(p, Path)
            globs = p.glob(pathparts[0])
            for g in globs:
                expandedpaths.append(g)
    
        if len(pathparts) > 1:
            return expand_pathglobs(pathparts[1:], expandedpaths)
    
        return expandedpaths
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-28
      • 2014-06-25
      • 2015-01-24
      • 2016-07-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多