Python中的“惰性”列表项评估

时间:2018-11-05 23:01:51

标签: python lambda lazy-evaluation f-string

由于缺少更好的词,我选择了这个标题。

我想要做的是这样的事情:

>>> from random import randint
>>> fruits = [
...     "Orange",
...     "Banana",
...     f"{randint(2,5)} Cherries",
... ]

>>> fruits[2]
'3 Cherries'

>>> fruits[2]
'5 Cherries'

>>> fruits[2]
'2 Cherries'

但是,相反,字符串内部的文字表达式在创建列表后就被求值一次,并且每次访问它时都得到相同的结果。

我想知道,除了编写一些复杂的边缘案例处理(我们毕竟是程序员;谁不喜欢编写漂亮的代码,又不失优雅和幻想?),是否还有一种更简单/更智能的方法来实现此目的。 我说边缘情况处理是因为49个字符串中只有6个需要这种“特殊”行为。

到目前为止,我一直在尝试从randint调用中创建一个lambda函数,但这没有帮助;同样的结果。 也许这是懒惰评估的一种情况,但是我需要一些关于如何(或是否?)将其与列表一起使用的指导。

4 个答案:

答案 0 :(得分:6)

如果您希望商品的一部分是文字的,但有些是可调用的,则可以创建自己的list版本:

from random import randint

class LazyList(list):
    'Like a list, but invokes callables'
    def __getitem__(self, key):
        item = super().__getitem__(key)
        if callable(item):
            item = item()
        return item

fruits = LazyList([
    "Orange",
    "Banana",
    lambda: f"{randint(2,5)} Cherries",
])

print(fruits[2])
print(fruits[2])

答案 1 :(得分:3)

您在正确的轨道上,需要一个lambda:

from random import randint

fruits = [
        lambda: "Orange",
        lambda: "Banana",
        lambda: f"{randint(2, 5)} Cherries",
]

print(fruits[2]())
print(fruits[2]())
print(fruits[2]())

有很多方法可以使()消失,但这可能不值得。

答案 2 :(得分:0)

首先将lambda放入列表中听起来不错,但是随后您必须调用列表中的这个特殊(或所有)索引。您无法迭代列表,无法对列表进行排序,...

创建一个为您提供列表的函数更容易:

from random import randint

def gimme_fruits ():
    return [ "Orange", "Banana", f"{randint(2,5)} Cherries",]

print(gimme_fruits())

输出:

['Orange', 'Banana', '3 Cherries']

['Orange', 'Banana', '4 Cherries']

['Orange', 'Banana', '2 Cherries']

每个列表的樱桃数量都是固定的-但您可以这样做:

for f in gimme_fruits() + gimme_fruits() + gimme_fruits():
    print(f)

获取维生素:

Orange
Banana
3 Cherries
Orange
Banana
3 Cherries
Orange
Banana
3 Cherries

答案 3 :(得分:0)

免责声明:我是图书馆的作者

您可以使用seqtools进行延迟映射,它支持迭代和切片:

>>> fruits = seqtools.smap(lambda x: x if isinstance(x, str) else x(), 
...                        fruits)
>>> fruits[0]
'Orange'
>>> fruits[-1]
'3 Cherries'

如果不想在每次调用时重新评估功能元素,则可以添加一些缓存:

fruits = seqtools.add_cache(fruits)

项目分配显然无法通过映射进行工作,因此您将不得不自己动手做。

排序将最终评估列表中的所有项目,因此您也可以预先进行评估并调用常规list.sort()方法。