简体   繁体   English

Python递归添加到类变量会产生不同的结果

[英]Python recursively adding to a class variable gives different results

class Perimeter:
    def __init__(self):
        super().__init__()
        self.count = 0
        self.grid = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]]
        self.seen = set()

    def perimeter_calculator(self, x: int, y: int) -> int:

        if self.grid[x][y] == 0:
            print(f"count: {self.count}")
            return 1

        if (x, y) not in self.seen:
            self.seen.add((x, y))

            a = self.perimeter_calculator(x + 1, y)
            b = self.perimeter_calculator(x - 1, y)
            c = self.perimeter_calculator(x, y + 1)
            d = self.perimeter_calculator(x, y - 1)

            self.count += a + b + c + d
        return 0

if __name__ == "__main__":
    perm = Perimeter()
    perm.perimeter_calculator(1, 1)
    print(perm.count)
    assert perm.count == 8

I'm working on leetcode problem 463 "Island Perimeter" ( https://leetcode.com/problems/island-perimeter/ ) and noticed some "Python" behavior I cannot explain when using a class variable.我正在处理 leetcode 问题 463 “Island Perimeter”( https://leetcode.com/problems/island-perimeter/ ),并注意到在使用类变量时我无法解释的一些“Python”行为。

The above function creates a simple 4x4 grid with a 2x2 island in the middle.上面的函数创建了一个简单的 4x4 网格,中间有一个 2x2 岛。 We start the search at (1, 1) and it should give 8 as the perimeter of that island.我们从 (1, 1) 开始搜索,它应该给出 8 作为该岛的周长。 If I run it like above everything is fine and the function returns 8 as expected.如果我像上面那样运行它,一切都很好,并且函数按预期返回 8。

If, however, I change the recursive call like so:但是,如果我像这样更改递归调用:

      self.count += self.perimeter_calculator(x + 1, y)
      self.count += self.perimeter_calculator(x - 1, y)
      self.count += self.perimeter_calculator(x, y + 1)
      self.count += self.perimeter_calculator(x, y - 1)

self.count is two in the end and somehow decreases within the recursive call (which can be seen with the print output). self.count 最后是 2,并且在递归调用中以某种方式减少(可以从打印输出中看到)。

Why is the result different when assigning the result of self.perimeter_calculator() directly to self.count instead of using the local variables a , b , c , and d as temporary storages?为什么将self.perimeter_calculator()的结果直接分配给self.count而不是使用局部变量abcd作为临时存储时,结果会有所不同? What is Python "doing under the hood"? Python“在幕后做什么”?

As @ThierryLathuille mentioned in the Python chat: https://chat.stackoverflow.com/transcript/message/54642897#54642897 the problem results from the way Python assigns values to the class variables when calling functions.正如@ThierryLathuille 在 Python 聊天中提到的那样: https ://chat.stackoverflow.com/transcript/message/54642897#54642897 问题源于 Python 在调用函数时为类变量赋值的方式。 Here is a simpler example from @Kevin highlighting that issue:这是@Kevin 的一个更简单的例子,强调了这个问题:

class Fred:
    def __init__(self):
        self.value = 0
    def f(self):
        self.value += self.h()
        print(self.value)
    def g(self):
        x = self.h()
        self.value += x
        print(self.value)
    def h(self):
        self.value += 1
        return 2

Fred().f() #2
Fred().g() #3

When calling f() , we add to the value self.value had before calling h()当调用f()时,我们添加到self.value调用h()之前的值

When calling g() , we use the value it had after calling h()调用g()时,我们使用调用h()后的值

When doing this recursively (as in the original example), I assume that Python overwrites the value within a deeper call stack, even leading to "decreasing" values of self.count .当递归地执行此操作时(如在原始示例中),我假设 Python 会覆盖更深调用堆栈中的值,甚至导致self.count的值“减少”。

Thank you @ThierreLathuille and @Kevin!谢谢@ThierreLathuille 和@Kevin!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM