【问题标题】:Difference between writing something on one line and on several lines单行写和多行写的区别
【发布时间】:2015-12-03 15:16:27
【问题描述】:

当我用, 和两行分隔的一行写一些东西时,区别在哪里。显然我不明白其中的区别,因为我虽然下面的两个函数应该返回相同的结果。

def fibi(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
    return a

print(fibi(6))
> 8 # expected result (Fibonacci)

但是

def fibi(n):
    a, b = 0, 1
    for i in range(n):
        a = b
        b = a + b 
    return a


print(fibi(6))
> 32 

【问题讨论】:

  • a = b; b = a + b 等价于a = b; b = b + b

标签: python


【解决方案1】:

这是因为 Python 的元组解包。在第一个中,Python 收集右侧的值,使它们成为一个元组,然后将元组的值分别分配给左侧的名称。所以,如果 a == 1 和 b == 2:

   a, b = b, a + b
=> a, b = (2, 3)
=> a = 2, b = 3

但在第二个例子中,这是正常的赋值:

   a = b
=> a = 2
   b = a + b
=> b = 4

【讨论】:

  • 哇哦。不知道 Python 会这样做。很好的解释。谢谢!
【解决方案2】:

寻找替代品

a, b = b, a + b

你必须意识到这个任务是“逐步”完成的。

所以它的等价物是

old_a = a
a = b
b = old_a + b # note the old_a here, as a has been replaced in the meanwhile.

演示:

def fibi(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
    return a

def fibi2(n):
   a, b = 0, 1
   for i in range(n):
    old_a = a
    a = b
    b = old_a + b
   return a

>>> fibi(0)
0
>>> fibi(1)
1
>>> fibi(2)
1
>>> fibi(3)
2
>>> fibi(4)
3
>>> fibi(5)
5
>>> fibi(6)
8
>>> fibi(7)
13
>>>
>>>
>>>
>>> fibi2(0)
0
>>> fibi2(1)
1
>>> fibi2(2)
1
>>> fibi2(3)
2
>>> fibi2(4)
3
>>> fibi2(5)
5
>>> fibi2(6)
8
>>> fibi2(7)

【讨论】:

  • 注意:像你写的那样写它返回8和fibi(5),而它应该返回5。
  • @Chrissl 如果完全按照上面的方式使用并替换上面的行,它就像一个魅力......
【解决方案3】:

你的不同之处在于:

1)

>>> a, b = 0, 1
>>> a, b = b, a+b
>>> a
1
>>> b
1

对比:

2)

>>> a, b = 0, 1
>>> a = b
>>> b = a+b
>>> a
1
>>> b
2

在第一种情况下,a = 1b = 0 + 1 在变量值发生更改之前。您基本上是在说“(a,b) 在给定状态 X 下,将 (a,b) 设置为值 (0,1)。”

查看此类差异的一个好方法是使用disassembly 模块(点击链接查看代码的含义):

>>> from dis import dis
>>> a, b = 0, 1
>>> dis('a, b = b, a+b')
  1           0 LOAD_NAME                0 (b)
              3 LOAD_NAME                1 (a)
              6 LOAD_NAME                0 (b)
              9 BINARY_ADD
             10 ROT_TWO
             11 STORE_NAME               1 (a)
             14 STORE_NAME               0 (b)
             17 LOAD_CONST               0 (None)
             20 RETURN_VALUE
>>> a, b = 0, 1
>>> dis('a = b; b = a+b')
  1           0 LOAD_NAME                0 (b)
              3 STORE_NAME               1 (a)
              6 LOAD_NAME                1 (a)
              9 LOAD_NAME                0 (b)
             12 BINARY_ADD
             13 STORE_NAME               0 (b)
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE

【讨论】:

    【解决方案4】:

    不同之处在于,在第二个示例中,您在引用 a 之前将 a 设置为 b。您在第二个示例中的值将关闭。这是一个例子:

    a = 5
    b = 6
    

    例 1:

    a, b = b, a+b // a = 6 and b = 11
    

    例 2:

    a = b // a = 6
    b = a + b // b = 6+6 or 12
    

    第一个例子是正确的

    【讨论】:

      【解决方案5】:

      可以在 33:13 到 38:17 之间的 PyCon 2013 视频中找到 Raymond Hettinger 的完美解释:

      https://www.youtube.com/watch?v=OSGv2VnC0go

      引用他的演讲:

      • 不要低估同时更新状态变量的优势
      • 消除由于无序更新导致的一整类错误

      【讨论】:

        【解决方案6】:

        在第一种情况下,命令

        a, b = b, a + b;
        

        将首先进行总和a + b,然后进行分配。在这种情况下,b 总是包含 1。这就解释了为什么最终结果是 6,因为您将 1 加了六次。

        您发布的第二个代码是正确的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-07
          • 2015-10-24
          • 2015-03-07
          • 1970-01-01
          • 2014-10-23
          • 1970-01-01
          相关资源
          最近更新 更多