如何查找在就地修改时具有多个引用的Python对象

如何查找在就地修改时具有多个引用的Python对象,python,Python,是否有任何通用策略(调试或代码分析)来查找大型python项目中可能被多次引用和修改的对象/类属性 背景: 在Python中,创建对同一对象的多个引用非常容易——如果不知道这一点,这可能会导致非常令人惊讶的事情。虽然我知道这一事实在我最早的Python测试中就已经存在,但实际上我并没有对此多想。直到上周我遇到了一个非常严重的bug,它是由一个就地操作引起的,几年前我把它放进了我的代码中,这时我从来没有意识到,如果我以后再次引用同一个对象,它可能会出问题(当时不记得它可能在其他地方被就地修改了…)

是否有任何通用策略(调试或代码分析)来查找大型python项目中可能被多次引用和修改的对象/类属性

背景:

在Python中,创建对同一对象的多个引用非常容易——如果不知道这一点,这可能会导致非常令人惊讶的事情。虽然我知道这一事实在我最早的Python测试中就已经存在,但实际上我并没有对此多想。直到上周我遇到了一个非常严重的bug,它是由一个就地操作引起的,几年前我把它放进了我的代码中,这时我从来没有意识到,如果我以后再次引用同一个对象,它可能会出问题(当时不记得它可能在其他地方被就地修改了…)

假设一个类,如:

class A:
    _x = None
    n = 0
    def set_range(self,n):
        self.n = n
        self._x = list(range(n))

    def get_range(self):
        return self._x

    def get_range_extended(self,n):
        return self._x + list(range(self.n,self.n+n))
只要您知道并记住了这个类的所有内部内容,那么很明显:

obj = A()
obj.set_range(10)

# old long forgotten code
a = obj.get_range()
a.reverse()

# new code
b = obj.get_range_extended(10)
不仅会反转
a
的内容,还会反转
b
的部分内容,因为它们是部分相同的对象(最初通过调用
set\u range
创建的列表)

因此,确保不会发生这种情况的最佳实践可能是在返回属性之前在任何类方法中创建属性的副本,对吗

    def get_range(self):
        return self._x.copy()

好的,这可以从源头上解决问题。但我经常不能这样做,因为这个课程不在我的范围之内。因此,我可能会更好地在代码中爬行,找到可能被多次引用的对象,并检查这些对象是否有任何就地操作。这些地方可能会证明某个特定的对象副本是正确的。。。但是,我如何才能识别所有这些关键对象和位置呢?

在很多情况下,多重引用都是良性的。当你改变一个对象时,对它有多个引用是完全正常的。例如,stuff:modify(thing)中的东西在被修改时通常至少有3个引用。一个来自
stuff
,一个来自
thing
变量,一个属于
modify
。对不起。这就是为什么我的导师比我更年长、更聪明,他们告诉我要避免使用mutator方法(在自包含的环境之外,例如使用.append构建列表并从某个函数返回值)。因此,总是喜欢
列表(反转的(一些列表))
而不是
一些列表。反转()
,或者
排序的(一些列表)
而不是
一些列表。排序()
。我还被告知不要将mutator方法公开给我的对象。总的来说,这是一个需要养成的好习惯。@user2357112:当然,这就是我为什么要问的原因——仅仅参考计数并没有真正的帮助。它必须为某种代码分支进行过滤。@juanpa:好的,那么-你知道有一个“过滤器”来查找所有这些mutator方法(无论如何,对于标准python对象)?