6

我只是想既然我已经看到了,我会记下来——如果能得到关于这种行为的确认,那就太好了;我确实看到了如何通过引用传递变量?,但我不确定如何在这种情况下解释它。

假设我们有这两个数组/列表:

a = [1, 2, 3, 4]
b = [-1, a, -100, a[2], -1]

解释器最初将它们视为:

>>> print(a)
[1, 2, 3, 4]
>>> print(b)
[-1, [1, 2, 3, 4], -100, 3, -1]

现在让我们改变一下a[2],看看会发生什么:

>>> print(a)
[1, 2, 55, 4]
>>> print(b)
[-1, [1, 2, 55, 4], -100, 3, -1]

因此,只要 listb有对list a的引用,值就会被更新——但是无论在哪里b初始化(引用?)list 中的一个元素a,Python 似乎在初始化时扩展了该值,因此将元素存储为价值(不是通过引用),所以它的价值显然不会更新。

基本上,我找到了一个用例,可以方便地定义 eg b = [-1 a[2] -1],然后 update a[2],并且能够计算a[2]得到 ( 在这种情况下) 的值时将发出的最新值b[1]。有没有办法在 Python 中做到这一点,而不必这样做b = [-1 a -1],然后阅读b[1][2](我想a[2]通过使用来获得价值b[1])?

4

3 回答 3

2

a是对可变列表的引用。所以,当你说:

a[2] = 55

您正在调用__setitem__在列表中设置项目的列表list.__setitem__不会尝试改变曾经存储在第二个索引中的项目。它只是用一个新的引用替换了那个引用。

另一方面,x = a[2]调用__getitem__只是创建对存储在列表中该索引处的对象的新引用。

于 2013-05-22T15:20:09.963 回答
1
>>> a = [1000,2000,3000,4000]
>>> sys.getrefcount(a[2])
2
>>> b = [-1, a, -100, a[2], -1]
>>> a is b[1]   # b[1] and `a` are actually two variables pointing to the same object
True
#[1000,2000,3000,4000] can be accessed or modified by either `a` or `b[1]`
>>> sys.getrefcount(a)  
3

>>> sys.getrefcount(a[2])
3

现在在内存中总共有 3 个对对象 3000 的引用(a[2]b[-2] shell 本身),但是由于整数是不可变的,所以如果您更改修改a[2]它只会从对象 3000 中删除一个引用,但b[-2]仍会指向同一个对象在内存中,a[2]现在将指向一些新分配的对象。

>>> id(a[2]),id(b[-2])
(150561920, 150561920)
>>> a[-2] = 5
>>> id(a[2]),id(b[-2])  #b still points to the same object
(148751024, 150561920)
>>> sys.getrefcount(b[-2])
2

如果位于的项目a[2]是可变对象,请说list

>>> a = [1000,2000, [2] , 4000]
>>> b = [-1, a, -100, a[2], -1]
>>> a[2] += [5]     # we can modify [2] from from either a[2] or b[-2]
>>> b[-2]+= [10]    # `+=` , `list.extend`, `list.append` changes the list in-place
>>> a[2] is b[-2]   #both still points to the same object as lists are mutable
True
>>> a
[1000, 2000, [2, 5, 10], 4000]
>>> b
[-1, [1000, 2000, [2, 5, 10], 4000], -100, [2, 5, 10], -1]
于 2013-05-22T15:21:01.657 回答
0

要解决通过外部列表的索引访问子列表的问题,您可以使用类似的东西:

class RecursiveList(list):
    def getitem(self, index, recurse=True):
        if not recurse:
            return self[index]
        else:
            return list(RecursiveList.flatten(self))[index]

    @staticmethod
    def flatten(l):
        for item in l:
            if hasattr(item, "__iter__"):
               for v in RecursiveList.flatten(item):
                   yield v
            else:
               yield item

对于您要求的确切行为,请添加以下内容:

    def __getitem__(self, i):
        return self.getitem(i, true)

请注意,如果您尝试使用切片,这可能会中断。

于 2013-05-22T15:47:13.680 回答