我可以从内部对生成器函数进行排序,而无需创建另一个包装函数或在外部对其进行排序吗?
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]
排序对象的概念涉及比较其元素以确定哪些元素大于其他元素。从本质上讲,生成器一次只生成一个元素。如果您想查看按特定顺序生成的元素,理想情况下您应该编写生成器的算法来生成您实际想要的顺序。否则,您将不得不将其耗尽到一个数据结构中,然后对其进行排序(显然不理想,因为它破坏了生成器的好处)。
就您编写的特定生成器而言,我的建议是考虑它生成“相当未排序”结果的方式 - 您已经在其中对一些循环进行排序,所以我希望它有某种秩序。准确调查您如何获得该订单并确定它与您希望看到的订单有何不同,然后根据需要进行调整。
就强制生成器按与其算法生成的顺序不同的一般问题而言,不,如果不存储整个结果然后将生成的元素相互比较(即排序),就无法做到这一点.
我有一个围绕 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]
排序对象的概念涉及比较其元素以确定哪些元素大于其他元素。从本质上讲,生成器一次只生成一个元素。如果您想查看按特定顺序生成的元素,理想情况下您应该编写生成器的算法来生成您实际想要的顺序。否则,您将不得不将其耗尽到一个数据结构中,然后对其进行排序(显然不理想,因为它破坏了生成器的好处)。
就您编写的特定生成器而言,我的建议是考虑它生成“相当未排序”结果的方式 - 您已经在其中对一些循环进行排序,所以我希望它有某种秩序。准确调查您如何获得该订单并确定它与您希望看到的订单有何不同,然后根据需要进行调整。
就强制生成器按与其算法生成的顺序不同的一般问题而言,不,如果不存储整个结果然后将生成的元素相互比较(即排序),就无法做到这一点.