【问题标题】:Conditional expression/ternary operator条件表达式/三元运算符
【发布时间】:2019-02-10 16:30:31
【问题描述】:

我不懂这个语法。

演示三元运算符的Python程序

a, b = 10, 20

使用元组选择项目

print( (b, a) [a < b] )

使用字典选择项目

print({True: a, False: b} [a < b])

PS:我猜这是来自旧版本的 Python,因为在较新的版本中(不知道来自哪个版本)True 和 False 是保留关键字,所以它们不能被赋值。

lamda 比以上两种方法效率更高 因为在 lambda 中,我们保证只有一个表达式将被评估,这与 元组和字典

print((lambda: b, lambda: a)[a < b]())

语法应该是:

[on_true] if [表达式] else [on_false]

那么如何

print( (b, a) [a < b] )
print({True: a, False: b} [a < b])
print((lambda: b, lambda: a)[a < b]())

适合这种语法吗? tuple/dictionary/lambda 后面的[a&lt;b] 是什么意思?我以前从未见过这种语法。当列表 [b, a] 位于 [a&lt;b] 之前时,它也有效。

我希望它看起来像这样

print( a if a < b else b )

资源链接: https://www.geeksforgeeks.org/ternary-operator-in-python/

【问题讨论】:

  • TrueFalse 没有被赋值;它们只是被用作dict 的键。
  • 确实如此。我还没有意识到这只是一个键而不是分配。
  • 这些是替代语法,而不是 [on_true] if [expression] else [on_false]。他们利用foo = {1: "one"}print( foo[1] )可以直接写成print( {1: "one"}[1] )的事实。
  • 关于 lambdas 更高效的评论也值得怀疑。构造两个function 对象并随后调用其中一个对象可能比首先简单地评估ab 更昂贵(无论如何计算a &lt; b,所以整个构造有点低效)。

标签: python ternary-operator conditional-operator


【解决方案1】:

首先请注意,所有这些都给出了ab最小 值:

a, b = 10, 20

res1 = (b, a)[a < b]                    # 10
res2 = {True: a, False: b}[a < b]       # 10
res3 = (lambda: b, lambda: a)[a < b]()  # 10

我们可以依次考虑这些:

  1. res1 构造一个由 2 个整数组成的 tuplea &lt; b 返回一个布尔值,在本例中为 True。在 Python 中,True == 1,因为boolint 的子类。最后,[]__getitem__ 的语法糖,这是调用位置索引的方法。由于 Python 从0 开始计数,所以第一个索引是a。您也可以自己确认:(b, a).__getitem__(1) 返回10
  2. res2 构造一个字典,将布尔值映射到 ab。在 dict 对象上调用 __getitem__ 会返回给定键的值。和以前一样,这里的关键是True。由于字典将True 映射到a,因此这是返回的值。
  3. res3 构造一个匿名 (lambda) 函数元组,每个函数返回标量,即 ba。根据res1,可以通过整数索引从元组中提取项目。唯一的附加要求是通过() 实际调用lambda 函数。

请注意,这些操作都与ternary operator 的操作方式相同,后者在编译时(参见 cmets)通过内联 if / else 应用:

res4 = a if a < b else b

【讨论】:

  • “编译时应用三元运算符”是什么意思?它是在运行时评估的真实条件(例如,与 C 预处理器 #ifdef 不同)。
  • @alexis,Python 文件在技术上是 compiled to bytecode。然后在 CPython 中解释字节码。你是对的,如果我理解你的意思,机器代码没有编译。
  • 不,那会让人毛骨悚然。我的意思是更相关的东西:编译时条件根据程序被读取/预处理/编译时的真实情况选择一个分支。例如,#if OS == "darwin" 然后将始终遵循相同的分支——实际上,条件不再存在。但是 Python 三元组是一个真实的 if,并且每次程序流遇到它时都会重新评估(有时为真,有时为假)。
【解决方案2】:

a&lt;bboolTrueFalse)。由于boolint 的子类型,因此它可以在需要整数的上下文中使用,例如作为列表/元组索引:

>>> True == 1
True
>>> False == 0
True
>>> isinstance(True, int)
True
>>> ('a', 'b')[True]  # True == 1
'b'
>>> ('a', 'b')[1<2]  # 1<2 == True == 1
'b'
>>> ('a', 'b')[2<1]  # 2<1 == False == 0
'a'

对于dict 键,类似,但甚至不需要类型强制:

>>> {True: 'a', False: 'b'}[1<2]  # 1<2 == True
'a'

【讨论】:

    【解决方案3】:

    您的误解可能是关于 a

    在所有这些情况下,评估 a

    如果是

    print( (b, a) [a < b] )
    

    print((lambda: b, lambda: a)[a < b]())
    

    对象是一个元组,包含变量本身或非常简单的匿名函数,它们返回这些变量。

    如果是

    print({True: a, False: b} [a < b])
    

    表达式被评估并用作字典的键,该字典具有 True 和 False 作为键。假设这意味着它必须是较旧的 Python 版本是不正确的,因为字典不代表值的重新分配,而只是一个数据结构,其中键映射到值。 True 和 False 是有效的键,这种情况正是这里使用的。

    最后:

     print( a if a < b else b )
    

    表达同样的事情和实际上我将在这种情况下使用的代码行是一种简洁的方式

    【讨论】:

      猜你喜欢
      • 2014-09-15
      • 2020-03-30
      • 2012-07-03
      • 1970-01-01
      • 2020-11-24
      • 1970-01-01
      • 1970-01-01
      • 2012-09-02
      • 2015-01-29
      相关资源
      最近更新 更多