python 内置类型(四)---list/tuple/range

4.6. Sequence Types — list, tuple, range

python拥有三种基本的序列类型:lists, tuplesrange。其他的序列类型包括二进制类型(binary data)和字符串类型(text strings)将会在其他章节内进行描述.

4.6.1. Common Sequence Operations

下面的操作支持大部分的序列类型,包括可变类型和不可变类型。python里提供的collections.abc.Sequence ABC是为了更容易在自定义序列类型上正确实现这些操作。

这个表格列举的操作是根据优先级排序的。在列表里,st是相同的序列类型。n,i,j是整数,x是满足任何类型限制的任意对象。

innot in操作有相同的优先级.
+*操作与相应的数字操作具有相同的优先级。[3]

Operation Result Notes
x in s True if an item of s is equal to x, else False (1)
x not in s False if an item of s is equal to x, else True (1)
s + t the concatenation of s and t (6)(7)
s * n or n * s equivalent to adding s to itself n times (2)(7)
s[i] ith item of s, origin 0 (3)
s[i:j] slice of s from i to j (3)(4)
s[i:j:k] slice of s from i to j with step k (3)(5)
len(s) length of s
min(s) smallest item of s
max(s) largest item of s
s.index(x[, i[, j]]) index of the first occurrence of x in s (at or after index i and before index j) (8)
s.count(x) total number of occurrences of x in s

相同的序列类型还支持比较。具体地说,tuplelist通过字典顺序来比较对应的元素。这表示如果两个序列相等,则必须每个对应的元素都要相同,而且两个序列的类型和长度必须相同。(想参阅对应的详细信息,可以参考Comparisons )

标记:

1.x not in s --> innot in不止用于一般的的包容测试,一些特殊的序列类型(比如str,bytesbytearray)也可以使用它们进行包容测试:

    >>> "gg" in "eggs"
    True

2.s * n or n * s --> n小于0时被视为0(产生跟s类型相同的空类型)。请注意,序列s里面的item并没有被copy,他们被重复引用多次(n次). 这个问题常常困扰新的python程序员。
考虑以下情况:

    >>> lists = [[]] * 3
    >>> lists
    [[], [], []]
    >>> lists[0].append(3)
    >>> lists
    [[3], [3], [3]]

为什么会发生这种情况呢,因为[[]]是一个包含一个[]元素的数组,因此[[]] * 3都是对这个空数组的相同引用,修改任意一个元素都会修改这个单独的列表。
用指针的说法表示就是:创建了一个包含三个指针的数组,这三个指针都指向同一个地址。你可以通过另一种方式创建空数组:

    >>>lists = [[] for i in range(3)]
    >>> lists[0].append(3)
    >>> lists[1].append(5)
    >>> lists[2].append(7)
    >>> lists
    [[3], [5], [7]]

FAQ条目中提供了进一步的说明如何创建多维列表?.

3.s[i],s[i:j],s[i:j:k] --> 如果i 和j是负数,i和j就会使用:len(s) + i 或者 len(s) + j 代替,但是-0还是0

if i < 0:
    i = len(s) + i
if j < 0:
    j = len(s) + j
  1. s[i:j] --> 从ij的对s的切片被定义为具有索引k的序列,使得i <= k < j。如果i或者jlen(s)的长度大,使用len(s)代替。如果i被省略或者iNone,使用0。如果j被省略或者jNone,使用len(s)代替。如果i大于等于j,则切片为空。

  2. s[i:j:k] --> s的从ij,具有索引为x = i + n * k的切片,其中n: 0 <= n < (j - i) / k.换句话说,指数为:i, i + k, i + 2 * k, i + 3 * k ......, 当x达到j时停止检索,但是x不包括j
    k是正数时,如果ijlen(s)大,他们将变为(减少到)len(s)
    k是负数时,如果ijlen(s)大,他们将变为(减少到)len(s)-1
    如果i或者j被省略或者为None,他们将会变成结束值,结束值的数值取决于k的符号。如下所示:

# k不能等于0
# 如果k=None,k = 1
if k == None:
    k = 1
if k < 0:
    i = len(s) - 1
    j = 0
if j > 0:
    i = 0
    j = len(s) - 1

