Ahm*_*fi' 8 python recursion pass-by-reference
第一次在这里提问,所以请强调我的错误。
我正在研究一些 Leetcode,并在 Python 中遇到了一种行为(与问题无关),我无法完全弄清楚也无法通过谷歌搜索。这特别困难,因为我不确定我是否缺乏理解:
+=或一般变量赋值这是简化的代码:
class Holder:
def __init__(self, val=0):
self.val = val
class Solution:
def runThis(self):
holder = Holder()
self.diveDeeper(holder, 5)
return
def diveDeeper(self, holder, n):
if n==0:
return 1
# 1) Doesn't result in mutation
holder.val += self.diveDeeper(holder, n-1)
# 2) Also doesn't result in mutation
# holder.val = holder.val + self.diveDeeper(holder, n-1)
# 3) !! Results in mutations
# returnVal = self.diveDeeper(holder, n-1)
# holder.val += returnVal
print(holder.val)
return 1
a = Solution()
a.runThis()
Run Code Online (Sandbox Code Playgroud)
所以,是的,我的主要困惑来源是(1)和(3)在语义上对我来说看起来相同,但导致了两个完全不同的结果:
================ RESTART: Case 1 ===============
1
1
1
1
1
>>>
================ RESTART: Case 3 ===============
1
2
3
4
5
>>>
Run Code Online (Sandbox Code Playgroud)
从(2)来看,它似乎与操作员无关+=,为了简洁起见,我没有包含我尝试过的数十种变体,但到目前为止它们都没有给我任何线索。非常感谢任何正确方向的指示(特别是万一我在工作面试中措手不及,lmao)
PS:如果这是相关的,我正在使用Python 3.8.2
你让我有点挣扎,但答案很简单。让我重新解释一下为什么会发生这种情况。
holder.val = holder.val + self.diveDeeper(holder, n - 1) # prints 1 1 1 1 1
holder.val = self.diveDeeper(holder, n - 1) + holder.val # prints 1 2 3 4 5
Run Code Online (Sandbox Code Playgroud)
我希望你现在明白发生了什么 - 如果+=它评估为第一个变体。在每个递归步骤中,holder.val执行该行时将为 0。这就是为什么我们将分配 5 次holder.val = 0 + 1。
改变顺序后,我们首先进行变异holder.val,然后用它来计算新的。通过引用传递按预期工作。
在 Python 中,如果有expression1() + expression2(),expression1()首先被求值。
所以 1 和 2 实际上相当于:
left = holder.val
right = self.diveDeeper(holder, n - 1)
holder.val = left + right
Run Code Online (Sandbox Code Playgroud)
现在,holder.val仅在递归调用之后修改,但您使用递归调用之前的值,这意味着无论迭代如何,left == 0.
您的解决方案 3 相当于:
right = self.diveDeeper(holder, n - 1)
left = holder.val
holder.val = left + right
Run Code Online (Sandbox Code Playgroud)
因此,递归调用是在left = holder.val求值之前进行的,这意味着left现在是上一次迭代的总和的结果。
这就是为什么你必须小心可变状态,你必须完全理解操作的顺序。