奇怪的行为:函数中的三元运算符

9
下面是与我的问题相关的简化示例。我认为这些函数应该具有完全相同的行为:
def f1(l):
    if type(l[0][0])==list: f=lambda x:x[0][0]
    else: f=lambda x:x[0]
    l.sort(key=f,reverse=True)

def f2(l):
    f=lambda x:x[0][0] if type(l[0][0])==list else lambda x:x[0]
    l.sort(key=f,reverse=True)

l=[[1,2],[3,4]]

但实际上,当f2(l)发生异常时,f1(l)仍然可以正常工作:

IndexError: list index out of range

那么问题是为什么会这样,是否可能使用返回其中一个函数的三元运算符?


1
这有点离题,但也许这是那种情况之一,lambda 使得事情变得更难读而不是更容易。怎么样使用 def getKey(x): 来检查 x 并返回 x[0]x[0][0] 或者你需要的任何东西?然后使用 l.sort(key=getKey,reverse=True) - Asad Saeeduddin
@Asad 是的,那是一个很好的观点,尽管它可能比原始版本运行得慢一些。 - Nik
我不确定为什么它会更慢。 它避免了每次调用f1f2时都要创建函数的开销,因此如果有什么区别,它可能会(微不足道地)更高效。 无论如何,我不认为这种差异值得担心。 - Asad Saeeduddin
@Asad 我的评论基于一种假设,即原始方法每次调用只进行一次决策,然后使用其中一个 lambda 作为 key,而 getkey 方法则检查列表中的每个元素,并且每次都做出相同(冗余)的决策。我进行了一些测试。测试结果显示原始方法大约比 getkey 方法快2倍。虽然对于我的任务来说这并不太重要。在这种情况下,我投票支持可读性。 - Nik
啊,是的,你说得对。在这种情况下,你可以从getKey返回正确的lambda,并且使用l.sort(key=getKey(l),reverse=True) - Asad Saeeduddin
1个回答

8

lambda 在运算符中的优先级是最低的。这就是为什么 Python 将该行解析为

f = lambda x: (x[0][0] if type(l[0][0]) == list else lambda x: x[0])

解决方法是用括号将单个的lambda包裹起来:
f = (lambda x: x[0][0]) if type(l[0][0]) == list else (lambda x: x[0])

话虽如此,type(l[0][0]) == list有点不正确,isinstance(l[0][0], list)是最好的方法(它还处理了list的子类)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接