6.s + t --> 拼接不可变序列总是产生一个新序列。这意味着通过重复连接建立一个序列将在总序列长度中具有二次运行成本。要获得线性运行时成本,您必须切换到以下其中一个选项:
* 如果拼接的是str类型,你可以生成一个序列,并且可以在末尾使用str.join()或写入一个io.StringIO实例,并在完成时检索其值
*如果拼接的是bytes类型,你可以相似的使用bytes.join()或者io.BytesIO,或者你可以使用bytearray代替,bytearray是可变的并且具有有效的分配机制
*如果拼接的是tuple类型,使用list代替
*如果拼接的是其他类型,请查看相关的类文档
7.s + t --> 某些序列类型(如range)仅支持遵循特定模式的项目序列,因此不支持序列拼接或重复。

  1. s.index(x[, i[, j]]) --> 当在s中没有找到xindex raises ValueError。不是所有的类型都支持传递附加的参数ij。这两个参数允许有效的搜索序列的子部分。传递额外的参数大致相当于使用s [i:j] .index(x),只是不复制任何数据,并且返回的索引是相对于序列的开始而不是切片的开始。

4.6.2. 不可变序列(Immutable Sequence Types)

唯一不可变的序列类型通常实现的操作不是通过可变序列类型实现的,这是对内置的hash()的支持。
这种支持允许将不可变序列(如tuple实例)用作dictkey,并存储在setfrozenset实例中。
尝试hash包含不可hash的不可变序列将导致TypeError。

4.6.3. 可变序列(Mutable Sequence Types)

下表中的操作是在可变序列类型上定义的。python里提供的collections.abc.MutableSequence ABC是为了更容易在自定义序列类型上正确实现这些操作。
在表中s是一个可变序列类型的实例,t是任何可迭代的对象,x是一个任意的对象,满足s施加的任何类型和数值限制(例如bytearray 只接受满足值限制'0 <= x <= 255'的整数)。

Operation Result Notes
s[i] = x item i of s is replaced by x
s[i:j] = t slice of s from i to j is replaced by the contents of the iterable t
del s[i:j] same as s[i:j] = []
s[i:j:k] = t the elements of s[i:j:k] are replaced by those of t (1)
del s[i:j:k] removes the elements of s[i:j:k] from the list
s.append(x) appends x to the end of the sequence (same ass[len(s):len(s)] = [x])
s.clear() removes all items from s (same as del s[:]) (5)
s.copy() creates a shallow copy of s (same as s[:]) (5)
s.extend(t) or s += t extends s with the contents of t (for the most part the same as s[len(s):len(s)] = t)
s *= n updates s with its contents repeated n times (6)
s.insert(i, x) inserts x into s at the index given by i (same as s[i:i]= [x])
s.pop([i]) retrieves the item at i and also removes it from s (2)
s.remove(x) remove the first item from s where s[i] == x (3)
s.reverse() reverses the items of s in place (4)

标记:

  1. 序列t的长度必须和切片的长度一样.
  2. 参数 i 默认是-1, 所以默认返回并删除最后一个元素。
  3. s中没有发现x时,remove raises ValueError.
  4. reverse()方法在倒置大序列时可以节省空间。为了提醒用户它是以副作用的方式运行的,它不会返回相反的顺序。
  5. 为了与不支持切片操作的可变容器的接口(如dict和set)保持一致,使用了clear()copy()
    New in version 3.3: clear() and copy() methods.
  6. 值n是一个整数,或者一个实现了__index__()的对象。n为零和负值时表示清除序列。序列中的item不是被复制;它们被多次引用,如Common Sequence Operations下的s * n所述。

4.6.4. Lists

数组是可变序列,经常用于存储同类项目的集合(精确的相似度因应用程序而异)。

class list([iterable])

Lists may be constructed in several ways:
列表可以以几种方式构建:

  • 用一对方括号表示一个空数组:[]
  • 使用方括号,用逗号分隔item: [a], [a, b, c]
  • for循环一个list(Using a list comprehension): [x for x in iterable]
  • 使用类型构造函数: list() or list(iterable)

构造函数list(iterable)构建一个列表,其items和iterable的item相同,并且item的顺序也相同。iterable可能是一个序列,支持迭代的容器,也可以是迭代器对象。如果iterable也是一个list,将会copy一个新的list并且返回,相当于iterable[:]。如果没有参数传入,创建一个空序列。举个例子:

>>>list("abc")
['a', 'b', 'c']
>>>list((1, 2, 3))
[1, 2, 3]
>>>list()
[]

