suchen

Heim  >  Fragen und Antworten  >  Hauptteil

javascript - python对不同类型的序列切片复制,但是效果为何不一样?

直接上代码,如下:
1.

a = [1,2,3]
b = a[:]
id(a)    #204324256
id(b)    #110000208

对于这个情况,a,b的地址是不一样的。
2.

a = '1,2,3'
b = a[:]
id(a)    #213689856
id(b)    #213689856

对于这个情况,ab的地址是一样的了。

同样是利用切片复制,而不是a='1,2,3',b=a这样的写法去复制,为何效果确实不一样呢?

巴扎黑巴扎黑2895 Tage vor305

Antworte allen(4)Ich werde antworten

  • 伊谢尔伦

    伊谢尔伦2017-04-10 17:16:49

    第一次说成__getitem__了, 有点不合适,应该是__getslice__,修改如下。

    同样是利用切片复制,而不是a='1,2,3',b=a这样的写法去复制 ,为何效果确实不一样呢?

    切片操作也就是x[i:j]这种操作,其实只是重写了__getslice__函数, 应该是str的重写方式与list的不一样。对于str这类不可变对象来说,应该是直接复制了原来的: 对于list等可变对象来说,应该是new了一个list对象。 
    __getslice__

    In [6]: str.__getslice__?
    Type:       wrapper_descriptor
    String Form:<slot wrapper '__getslice__' of 'str' objects>
    Namespace:  Python builtin
    Docstring:
    x.__getslice__(i, j) <==> x[i:j]
    
    Use of negative indices is not supported.
    
    In [7]: list.__getslice__?
    Type:       wrapper_descriptor
    String Form:<slot wrapper '__getslice__' of 'list' objects>
    Namespace:  Python builtin
    Docstring:
    x.__getslice__(i, j) <==> x[i:j]
    
    Use of negative indices is not supported.
    

    Antwort
    0
  • 阿神

    阿神2017-04-10 17:16:49

    这个应该是切片复制内部进行的优化。都是复制整体,而字符串是不可变类型,直接让新变量指向原来的字符串没有任何问题。但list是可变的,因此不能这样优化。

    Antwort
    0
  • 怪我咯

    怪我咯2017-04-10 17:16:49

    这里涉及到 Python 的可变对象和不可变对象赋值操作的区别。

    可变对象比如:列表、字典等,其内部值可以增删更改;
    不可变对象比如:元组、字符串,值一旦形成,便不可更改。
    你的示例 1 实际上是对 “a 列表的值” 进行浅复制,而对于所有的可变对象而言,不管所赋的值的大小,赋值操作都会建立新的 ID,以防止多个对象共用一个值 ID 导致的对某个对象值进行更改而影响其他对象的值的情况发生。

    a = [1, 2, 3]
    
    b = a
    
    c = a[:]
    
    id(a)
    Out[4]: 2618569309704
    
    id(b)
    Out[5]: 2618569309704
    
    id(c)
    Out[6]: 2618569309640

    如上, b 和 c 的 ID 是不一样的,因为 b = a 是拷贝 a,b = a[:] 是拷贝 a 的值,对于可变对象而言,这两者含义是不同的。

    而你的示例 2 则是对不可变对象进行赋值操作。由于不可变对象值不可改变,因此 b = a[:] b = a 本质上不存在如上的区别,也就是都是对值 ID 进行拷贝,因此 你的 a/b 的 ID 是相同的。
    但是要注意对不可变对象进行赋值操作,解释器可能有一定的优化而不会像对可变对象那样每次都重新建立一个ID,具体来说,对于值比较小的不可变对象进行赋值,解释器一般不会重新开辟新的id,而对值较大的不可变对象进行赋值,则id必须重建:

    a = 1
    
    b = 1
    
    id(a)
    Out[13]: 1824648976
    
    id(b)
    Out[14]: 1824648976
    
    c = 123456789
    
    d = 123456789
    
    id(c)
    Out[17]: 2618567010576
    
    id(d)
    Out[18]: 2618567009872

    如上,a b 值相等且比较小,因此 a b 的id 一样,但 c d 值比较大,而 值 id 就不同。这样做的目的是为了最大限度的提高效能。

    Antwort
    0
  • 天蓬老师

    天蓬老师2017-04-10 17:16:49

    对于第一种情况 id(a) 和 id(b) 虽然不一样,
    但 id(a[0]) 和 id(b[0]) (也就是 id(a[i]) = id(b[i]))却是一样的.

    a, b 相当于 C 语言里的指针, 这个复制操作是复制指针指向的地址,也就是 a[0] 和 b[0] 实际上是同一个东西。

    Antwort
    0
  • StornierenAntwort