由于缺少更好的词,我选择了这个标题。
我想要做的是这样的事情:
>>> 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函数,但这没有帮助;同样的结果。 也许这是懒惰评估的一种情况,但是我需要一些关于如何(或是否?)将其与列表一起使用的指导。
答案 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()方法。