Python 3.7.1 基础 数据类型 列表 元组 字符串

1.前言

有三种基本序列类型:list(列表),tuples(元组)和 range (范围对象)。专门用于处理二进制数据和文本字符串的附加序列类型 在专门章节中描述。

2.序列的通用操作

大多数序列类型都支持下表中的操作,包括可变和不可变的序列。python提供的collections.abc.Sequence使其更容易正确地执行自定义序列类型的操作。

此表列出了按升序排序的顺序操作。在表中,s和t是相同类型的序列,n,i,j 和 k是整数,x是满足强加的任何类型和值限制的任意s对象。

innot in操作符具有和他们相同的优先级。+(串联)和*(重复)操作具有相同的优先级。

操作 结果 注意
x in s 如果s的某项等于x返回True,否则False (1)
x not in s 如果s的某项等于x返回False,否则True (1)
s + t s和 t的串联 (6)(7)
s * n 或者 n * s n个s 拼接 (2)(7)
s[i] s的第i个元素,从0开始 (3)
s[i:j] s的切片,从i到j(不包括j,顾左不顾右) (3)(4)
s[i:j:k] s的切片,从i到j,步长为k (3)(5)
len(s) s的长度
min(s) s的最小元素
max(s) s的最大元素
s.index(x[, i[, j]]) x在s中第一次出现的位置(限定位置在i,j之间) (8)
s.count(x) x在s中出现的次数

相同类型的序列也支持比较。特别是,元组和列表通过比较相应的元素并且按字典顺序比较。这意味着要比较相等,序列中的每个元素必须比较相等,并且两个序列必须是相同类型并且具有相同的长度。(有关完整详细信息,请参阅语言参考中的比较。)

注意:
(1)虽然innot in操作仅用于一般情况下的简单包含测试,但一些专门的序列(例如str,bytes 和 bytearray)也将它们用于子序列测试:

>>>
>>> "gg" in "eggs"
True

(2)小于0的n被视为0(其产生与s相同类型的空序列)。请注意,序列s 中的项目不会被复制; 它们被多次引用。这常常困扰着新的Python程序员; 考虑:

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

事情是这样的,[[]]是一个包含[]元素的非空列表,因此所有三个[[]]* 3元素都是对这个空列表元素的引用。修改任何lists元素都会修改此单个列表。您可以通过以下方式创建不同列表的列表:

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

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

(3)如果i或j为负数,则索引相对于序列s的结尾: len(s) + ilen(s) + j被替换。但请注意,-0仍然是0

(4)从i到j的s的切片就是所有满足k(i <= k < j)的s的索引项的拼接。如果i或j大于len(s),会使用len(s) 。如果i 被省略或使用None,从0开始。如果省略j或 None,使用len(s)。如果i大于或等于j,则切片为空。

def list_range_plus():
    s = [1,'a','bcd',223]
    print(s[0],s[1],s[2],s[3])

    print(s[-1],s[-2],s[-3],s[-4])
    print(s[len(s)-1], s[len(s)-2], s[len(s)-3], s[len(s)-4])

    print(s[0:-2],s[0:len(s)-2])
    print(s[-2:],s[len(s)-2:])# 从-2位置到结尾
    print(s[:-2], s[:len(s) - 2])
    print(s[::2])
# 输出结果
1 a bcd 223
223 bcd a 1
223 bcd a 1
[1, 'a'] [1, 'a']
['bcd', 223] ['bcd', 223]
[1, 'a'] [1, 'a']
[1, 'bcd']

(5)基本内容同(4),只不过增加一个步长k。

(6)连接不可变序列总是会产生一个新对象。这意味着通过重复级联构建序列将在总序列长度中具有二次运行时成本。要获得线性运行时成本,您必须切换到以下替代方案之一:

  • 如果连接str对象,您可以构建一个列表并在最后使用 str.join(),或者写入io.StringIO 实例并在完成时检索其值。
  • 如果连接bytes对象,您可以类似地使用 bytes.join()或io.BytesIO,或者您可以与bytearray对象进行就地连接。 bytearray 对象是可变的并且具有有效的过度分配机制
  • 如果连接tuple对象,扩展list代替
  • 对于其他类型,请调查相关的类文档

