python 试图理解调用堆栈
python trying to understand callstacks
我正在尝试理解下面代码的调用堆栈,但我无法回答。
为什么这一行 return 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)
这是因为变量 x 和 z 是不可变的。
在 python 中,当我们将不可变参数传递给函数时,通过引用调用不再适用。
一旦我们更改此类变量的值,函数就会创建自己的副本,即局部变量。这就是背后的原因。
Please refer this for more information
我想你需要知道的是函数内部的变量与函数外部的变量是不同的。或者更准确地说,每次调用函数时,都会为该函数调用创建一组新变量,与可能碰巧具有相同名称的其他任何变量无关。 (除了极少数例外。)所以,例如,如果你写
def f1(x):
x = x + 1
return x
x = 1
x = f1(x)
x = f1(x)
print(x)
实际上有三个单独的变量名为 x
:有一个在顶层 ("global"),它被初始化为 1,为第一次调用 [=18 创建的=],以及为第二次调用 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)
从这里您可以看到不同的变量是如何分开的,即使它们在代码中具有相同的名称。每个变量都有自己的 "area" 种类,其中名称指的是该变量,而在不同的 "area" 中,相同的名称指的是不同的变量。这叫做scoping.
我提到过有一些例外。这里有两个比较常见的:
Python 允许您在函数内部放置一个 "global declaration" 当您希望该名称在函数内部和函数外部引用相同的事物时。因此,如果我这样定义 f2
:
def f2():
global x
x = x + 1
return x
那么就不会有 x
的特定功能 ("local") 版本。它只会使用全局 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
我正在尝试理解下面代码的调用堆栈,但我无法回答。
为什么这一行 return 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)
这是因为变量 x 和 z 是不可变的。
在 python 中,当我们将不可变参数传递给函数时,通过引用调用不再适用。
一旦我们更改此类变量的值,函数就会创建自己的副本,即局部变量。这就是背后的原因。
Please refer this for more information
我想你需要知道的是函数内部的变量与函数外部的变量是不同的。或者更准确地说,每次调用函数时,都会为该函数调用创建一组新变量,与可能碰巧具有相同名称的其他任何变量无关。 (除了极少数例外。)所以,例如,如果你写
def f1(x):
x = x + 1
return x
x = 1
x = f1(x)
x = f1(x)
print(x)
实际上有三个单独的变量名为 x
:有一个在顶层 ("global"),它被初始化为 1,为第一次调用 [=18 创建的=],以及为第二次调用 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)
从这里您可以看到不同的变量是如何分开的,即使它们在代码中具有相同的名称。每个变量都有自己的 "area" 种类,其中名称指的是该变量,而在不同的 "area" 中,相同的名称指的是不同的变量。这叫做scoping.
我提到过有一些例外。这里有两个比较常见的:
Python 允许您在函数内部放置一个 "global declaration" 当您希望该名称在函数内部和函数外部引用相同的事物时。因此,如果我这样定义
f2
:def f2(): global x x = x + 1 return x
那么就不会有
x
的特定功能 ("local") 版本。它只会使用全局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