许多其他操作也可以创建lists,包括内建函数sorted().
list支持所有通用common方法和可变mutable方法(即以上两个表格里的所有方法)。并且还支持以下的方法:

sort(*, key=None, reverse=False)

这个方法对列表进行排序,通过<(大小)比较对list里的item进行比较。异常不会被抑制 - 如果任何比较操作失败,整个排序操作将失败(并且列表可能会保留在部分修改状态)。

>>>l1 = [3, 2, 6, 3, 'xl', 9, 0] # 注意当前l1的排列顺序
>>>l1.sort() # 对l1进行排序sort,报错
Traceback (most recent call last):
  File "xx.py", line 91, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
TypeError: '<' not supported between instances of 'str' and 'int'
>>>l1 # 重新查看l1的数据,发现数据的排列顺序已经改变
[2, 3, 3, 6, 'xl', 9, 0]

sort()accepts two arguments that can only be passed by keyword (keyword-only arguments):
sort()接受两个只能通过关键字传递的参数key,reverse
key指定一个用于从每个列表元素提取比较键的参数的函数(例如key = str.lower)。对应于列表中每个项目的键被计算一次,然后用于整个排序过程。 “None”的默认值意味着列表项直接排序而不需要计算单独的键值。

>>>l2 = ['5', '9', 9, 8, 7, '3', 1]
>>>l2.sort() # 类型不同,无法比较,报错
Traceback (most recent call last):
  File "xx.py", line 91, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'
>>>l2.sort(key=int) #使用int()作用于每一个元素,然后进行比较
>>>l2
[1, '3', '5', 7, 8, '9', 9]

functools.cmp_to_key()可用于将2.x风格的cmp方法转化为key方法

reverse是一个布尔值。如果设置为True,则列表元素按照相反的顺序进行排序(逆序)。