译者实例(帮助理解第6点的意思):

def list_connect():
    import string
    import time
    s = string.ascii_letters
    bases =''
    time1 = time.time()
    for i in range(100000):
        bases+=s
    #print(bases)
    end_time1 = time.time()
    print("普通连接5万次字符串花费时间:{:f}".format(end_time1-time1))
    time2 = time.time()
    list =[]
    for i in range(100000):
        list.append(s)
    #print("".join(list))
    end_time2 = time.time()
    print("list+join连接10万次字符串花费时间:{:f}".format(end_time2 - time2))
# 输出结果
普通连接10万次字符串花费时间:5.403309
list+join连接10万次字符串花费时间:0.086005

可以看出第二种方法花费的时间快了70倍左右,而且内存消耗不会剧烈上升。 如果你的机器比较好,可以尝试连接几百万次测试性能。

(7)某些序列类型(例如range)仅支持遵循特定模式的项序列,因此不支持序列连接或重复。

def list_range_plus():
    s = [1,'a','bcd',223]
    for i in range(3)+range(4):
        print(i)
# 输出结果
Traceback (most recent call last):
File "xxx/list1.py", line 42, in list_test
    for i in range(3)+range(4):
TypeError: unsupported operand type(s) for +: 'range' and 'range'

(8)index方法在s中找不到x时会引发ValueError。并非所有实现都支持传递附加参数i和j。这些参数允许有效搜索序列的子部分。传递额外的参数大致相当于使用s[i:j].index(x),只是没有复制任何数据,并且返回的索引是相对于序列的开始而不是切片的开始。

3. 序列类型

3.1 可变序列类型

下表中的操作是在可变序列类型上定义的。

在表中,s是可变序列类型的实例,t是任何可迭代对象,x是满足强加的任何类型和值限制的任意s对象(例如,bytearray只接受满足值限制0 <= x <= 255的整数)。

