Python中的变量重赋值--本体查询--使用牛顿法

Variable Reassignment in Python-- ontological query -- using Newton Method

我正在使用 Python 阅读 Miller 和 Ranum 关于算法和数据结构的书。他们使用以下示例:

def squareroot(n):
    root = n/2
    for k in range(20):
        root = (1/2)*(root + n / root)

    return root 

我的问题是,变量 'root' 在 for 循环中被重新赋值,因此随着每次迭代,赋值运算符右侧表达式中 'root' 的值都会发生变化。我不确定我明白这是怎么可能的。

一旦进行了函数调用,for 循环外的 'root' 变量(第 2 行)的计算结果为一个值,然后由表达式中的 'root' 变量引用for 循环块的,允许表达式计算为单个值,该值被重新分配给变量 'root',在 for 循环块中赋值运算符的左侧。在下一次迭代开始时,'root' 不再是 n/2,而是 for 循环中的表达式求得的任何值。在这种情况下,变量 'root' 已被重新分配了一个浮点值,因此不再是它最初定义的值——一个使用 'root' 变量的表达式。

例如,如果我们使用函数调用 squareroot(9),'root' 将在第一次迭代后保持值 3.25,因为 for 循环中的表达式求值为该值。一旦 for 循环中的变量 'root' 被重新分配了一个浮点值,最初定义 'root' 的表达式将被销毁。 'root' 已被重新定义为 3.25。 'root',在for循环中,不再指代一个表达式,而是指一个单一的浮点值。然而,在这个例子中,for 循环中的 'root' 变量在每次迭代后似乎有两个含义:它既是浮点值又是表达式。我不明白怎么会这样。

简短的回答是 Python 不将表达式视为抽象公式;它将其视为要执行的一系列具体计算。每次通过循环,它都会用 root 的当前值执行这些计算,然后使用结果更新 root 的值。查看 Python 执行的实际操作顺序可能会有所帮助,如下所示:

import dis
def squareroot(n):
    root = n/2
    for k in range(20):
        root = 0.5 * (root + n / root)
    return root
dis.dis(squareroot)

结果:

  2           0 LOAD_FAST                0 (n)
              3 LOAD_CONST               1 (2)
              6 BINARY_DIVIDE       
              7 STORE_FAST               1 (root)

  3          10 SETUP_LOOP              38 (to 51)
             13 LOAD_GLOBAL              0 (range)
             16 LOAD_CONST               2 (20)
             19 CALL_FUNCTION            1
             22 GET_ITER            
        >>   23 FOR_ITER                24 (to 50)
             26 STORE_FAST               2 (k)

  4          29 LOAD_CONST               3 (0.5)
             32 LOAD_FAST                1 (root)
             35 LOAD_FAST                0 (n)
             38 LOAD_FAST                1 (root)
             41 BINARY_DIVIDE       
             42 BINARY_ADD          
             43 BINARY_MULTIPLY     
             44 STORE_FAST               1 (root)
             47 JUMP_ABSOLUTE           23
        >>   50 POP_BLOCK           

  5     >>   51 LOAD_FAST                1 (root)
             54 RETURN_VALUE        

有趣的部分是以 4 开头的块,它对应于您询问的作业。事情是这样的:

  • 将以下内容加载到堆栈上:[0.5,root 的当前内容,n 的当前内容,root 的当前内容。在第一次迭代期间(n=9),堆栈现在将保存 [0.5, 4.5, 9.0, 4.5].
  • 将堆栈中的倒数第二项除以最后一项,并将结果放入堆栈:堆栈现在为 [0.5, 4.5, 2.0]
  • 将最后两项添加到堆栈中并将结果放入堆栈中:堆栈现在是 [0.5, 6.5]
  • 将堆栈中的最后两项相乘并将结果放入堆栈中:堆栈现在是 [3.25]
  • 将堆栈中的最后一项 (3.25) 存储在变量 root 中。

因此,如您所见,表达式仅表示要遵循的一系列步骤。在这些步骤结束时,结果将存储到 root。然后可以使用 root.

的新值再次执行这些步骤