python中的切片,是一个副本或只是一个指针

cst*_*ur4 7 python list python-2.7

>>>a = [3, 2]
>>>a[0:1][0] = 1
>>>a
[3, 2]

>>>a[0:1] = [1]
>>>a
[1, 2]
Run Code Online (Sandbox Code Playgroud)

什么a[0:1]意思?

  1. 如果它是指向a范围的指针,那么a[0:1][0] = 1应该改变a的值.
  2. 如果它是a范围的副本,那么a[0:1] = [1]不应该改变a的值.

我认为两者的结果彼此不一致.你能帮我解决一下这个问题吗?

Ale*_*ton 7

切片列表会创建一个浅表副本 - 它不是对原始副本的引用.所以,当你得到那个切片时,它不会与原始切片绑定list a.因此,您可以尝试更改它的单个元素,但它不会存储在变量中,也不会对任何原始元素进行更改list.

澄清一下,前者对你做__getitem__- 访问部分列表(副本):

a[0:1][0] = 1
Run Code Online (Sandbox Code Playgroud)

您正在编辑切片[0:1],这是一个唯一的浅表副本a,因此不会编辑a自己.

但是对于后者,一个是调用__setitem__,当然会就地编辑对象:

a[0:1] = [1]
Run Code Online (Sandbox Code Playgroud)

您直接参考和编辑部分内容a,因此会实时更改.


glg*_*lgl 6

在内部,这是一个很大的区别:

>>>a = [3, 2]
>>>a[0:1][0] = 1
Run Code Online (Sandbox Code Playgroud)

是一个简写

temp = a[0:1]
temp[0] = 1
Run Code Online (Sandbox Code Playgroud)

并在内部表示为

a.__getitem__(slice(0, 1)).__setitem__(0, 1)
Run Code Online (Sandbox Code Playgroud)

RESP.

temp = a.__getitem__(slice(0, 1))
temp.__setitem__(0, 1)
Run Code Online (Sandbox Code Playgroud)

所以它访问列表的一部分,创建一个单独的对象,并对该对象进行赋值,然后将其删除.

OTOH,

>>>a[0:1] = [1]
Run Code Online (Sandbox Code Playgroud)

a.__setitem__(slice(0, 1), [1])
Run Code Online (Sandbox Code Playgroud)

它只对原始对象进行操作.

因此,虽然看起来很相似,但这些表达方式与它们的含义截然不同.

让我们测试一下:

class Itemtest(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return self.name
    def __setitem__(self, item, value):
        print "__setitem__", self, item, value
    def __getitem__(self, item):
        print "__getitem__", self, item
        return Itemtest("inner")

a = Itemtest("outer")
a[0:1] = [4]
temp = a[0:1]
temp[0] = 4
a[0:1][0] = 4
Run Code Online (Sandbox Code Playgroud)

输出

__setitem__ outer slice(0, 1, None) [4]
__getitem__ outer slice(0, 1, None)
__setitem__ inner 0 4
__getitem__ outer slice(0, 1, None)
__setitem__ inner 0 4
Run Code Online (Sandbox Code Playgroud)