操作 结果 注意
s[i] = x s的第i项被替换为 X,i从0开始
s[i:j] = t 从i到j的s切片 被可迭代t的内容替换
del s[i:j] s[i:j] = []一样
s[i:j:k] = t s[i:j:k]中的元素被t取代 (1)
del s[i:j:k] 从列表中删除s[i:j:k]元素
s.append(x) 将x附加到序列的末尾(与s[len(s):len(s)] = [x])相同
s.clear() 从s中删除所有项目 (同于del s[:] (5)
s.copy() 创建s的浅表副本 (同于s[:] (5)
s.extend(t)s += t 使用t的内容扩展s(大致等于s[len(s):len(s)] = t
s *= n 更新s,其内容重复n次 (6)
s.insert(i, x) 在由i给出的索引处将x插入s (同于s[i:i] = [x]
s.pop([i]) 在i处检索项目并将其从s中删除 (2)
s.remove(x) 从s 中删除第一个等于x的项s[i] (3)
s.reverse() 反转s (4)

译者实例

def seq_changelist():
    s = [1, 'a', 'bcd', 223]
    s1 =[ 'i','love','you']
    s[1:] = 'abc'
    print(s)
    s[1:] = ('abc', 'qian')
    print(s)
    s[1] = s1
    print(s)
    s[0] = 0
    print(s)
    del s[:1]
    print(s)
    s.append(' ')
    s.append(['-- by leng','.'])
    print(s)
    s.extend('2018')
    s.extend(['.12.','01'])
    print(s)
    s.insert(len(s),'!')
    print(s)
# 输出结果
[1, 'a', 'b', 'c']
[1, 'abc', 'qian']
[1, ['i', 'love', 'you'], 'qian']
[0, ['i', 'love', 'you'], 'qian']
[['i', 'love', 'you'], 'qian']
[['i', 'love', 'you'], 'qian', ' ', ['-- by leng', '.']]
[['i', 'love', 'you'], 'qian', ' ', ['-- by leng', '.'], '2', '0', '1', '8', '.12.', '01']
[['i', 'love', 'you'], 'qian', ' ', ['-- by leng', '.'], '2', '0', '1', '8', '.12.', '01', '!']

注意:
(1)t必须与它所替换的切片具有相同的长度。

def seq_list_iport():
    import string
    s = [x for x in string.digits ]
    print(s)
    slice_len = len(s[::2])
    print(s[::2])
    s[::2]= "".join([ _ for _ in string.ascii_lowercase])[0:slice_len]
    print(s)
# 输出结果
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
['0', '2', '4', '6', '8']
['a', '1', 'b', '3', 'c', '5', 'd', '7', 'e', '9']

(2)pop函数默认使用可选参数为-1,因此默认情况下会移除并返回最后一项。参数越界报错IndexError

def list_pop():
	import string
    s = [x for x in string.digits]
    print(s)
    print("pop():", s.pop())
    print(s)
    print("pop(-1):", s.pop(-1))
    print(s)
    print("pop(4):", s.pop(4))
    print(s)
# 输出结果
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
pop(): 9
['0', '1', '2', '3', '4', '5', '6', '7', '8']
pop(-1): 8
['0', '1', '2', '3', '4', '5', '6', '7']
pop(4): 4
['0', '1', '2', '3', '5', '6', '7']

(3)remove函数在s中找不到x的时候时候引发ValueError

def list_remove():
    import string
    s0 = ['!','@','*']
    s = ['a',123,45.24,[1,'d'],s0]
    print(s)
    print("remove('a')", s.remove('a'))
    print(s)
    print("remove([1,'d'])", s.remove([1,'d']))
    print(s)
    print("remove(s0)", s.remove(s0))
    print(s)
# 输出结果
['a', 123, 45.24, [1, 'd'], ['!', '@', '*']]
remove('a') None
[123, 45.24, [1, 'd'], ['!', '@', '*']]
remove([1,'d']) None
[123, 45.24, ['!', '@', '*']]
remove(s0) None
[123, 45.24]

(4)reverse()当反转大序列时,该方法修改了用于空间经济性的序列。为了提醒用户它是由副作用操作,它不会返回相反的顺序。

def list_reverse():
    s0 = ['!', '@', '*']
    s = ['a', 123, 45.24, [1, 'd'], s0]
    print(s.reverse())
    print(s)
# 输出结果
None
[['!', '@', '*'], [1, 'd'], 45.24, 123, 'a']

(5)clear()和copy()包括与不支持切片操作的可变容器的接口(例如dict和set)的一致性。

变化:版本3.3中增加的clear()copy()方法。

译者注
list.copy()函数是一种浅copy,同copy.copy(),同s[:],不同于copy.deepcopy(),不同于同x=s=就是纯引用,就是同一个对象)。
copy.copycopy.deepcopy的不同之处在于对拷贝对象中的可变元素(如list)和不可变的元素(如int,str)的处理。

  • 对于不可变元素的处理是一样的,都只是复制一份,各不相干。
  • 对于可变元素,deepcopy还是复制一份,各不相干;copy是引用一份,你变我也变,我变你也变。

译者实例

def list_copy(type=0):
    s0 = ['!', '@', '*']
    s = ['a', 123, 45.24, [1, 'd'], s0]
    new_s =[]
    if type == 0:
        new_s = s.copy()
    else:
        import copy
        if type == 1:
            new_s = copy.copy(s)
        elif type == 2:
            new_s = copy.deepcopy(s)
        elif type == 3:
            new_s = s
        elif type == 4:
            new_s = s[:]
    print("id(s)={}:{}".format(id(s),s))
    print("id(new_s):{}".format(id(new_s)))
    s[0],new_s[0] = 'an','bn'
    print(s)
    print(new_s)
    print(s)
    print(new_s)
    s[len(s)-1][0],new_s[len(new_s)-1][0] ='!!','**'
    print(s)
    print(new_s)
    print(s)
    print(new_s)
    s[3][0], new_s[3][0] = '!!', '??'
    print(s)
    print(new_s)
    print(s)
    print(new_s)

def test_copy():
    print("use list.copy".center(50, '-'))
    list_copy(0)
    print("use copy.copy".center(50,'-'))
    list_copy(1)
    print("use copy.deepcopy".center(50, '-'))
    list_copy(2)
    print("use =".center(50, '-'))
    list_copy(3)
    print("use [:]".center(50, '-'))
    list_copy(4)

if __name__ == "__main__":
    test_copy()
# 输出结果
------------------use list.copy-------------------
id(s)=20388480:['a', 123, 45.24, [1, 'd'], ['!', '@', '*']]
id(new_s):20388400
['an', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['an', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['an', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
------------------use copy.copy-------------------
id(s)=1590696:['a', 123, 45.24, [1, 'd'], ['!', '@', '*']]
id(new_s):20388080
['an', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['an', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['an', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
----------------use copy.deepcopy-----------------
id(s)=20388400:['a', 123, 45.24, [1, 'd'], ['!', '@', '*']]
id(new_s):20388480
['an', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['!!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['!!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['an', 123, 45.24, ['!!', 'd'], ['!!', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['an', 123, 45.24, ['!!', 'd'], ['!!', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
----------------------use =-----------------------
id(s)=20387960:['a', 123, 45.24, [1, 'd'], ['!', '@', '*']]
id(new_s):20387960
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
---------------------use [:]----------------------
id(s)=20388480:['a', 123, 45.24, [1, 'd'], ['!', '@', '*']]
id(new_s):1591856
['an', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['!', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['an', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['bn', 123, 45.24, [1, 'd'], ['**', '@', '*']]
['an', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['an', 123, 45.24, ['??', 'd'], ['**', '@', '*']]
['bn', 123, 45.24, ['??', 'd'], ['**', '@', '*']]

(6)值n是整数或实现__index__()的对象 。n的零值和负值清除序列。序列中的项目不会被复制; 他们被多次引用

def list_mn():
    s = [3,4]
    import random
    class NN:
        def __index__(self):
            return random.randint(1,3)

    n = NN()
    print(s*n)
    print(s * n)
    s[1]=5
    print(s * n)
    s1 = s*0
    print(s1)
# 输出结果
[3, 4, 3, 4, 3, 4]
[3, 4, 3, 4]
[3, 5, 3, 5, 3, 5]
[]

3.1.1 列表 List

列表是可变序列,通常用于存储同类项目的集合(其中精确的相似程度将根据应用而变化)。
列表实现所有 通用可变序列操作(上面2、3.1节已经说过了)。

3.1.1.1 class list([iterable])

列表可以通过以下几种方式构建:

(1)使用一对方括号表示空列表: []
(2)使用方括号,用逗号分隔项目:[a][a, b, c]
(3)使用列表生成器: [x for x in iterable]
(4)使用类型构造函数:list()list(iterable)

构造函数构建一个列表,其项目与iterable的项目相同且顺序相同。 iterable可以是序列,支持迭代的容器,也可以是迭代器对象。如果iterable 已经是一个列表,则会生成并返回一个副本,类似于iterable[:]。例如,list('abc')返回['a', 'b', 'c']list( (1, 2, 3) )返回[1, 2, 3]。如果没有给出参数,构造函数会创建一个新的空列表[]

许多其他操作也会生成列表,包括内置sorted()

列表实现所有 通用 和 可变序列操作(上面2、3节已经说过了)。列表还提供以下附加方法:

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

此方法仅使用<比较符对列表中的元素进行排序。不会压制异常 - 如果任何比较操作失败,整个排序操作将失败(列表可能会保留在部分修改状态)。

sort()接受两个只能通过关键字传递的参数(仅限关键字参数):

key指定一个函数作为参数,该函数用于从每个列表元素中提取比较键(例如,key=str.lower)。对应于列表中每个项目的key计算一次,然后用于整个分类过程。默认值为None, 表示列表项直接排序而不计算单独的键值。

functools.cmp_to_key()实用程序可用于将2.x版本中的的cmp函数转换为key函数。

reverse是一个布尔值。如果设置为True,则对列表元素进行排序,就好像每个比较都已反转一样。

当对大序列进行排序时,该方法修改了用于空间经济性的序列。为了提醒用户它是由副作用操作,它不返回已排序的序列(使用sorted()显式请求新的已排序列表实例)。

该sort()方法保证稳定。如果排序保证不更改比较相等的元素的相对顺序,则排序是稳定的 - 这有助于在多个过程中进行排序(例如,按部门排序,然后按工资等级排序)。

CPython实现细节:在对列表进行排序时,尝试变异甚至检查列表的效果是不确定的。Python的C实现使得列表在持续时间内显示为空,并且如果它可以检测到列表在排序期间已经变异,则会引发该列表的ValueError

def list_sort():
    # s = ['c','b','a',9,1,['e','f']]
    # print(s.sort())
    s = ['b', 'a', 'agh', 'dfe', 'def', 'Agh', 'a1', '1a']
    s.sort()  # 默认按ascii顺序表排序,1~9A~Za~z
    print(s)
    s = ['b', 'a', 'agh', 'dfe', 'def', 'Agh', 'a1', '1a']
    s.sort(key=str.upper)  # 将元素键都变为大写,
    print(s)
    s = ['b', 'a', 'agh', 'dfe', 'def', 'Agh', 'a1', '1a']
    s.sort(key=str.lower)
    print(s)

    def fun(element):
        return element[0]

    s = [(3,'threee'),(1,"one"),(2,"two")]
    s.sort(key=fun)
    print(s)

    class Stu:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def __repr__(self):
            return repr((self.name,self.age))
    stu_list = [Stu('sam',15),Stu('baby',10),Stu('doge',25)]
    stu_list.sort(key= lambda s:s.age)
    print(stu_list)
# 输出结果
['1a', 'Agh', 'a', 'a1', 'agh', 'b', 'def', 'dfe']
['1a', 'a', 'a1', 'agh', 'Agh', 'b', 'def', 'dfe']
['1a', 'a', 'a1', 'agh', 'Agh', 'b', 'def', 'dfe']
[(1, 'one'), (2, 'two'), (3, 'threee')]
[('baby', 10), ('sam', 15), ('doge', 25)]

3.2 不可变序列类型

不可变序列类型通常实现的唯一操作是对内置hash()的支持(可变序列类型没有实现)。

这种支持允许不可改变的序列(如tuple实例),用作字典(dict)的键,并存储在set和frozenset 实例中。

尝试哈希包含不可变值的不可变序列将导致TypeError

3.2.1 元组

元组实现所有 序列的通用操作 (上面第2节讲过)。

3.2.1.1 class tuple([iterable])

元组可以通过多种方式构建:

(1)使用一对括号表示空元组:()
(2)对单例元组使用尾随逗号:a,(a,)
(3)用逗号分隔项目:a, b, c(a, b, c)
(3)使用内置tuple():tuple()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元组作为一个一参数的函数调用。

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

3.2.2 str (字符串,文本序列类型)

有关str 定义和操作非常多,作者另有两篇文章单独讲述,请参阅 Python 3.7.1 基础-数据类型-字符串Python 3.7.1 模块 string

3.2.3 range

range类型表示不可变的数字序列,通常用于在for循环中循环特定次数 。

3.2.3.1 class range(stop)

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

猜你喜欢

转载自blog.csdn.net/lengfengyuyu/article/details/84679592