【问题标题】:python trying to understand callstackspython试图理解调用堆栈
【发布时间】:2018-06-30 03:12:41
【问题描述】:

我正在尝试理解下面代码的调用堆栈,我无法回答。

为什么这行返回4:

7. return z

为什么是第 5 行:

16 x = x + m1(x) 

希望你能帮助我。

1  def m1(x): 
2      x = x + 1
3      z = m2(x, 4)
4      x = x + 1
5      z = z + 1
6      print(x)
7      return z
8 
9  def m2(x, y):
10     x = x + 1
11     y = y + 1
12     print(x, y)
13     return x
14
15 x = 1
16 x = x + m1(x)

【问题讨论】:

    标签: python callstack


    【解决方案1】:

    我怀疑您需要知道的是函数内部的变量与函数外部的变量不同。或者更准确地说,每次调用函数时,都会为该函数调用创建一组新变量,与其他任何可能碰巧具有相同名称的变量无关。 (极少数例外。)因此,例如,如果您写了

    def f1(x): 
        x = x + 1
        return x
    
    x = 1
    x = f1(x)
    x = f1(x)
    print(x)
    

    实际上存在三个名为x 的独立变量:一个位于顶层(“全局”),初始化为 1,一个为第一次调用 f1 而创建,另一个为第二次拨打f1。如果您注释它们的名称以将它们彼此区分开来,那么实际上会发生以下情况:

    x_global = 1
    
    # Python does this behind the scenes
    f1_call1_argument1 = x_global
    # call f1
    x_f1_call1 = f1_call1_argument1
    # now your code in f1 starts running
    x_f1_call1 = x_f1_call1 + 1
    f1_call1_return_value = x_f1_call1
    # return from f1
    x_global = f1_call1_return_value
    
    # now repeat but with the second call to f1
    f1_call2_argument1 = x_global
    x_f1_call2 = f1_call2_argument1
    x_f1_call2 = x_f1_call2 + 1
    f1_call2_return_value = x_f1_call2
    x_global = f1_call2_return_value
    
    print(x_global)
    

    从这里您可以看到不同的变量是如何分开的,即使它们在代码中具有相同的名称。每个变量都有自己的“区域”,其中名称指的是该变量,而在不同的“区域”中,相同的名称指的是不同的变量。这称为scoping


    我提到有一些例外。以下是两个比较常见的:

    • 当您希望该名称在函数内部引用与函数外部相同的事物时,Python 允许您在函数内部放置一个“全局声明”。所以如果我这样定义f2

      def f2():
          global x
          x = x + 1
          return x
      

      那么就没有x 的特定功能(“本地”)版本。它只会使用全局x。运行这段代码

      x = 1
      x = f2()
      x = f2()
      

      会这样工作:

      x_global = 1
      
      # call f2
      x_global = x_global + 1
      f2_call1_return_value = x_global
      # return from f2
      x_global = f2_call1_return_value
      
      x_global = x_global + 1
      f2_call2_return_value = x_f1_call2
      x_global = f2_call2_return_value
      
    • 您还可以为参数设置默认值,并且由于 Python 实现方式的设计决定,默认值有效地存储在一个不可见的变量中,该变量在函数调用之间持续存在。如果我有

      def f3(x=[]):
          x.append(5)
          return x
      
      x = [1]
      x = f3()
      x = f3()
      

      (我使用列表是因为它可以更改,但整数不能)然后它的工作方式如下:

      # as part of the definition of f3
      f3_argument1_default = []
      
      x_global = [1]
      
      # first call to f3
      f3_call1_argument1 = f3_argument1_default
      x_f3_call1 = f3_call1_argument1
      x_f3_call1.append(5)                      # f3_argument1_default is now  [1,5]
      f3_call1_return_value = x_f3_call1
      x_global = f3_call1_return_value
      
      # second call to f3
      f3_call2_argument1 = f3_argument1_default
      x_f3_call2 = f3_call2_argument1
      x_f3_call2.append(5)                      # f3_argument1_default is now  [1,5,5]
      f3_call2_return_value = x_f3_call2
      x_global = f3_call2_return_value
      

    【讨论】:

      【解决方案2】:

      这是因为变量 x 和 z 是不可变的。
      在 python 中,当我们将不可变的参数传递给函数时,引用调用不再适用。
      一旦我们更改了此类变量的值,函数就会创建自己的副本,即局部变量。这就是背后的原因。
      Please refer this for more information

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-05
        • 1970-01-01
        • 2016-12-13
        • 1970-01-01
        • 1970-01-01
        • 2013-08-08
        • 2021-03-16
        • 1970-01-01
        相关资源
        最近更新 更多