【发布时间】:2022-01-22 10:17:04
【问题描述】:
我想知道 python 在定义列表/元组之后评估切片/索引是否有原因?
(这个问题与 Python Code Golf 有关,所以我知道它不可读或“良好做法”,它只是关于可接受的语法和语言的基本行为。)
我们可以使用索引来模拟三元运算符的行为:
a if x > 9 else b
(b,a)[x>9] # way shorter
但这有一个问题:元组的内容在索引中的条件之前被评估。
我创建了一个示例来说明这一点:一个函数f,它递归地将字符串的大小减一,直到字符串为空,然后返回0
f = lambda s: f(s) if len(s:=s[:-1]) else 0
print(f("abc")) # works fine
f = lambda s: (0, f(s))[len(s:=s[:-1])==0]
print(f("abc")) # max recursion depth error
出现递归深度错误是因为在索引之前评估元组定义。这意味着切片/索引中的内容无关紧要,该函数将被一遍又一遍地调用。
我真的不明白为什么 python 之前不评估切片/索引,因为即使是像下面这样的明显情况也会失败:
f = lambda: (0, f())[0]
f() # max recursion depth error
最重要的是,如果我们只评估我们想要从数组中获取的单个元素(或切片)而不是每个单个元素,它可能会在内存使用和运行时间方面受益:
x = 2
print([long_computation(), other_long_computation(), 0][x])
有什么理由不在元组定义之前评估切片/索引吗?
【问题讨论】:
-
你不能切片还不存在的东西。 (另外,这是索引,而不是切片。)
-
@user2357112supportsMonica 是的,它更多的是关于索引 :) 元组可以存在但不评估其元素,有点像
f = lambda s: (lambda: 0, lambda: f(s))[len(s:=s[:-1])==0]()那样有效 -
所以你真的想要一个对其成员进行惰性求值的元组吗?在 Python 中可能有一种方法可以做到这一点,但我不知道怎么做,而且肯定不值得麻烦。
-
@MarkRansom 是的,当
[...]index/slice 直接跟随时,我想要惰性元组评估,因为我不明白为什么要评估其余部分,因为它会被切片留下,评估切片后直接保留元素会发生 -
但这仅对代码高尔夫有用,这是 Python 开发团队无意鼓励的用例。对于不打代码的人来说,它只会增加语言的复杂性和奇怪的边缘情况。