我可以从内部对生成器函数进行排序,而无需创建另一个包装函数或在外部对其进行排序吗?

Can I sort a generator function from within itself without creating another wrapper function, or sorting it outside?

我有一个围绕 os.walk() 的很好用的包装器,它将深入发现的文件和目录映射到 Path 的子 class:

class 查找:

@staticmethod
def deep(path: Union[str, Path, 'WalkPath'], 
            sort_key=lambda p: str(p).lower()) -> ['WalkPath']:
    
    if Path(path).is_file(): 
        return [WalkPath(path)]
    
    for root,dirs,files in os.walk(WalkPath(path)):
        
        dirs = sorted([WalkPath(root).joinpath(d) for d in dirs], key=sort_key)
        files = sorted([WalkPath(root).joinpath(f) for f in files], key=sort_key)
        
        yield WalkPath(root, dirs=dirs, files=files)
        yield from files

这非常有效 - 我可以迭代结果,并在其中任何一个上检查其中包含的文件或目录。

不幸的是,结果返回时未排序。我知道我可以做到:

paths = sorted(Find.deep(root), key=lambda p: str(p).lower())

事后,或者我可以创建一个包装函数:

@staticmethod      
def sorted_deep(path):
    yield from sorted(Find.deep(root), key=lambda p: str(p).lower())

但我想知道是否有一种方法可以直接在主函数中处理排序?我试着研究是否可以重新处理它以适应 lambda 表达式,但无法让它与分配目录和文件一起工作。

为了完整起见,这里是 WalkPath 对象:

#!/usr/bin/env python
import os
import pathlib
from pathlib import Path
from typing import Union

class WalkPath(Path):
    
    _flavour = type(Path())._flavour
    
    def __init__(self, *args, dirs: []=[], files: []=[]):
        """Initialize WalkPath object.

        Args:
            dirs (list):    Dirs provided by os.walk(), defauls to []
            files (list):   Files provided by os.walk(), defaults to []
        """
        
        super().__init__()
        
        self.dirs: [WalkPath] = list(map(WalkPath, dirs))
        self.files: [WalkPath] = list(map(WalkPath, files))
    
    def joinpath(self, path) -> 'WalkPath':
        joined = WalkPath(super().joinpath(path))
        self.__dict__ = joined.__dict__.copy()
        return joined
    
    @property
    def is_terminus(self) -> bool:
        return self.is_file() or not self.dirs
    
    @property
    def dirs_abs(self) -> ['WalkPath']:
        return [self.joinpath(d) for d in self.dirs]
    
    @property
    def files_abs(self) -> ['WalkPath']:
        return [self.joinpath(f) for f in self.files]

排序对象的概念涉及比较其元素以确定哪些元素大于其他元素。从本质上讲,生成器一次只生成一个元素。如果您想查看按特定顺序生成的元素,理想情况下您应该编写生成器的算法来生成您实际想要的顺序。否则,您将不得不将其耗尽到一个数据结构中,然后对其进行排序(显然不理想,因为它破坏了生成器的好处)。

就您编写的特定生成器而言,我的建议是考虑它生成“相当未排序”结果的方式 - 您已经在其中对一些循环进行排序,所以我希望它有某种秩序。准确调查您如何获得该订单并确定它与您希望看到的订单有何不同,然后根据需要进行调整。

就强制生成器按与其算法生成的顺序不同的一般问题而言,不,如果不存储整个结果然后将生成的元素相互比较(即排序),就无法做到这一点.