【问题标题】:Flat generators in PythonPython 中的平面生成器
【发布时间】:2013-06-12 21:40:03
【问题描述】:

是否可以在 python 中进行平面惰性生成?例如,我在下面的代码中试图做的是传递 os.walk 的结果并尝试只返回那些结果

def os_walk_transcript(self, walk_results):
    """Takes the results of os.walk on the data directory and returns a list of absolute paths"""
    file_check = lambda walk: len(walk[2]) > 0
    srt_prelim = lambda walk: ".srt.sjson" in " ".join(walk[2])
    relevant_results = (entry for entry in walk_results if file_check(entry) and srt_prelim(entry))
    return (self.os_path_tuple_srts(result) for result in relevant_results)

def os_path_tuple_srts(self, os_walk_tuple):
    srt_check = lambda file_name: file_name[-10:] == ".srt.sjson"
    directory, subfolders, file_paths = os_walk_tuple
    return [os.path.join(directory, file_path) for file_path in file_paths if srt_check(file_path)]

延迟评估 os_walk_transcript 的结果很重要,但我希望能够以平坦的方式评估它,而不是当前的嵌套列表评估。

例如:目前,当我从生成的生成器中请求结果时,我得到了 ["1.srt.sjson", "2.srt.sjson", "3.srt.sjson"] 的完整列表,然后如果我再次调用它,我会得到:["4.srt.sjson"] 我正在一个项目中工作,其中数据足够大且足够不一致,以至于这种行为会导致性能不一致,有时这会导致事情比我想要的慢得多。有什么办法可以让惰性求值更加惰性,一次只加载一个对象?

【问题讨论】:

    标签: python generator list-comprehension lazy-evaluation


    【解决方案1】:

    您可以使用 itertools chain.from_iterable()。文档是here.

    基本上,你可以这样使用它:

    import itertools
    
    myList = [[1,2,3],[4,5],[6],[7,8,9]]
    
    itr = itertools.chain.from_iterator(myList)
    

    itr 现在将是一个生成器对象,每次调用它时都会返回下一个元素。 (在这种情况下,它将与xrange(10) 完全相同)

    【讨论】:

    • 太棒了!正是我想要的。
    【解决方案2】:

    你就不能做一个这样的函数吗?

    def lazyarray(index):
        return str(index) + ".srt.sjson"
    

    那么你甚至可以做到这一点

    firstTen = [lazyarray(x) for x in xrange(10)]
    

    完全懒惰,实现起来非常简单。如果您想少一点懒惰(缓存计算),您也许可以这样做。

    cache = []
    def lazyarray(index):
        if len(cache) <= index:
            cache += ["" for x in xrange(index - len(cache))]
        if cache[index] == "":
            cache[index] = str(index) + ".srt.sjson"
        return cache[index]
    

    我还没有测试过任何代码,所以它可能需要调整,而且我不处理文件,但这不是你要问的吗?

    而且无论你在代码中的哪个位置,而不是说

    lazyarray[5]
    

    只是说

    lazyarray(5)
    

    它会产生和数组一样的效果。

    编辑: 您甚至可以覆盖__getitem__ 方法,如here 所示,并根据我上面发布的代码拥有一个自定义生成器类。

    【讨论】:

    • 这解决了懒惰的部分,但不是扁平的部分,这是我真正需要帮助的这个问题的一部分。如果您在上面的代码中注意到,我已经大量使用了惰性求值,但是我需要将列表的惰性求值更改为单个元素的惰性求值。我并不是要粗鲁,但似乎您在发布之前没有按问题阅读或查看我的代码。
    • 很抱歉你有这种感觉。我提供了一种回答这篇文章的方法,即使我没有意识到这不是你想要的。我确实阅读了您的代码和问题,并尽我所能正确解释它。
    • 引用,你问“有没有办法让它变得更懒惰,一次只加载一个对象?”这是我试图解决的问题回答。我提供的是一个框架,可以让某些东西在执行中变得非常懒惰。遍历一个列表很容易,这里的关键是使它成为对列表的惰性求值。显然,要么我未能解释该帖子,要么您需要澄清您的问题。不过,我很高兴有人正确解释了它。
    • 问题不在于对列表的懒惰评估。问题特别是对已经被延迟评估的列表的延迟评估。非常关键的区别。一个用括号解决,另一个需要使用外部模块。你的反应是懒惰的,是的,但不是那么懒惰。我需要一些递归惰性的东西,而如果你的惰性数组中的元素是列表,你会遇到我最初提出的完全相同的问题。
    猜你喜欢
    • 2019-09-25
    • 2015-01-17
    • 2011-06-25
    • 1970-01-01
    • 2019-06-15
    • 2012-07-15
    • 2013-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多