第二章开头作者提到序列可以根据是否能存放不同类型的item分为容器序列和扁平序列两种类型。这种区分方法本没有问题,因为一个序列总可以划分成为能存放不同类型的数据,和不能存放不同类型的数据。但关键是这么区分有什么意义。毕竟不可变序列和可变序列的划分对+=操作符和id的作用有所不同。
作者说其中扁平序列存放的是值而不是引用,它在内存中一段连续的内存空间。
但是经过测试,。
>>> a="xzz"
>>> id(a)
83971168
>>> id(a[0])
55290688
>>> id(a[1])
83970528
>>> id(a[2])
83970528
经过了解,这种现象由于python的字符串驻留机制引起的。
创建字符串的时候,内部确实是直接分配了连续空间,并将对象复制进去。
obj = (PyObject *) PyObject_MALLOC(struct_size + (size + 1) * char_size);
但是当我们对字符串切片时,会返回一个新的字符串对象,所以id某个单字符字符串事实上返回的是单字符在缓冲池中的位置。
/* Single character Unicode objects in the Latin-1 range are
shared when using this constructor */
if (size == 1 && (Py_UCS4)*u < 256)
return get_latin1_char((unsigned char)*u);
/* If not empty and not single character, copy the Unicode data
into the new object */
if (find_maxchar_surrogates(u, u + size,
&maxchar, &num_surrogates) == -1)
return NULL;
作者:松直
链接:https://juejin.im/post/5959bd395188250d7f23faf5
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
总结:切片取单字符事实上会返回一个新的单字符字符串对象,而由于字符串驻留机制,同一单字符字符串的id永远是相同的。
有趣的例外:
>>> a="我"
>>> b="wo "
>>> b="我"
>>> id(a)
83979392
>>> id(b)
83979440
这两个是不同的,这是由于字符串驻留只针对ASCII码做缓存。
官方文档对序列的定义是“以非负整数索引的有限且有序的集合”。序列(sequence)中的每一项被定义成item。
让我感兴趣的是str这个序列(和数字一样最长使用),根据文档,str不是内置类型。也没有单独的“字符”类型,对str切片得到是长度为1的字符串。
由于没有单独的“字符”类型,索引字符串会生成长度为1的字符串。也就是说,对于非空字符串s,s[0] == s[0:1]。
看来cpython处理字符串的时候,永远把它看成一个个长度为1的字符串的集合。
也许作者想说的是原子类型,但在python3文档中,完全没有提到原子类型。
可变和不可变类型的区别:
An object of an immutable sequence type cannot change once it is created. (If the object contains references to other objects, these other objects may be mutable and may be changed; however, the collection of objects directly referenced by an immutable object cannot change.)
item是由id,类型,值三个东西组成的东西。
简单说说,既然我们已经知道了序列是引用(id)的集合,只要序列本身各个item的引用不能被改变,它就是个不可变类型。
比如(1,2,[3,4])虽然元组中的列表内容会变,但列表的id不会变,所以元组是个不可变类型。