这种方法在排序大序列时可以有效节省内存空间。为了提醒用户,它运行的副作用,此方法不返回排好序的序列(使用[sorted())

sort()方法保证稳定。如果确保不会更改比较相等的元素的相对顺序,则排序是稳定的 - 这对于多次排序很有帮助。

CPython实现细节:在列表正在排序时,试图进行变异甚至检查列表的效果时,列表是undefined。CPython实现使得列表在持续时间内显示为空,并且如果列表在排序过程中发生了变化,它可以检测到ValueError

4.6.5. Tuples

元组是不可变的序列,通常用于存储异构数据的集合(例如enumerate()生成的2元组)。 元组也用于需要存储不变序列的同类数据的情况(例如允许存储在setdict实例中)。

class tuple([*iterable*])

元组可以通过以下方式创建:

  • 使用一对小括号来创建一个空tuple: ()
  • 使用一个逗号结尾的单个tuple: a, or (a,)
  • 用逗号分隔项目: a, b, c or (a, b, c)
  • 使用内置函数tuple(): tuple() or tuple(iterable)

构造函数tuple(iterable)构建一个元组,其元素与iterable的元素相同且顺序相同。iterable可以是序列,支持迭代的容器,也可以是迭代器对象。如果iterable已经是一个元组,返回数据不变。例如,tuple('abc')返回('a','b','c')tuple([1,2,3])返回(1,2,3) 。如果没有参数,构造函数将创建一个新的空元组``()`。

请注意,元组实际上是由逗号组成的,而不是括号。除了在空元组的情况下,或当他们需要避免语法歧义时,括号是可选的。例如,f(a,b,c)是一个带有三个参数的函数调用,而f((a,b,c))是一个以3-tuple作为唯一参数的函数调用。

tuple支持所有的通用序列操作

对于数据的异质集合,其中通过名称访问比由索引访问更清晰,collections.namedtuple()可能是一个比简单的元组对象更合适的选择。

4.6.6. Ranges

range类型表示numbers的不可变序列,并通常用于for循环中。

class range(stop)
class range(start, stop[, step])

range构造函数的参数必须是整数(内置[int]或任何实现__index__特殊方法的对象)。
如果省略step参数,则默认为1
如果省略start参数,则默认为0
如果step为零,则引发'ValueError`

对于step > 0,range的实例对象r的内容由以下公式确定:r[i] = start + step * i where (i >= 0 and r[i] < stop).请注意,这里r[i] < stop.

对于step < 0,range的实例对象r的内容由以下公式确定:r[i] = start + step * i where (i >= 0 and r[i] > stop).请注意,这里r[i] > stop.

# 伪代码
if step > 0:
    int i = 0
    while r[i] < stop:
        r[i] = start + step * i
        i += 1
if step < 0:
    int i = 0
    while r[i] > stop:
        r[i] = start + step * i
        i += 1

如果r [0]不符合值约束,range对象将为空。range确实支持负指数,但这些被解释为从正指数确定的序列末尾开始的索引。(可以参考切片的理解)

range的元素中包含有大于sys.maxsize的元素是被允许的,但是一些方法可能会引发OverflowError,比如说len()

Range examples:

>>>list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(range(0, 30, 5))
[0, 5, 10, 15, 20, 25]
>>> list(range(0, 10, 3))
[0, 3, 6, 9]
>>> list(range(0, -10, -1))
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
>>> list(range(0))
[]
>>> list(range(1, 0))
[]

范围实现所有通用序列操作,除了连接和重复(由于范围对象只能表示序列遵循严格的模式,重复和连接通常会违反该模式)。

start
start参数的值(如果参数未提供,则为0
stop
stop参数的值
step
step参数的值(如果参数未提供,则为1

range类型比listtuple好的一个地方是:一个range对象将总是采取相同(小)的内存量,无论它代表的范围的大小(因为它只存储“start”,“stop”和“step”的值,在使用时再根据需要计算单个项目和子范围)。

Range对象支持collections.abc.Sequence ABC方法,提供诸如包含测试,元素索引查找,切片和负指数支持等功能:

>>>r = range(0, 20, 2)
>>> r
range(0, 20, 2)
>>> 11 in r
False
>>> 10 in r
True
>>> r.index(10)
5
>>> r[5]
10
>>> r[:5]
range(0, 10, 2)
>>> r[-1]
18

测试range对象的==和!=时,将它们作为序列进行比较。也就是说,如果两个range序列对象表示的值相同,则它们被认为是相等的。 (请注意,比较相等的两个范围对象可能会有不同的startstopstep.例如range(0)== range(2,1,3)range(0,3,2)== range(0,4) ,2)

>>>range(0)
range(0, 0)
>>>range(2, 1, 3)
range(2, 1, 3)
>>>list(range(0))
[]
>>>list(range(2, 1, 3))
[]

在版本3.2中更改:实现序列ABC。支持切片和负指数。在恒定时间测试[int]成员的对象,而不是迭代所有项目。

在版本3.3中更改:定义'=='和'!='以根据它们定义的值序列比较范围对象(而不是根据对象标识进行比较)。

3.3版新增功能:start,stopstep属性。

也可以看看

  • linspace recipe显示如何实现适合浮点应用程序的惰性版本的范围

通用序列(common)操作表格摘抄

x in s True if an item of s is equal to x, else False (1)
x not in s False if an item of s is equal to x, else True (1)
s + t the concatenation of s and t (6)(7)
s * n or n * s equivalent to adding s to itself n times (2)(7)
s[i] ith item of s, origin 0 (3)
s[i:j] slice of s from i to j (3)(4)
s[i:j:k] slice of s from i to j with step k (3)(5)
len(s) length of s
min(s) smallest item of s
max(s) largest item of s
s.index(x[, i[, j]]) index of the first occurrence of x in s (at or after index i and before index j) (8)
s.count(x) total number of occurrences of x in s

可变序列(mutable)操作表格摘抄

s[i] = x item i of s is replaced by x
s[i:j] = t slice of s from i to j is replaced by the contents of the iterable t
del s[i:j] same as s[i:j] = []
s[i:j:k] = t the elements of s[i:j:k] are replaced by those of t (1)
del s[i:j:k] removes the elements of s[i:j:k] from the list
s.append(x) appends x to the end of the sequence (same as s[len(s):len(s)] = [x])
s.clear() removes all items from s (same as del s[:]) (5)
s.copy() creates a shallow copy of s (same as s[:]) (5)
s.extend(t) or s += t extends s with the contents of t (for the most part the same as s[len(s):len(s)] = t)
s *= n updates s with its contents repeated n times (6)
s.insert(i, x) inserts x into s at the index given by i (same as s[i:i] = [x])
s.pop([i]) retrieves the item at i and also removes it from s (2)
s.remove(x) remove the first item from s where s[i] == x (3)
s.reverse() reverses the items of s in place (4)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容