【问题标题】:Short-circuiting a condition statement短路条件语句
【发布时间】:2021-01-05 02:59:20
【问题描述】:

我写了一个函数:

# given a n x m grid return how many different ways there are to move from top left to 
# bottom right by only being able to move right or down

def grid(n, m, memo = {}):
    if f'{n},{m}' in memo:
        return memo[f'{n},{m}']

    if n == 1 and m == 1:
        return 1
    
    if n == 0 or m == 0:
        return 0

    memo[f'{n},{m}'] = grid(n,m-1,) + grid(n-1,m)

    return grid(n,m-1,) + grid(n-1,m)

最近我读到了一些关于 Python 短路的内容,我正在尝试进一步理解它。

据我了解,它不会在运行时提供任何提升,只是一种语法糖。

例如:

1 < 2 < 3 # is True
1 < 2 and 2 < 3 # is also True

# hence
(1 < 2 < 3) == 1 < 2 and 2 < 3 # is True

我想知道我可以在if 语句中使用这种短路来编写我的函数吗?

我想出了这个:

 def grid(n, m, memo = {}):
    if f'{n},{m}' in memo:
        return memo[f'{n},{m}']

    if (n or m) == 1:
        return 1
    
    if (n and m) == 0:
        return 0

    memo[f'{n},{m}'] = grid(n,m-1,) + grid(n-1,m)

    return grid(n,m-1,) + grid(n-1,m)

这里有没有更聪明的方法来使用短路?

【问题讨论】:

  • if (n or m) == 1 绝对与if n == 1 or m == 1相同。
  • 那么如何写成这样:n 还是 m 等于 1?不使用n == 1 or m == 1?
  • 在下面查看我的答案。
  • 和测试:if n == 1 and m == 1:可以转换成if n == m == 1:
  • 1 &lt; 2 &lt; 3 不是short-circuiting,实际上是chaining,在某些方面有点相反。

标签: python


【解决方案1】:

(1 &lt; 2 &lt; 3) 不是短路 - 我认为您误解了该术语的含义。你是对的,它只是语法糖——尽管它在晦涩的情况下会产生一些非常奇怪的结果。 (1 &lt; 2 &lt; 3) 扩展为 (1 &lt; 2) and (2 &lt; 3) - 中间操作数被复制到两者,and 用于连接运算符。

当python已经知道布尔表达式的答案时,甚至在计算两个输入之前,就会发生短路。例如

def false():
    print("false")
    return False

def true():
    print("true")
    return True

print(false() and true())

输出将是

false
False

因为当python看到False and时,它已经知道结果是False(因为and要求两个操作数都是True),所以它不会费心去跑下半行。 这种真正的短路确实会导致性能提升,但是由于您无法关闭短路,所以这并不重要¯\_(ツ)_/¯

【讨论】:

  • 你在自相矛盾...(1 &lt; 2 &lt; 3) 扩展为(1 &lt; 2) and (2 &lt; 3) 所以有短路...如果1 &lt; 2 , 那么2 &lt; 3 将根本不会被评估...而且 - 从docs: "x &lt; y &lt;= z 等效于x &lt; y and y &lt;= z,除了 y 只评估一次(但在这两种情况下,当发现x &lt; y 为假时,根本不会评估 z" - 所以这是您的改进,而不仅仅是语法糖...
  • 好吧,这很公平。几周前我确实读过它,但我忘记了。
【解决方案2】:

if (n or m) == 1if n == 1 or m == 1 绝对不是一回事。第一个if 语句相当于:

value = n
if not value:
    value = m
if value == 1:
    # do something:

或者更简洁的表达方式:

if (n if n else m) == 1:
       # do something

换句话说,n or m 仅在 n 为 False 时计算 m(如果 n 为整数则为 0),否则表达式的结果为 n

您要避免冗余的是:

if 1 in (n, m): # equivalent to: if 1 is either n or m:

更新:演示

n = 4
m = 1
if (n or m) == 1:
    print('if branch taken')
else:
    print('else branch taken')

打印:

else branch taken

【讨论】:

  • 我相信在我的情况下我使用了(n or m) == 1 是正确的,这与If either n or m is 1: do something 不一样。因为(1 or 0) (0 and 1) 都返回1,我将其与1 进行比较?
  • 我说的是任意值 n 和 m 的一般情况。如果你知道 n 和 m 的值,为什么还要费心写一个 if 语句呢?那么整个问题就变得毫无意义了。
  • 等价地,if n == 1 and m == 1: 可以是if (m, n) == (1, 1):(或m == n == 1...)
  • 因为mn 只能是整数,我只关心其中任何一个是否为1,如果是,则返回1。所以if (n or m) == 1: return 1 返回我1,如果mn 是 1,这是我需要的。还是我错过了什么?
  • @JonasPalačionis 如果 n 为 4 且 m 为 1,则 (n or m) 的计算结果为 4,这将 等于 1,并且 if 表达式的计算结果为False。你肯定错过了一些东西。再读一遍我的答案。
【解决方案3】:
if (n or m) == 1

评估为

if (<bool>) == 1  # e.g. if {True,False} == 1

这可能不是您想要的,因为它本质上是在评估 nm 的真实性。

您现有的代码already captures the nature of short-circuiting;

if n == 1 and m == 1

只会评估第二个参数m == 1 iff n == 1,否则会短路。

给你的评论

据我了解,它不会在运行时提供任何提升,只是一种语法糖。

嗯,实际上,如果 Python 能够跳过评估原本会“昂贵”的条件来评估,它确实提供了运行时提升,因为它能够提前短路。

【讨论】:

    猜你喜欢
    • 2021-08-20
    • 1970-01-01
    • 2013-02-15
    • 2016-06-17
    • 2013-08-23
    • 2012-09-14
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多