今天列表专题的目录如下:

很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:101677771

列表基础

    • 1 创建列表

    • 2 访问元素

    • 3 添加元素

    • 4 删除元素

    • 5 list 与 in

    • 6 list 与数字

    • 7 列表生成式

  • 列表进阶

    • 8 其他常用API

    • 9 列表实现栈

    • 10 列表包含自身

    • 11 插入元素性能分析

    • 12 深浅拷贝

    • 13 列表可变性

列表基础

1 创建列表

列表是一个容器,使用一对中括号 [] 创建一个列表。

创建一个空列表:

  1. a = [] # 空列表

创建一个含有 5 个整型元素的列表 a :

  1. a = [3,7,4,2,6]

列表与我们熟知的数组很相似,但又有很大区别。

一般数组内的元素要求同一类型,但是列表内可含有各种不同类型,包括再嵌套列表。

如下,列表 a 包含三种类型:整形,字符串,浮点型:

如下列表 a 嵌套两个列表:

2 访问元素

列表访问主要包括两种:索引和切片。

如下,访问列表 a 可通过我们所熟知的正向索引,注意从 0 开始;

也可通过Python特有的负向索引,

即从列表最后一个元素往前访问,此时索引依次被标记为 -1,-2,...,-5 ,注意从 -1 开始。

除了以上通过索引访问单个元素方式外,

还有非常像 matlab 的切片访问方式,这是一次访问多个元素的方法。

切片访问的最基本结构:中间添加一个冒号。

如下切片,能一次实现访问索引为1到4,不包括4的序列:

  1. In [1]: a=[3,7,4,2,6]
  2. In [2]: a[1:4]
    Out[2]: [7, 4, 2]

Python支持负索引,能带来很多便利。比如能很方便的获取最后三个元素:

  1. In [1]: a=[3,7,4,2,6]
  2. In [3]: a[-3:]
    Out[3]: [4, 2, 6]

除了使用一个冒号得到连续切片外,

使用两个冒号获取带间隔的序列元素,两个冒号后的数字就是间隔长度:

  1. In [1]: a=[3,7,4,2,6]
  2. In [7]: a[::2] # 得到切片间隔为2
    Out[7]: [3, 4, 6]

其实最全的切片结构: start:stop:interval ,如下所示,获得切片为:索引从 1 到 5 间隔为 2 :

  1. In [6]: a=[3,7,4,2,6]
  2. In [7]: a[1:5:2]
    Out[7]: [7, 2]

3 添加元素

列表与数组的另一个很大不同,使用数组前,需要知道数组长度,便于从系统中申请内存。

但是,列表却不需要预先设置元素长度。

它支持任意的动态添加元素,完全不用操心列表长短。

它会随着数组增加或删除而动态的调整列表大小。

这与数据结构中的线性表或向量很相似。

添加元素通常有两类场景。

append 一次添加1个元素, insert 在指定位置添加元素:

  1. In [8]: a=[3,7,4,2,6]
    In [9]: a.append(1) # append默认在列表尾部添加元素
    In [10]: a
    Out[10]: [3, 7, 4, 2, 6, 1]
  2. In [11]: a.insert(2,5) # insert 在索引2处添加元素5
    In [12]: a
    Out[12]: [3, 7, 5, 4, 2, 6, 1]

extend 或直接使用 + 实现一次添加多个元素:

  1. In [13]: a.extend([0,10])# 一次就地添加0,10两个元素
    In [14]: a
    Out[14]: [3, 7, 5, 4, 2, 6, 1, 0, 10]
  2. In [15]: b = a+[11,21] # + 不是就地添加,而是重新创建一个新的列表
    In [16]: b
    Out[16]: [3, 7, 5, 4, 2, 6, 1, 0, 10, 11, 21]

这里面有一个 重要细节 ,不知大家平时注意到吗。

extend 方法实现批量添加元素时未创建一个新的列表,而是直接添加在原列表中,这被称为 in-place ,就地。而 b=a+list对象 实际是创建一个新的列表对象,所以不是就地批量添加元素。

但是, a+=一个列表对象 , += 操作符则就会自动调用 extend 方法进行合并运算。大家注意这些 微妙的区别 ,不同场景选用不同的API,以此高效节省内存。

4 删除元素

删除元素的方法有三种: remove , pop , del .

remove 直接删除元素,若被删除元素在列表内重复出现多次,则只删除第一次:

  1. In [17]: a=[1,2,3,2,4,2]
    In [18]: a.remove(2)
    In [19]: a
    Out[19]: [1, 3, 2, 4, 2]

pop 方法若不带参数默认删除列表最后一个元素;若带参数则删除此参数代表的索引处的元素:

  1. In[19]: a = [1, 3, 2, 4, 2]
    In [20]: a.pop() # 删除最后一个元素
    Out[20]: 2
    In [21]: a
    Out[21]: [1, 3, 2, 4]
  2. In [22]: a.pop(1) # 删除索引等于1的元素
    Out[22]: 3
    In [23]: a
    Out[23]: [1, 2, 4]

del 与 pop 相似,删除指定索引处的元素:

  1. In [24]: a = [1, 2, 4]
    In [25]: del a[1:] # 删除索引1到最后的切片序列
    In [26]: a
    Out[26]: [1]

5 list 与 in

列表是可迭代的,除了使用类似 c 语言的索引遍历外,还支持 for item in alist 这种直接遍历元素的方法:

  1. In [28]: a = [3,7,4,2,6]
    In [29]: for item in a:
    ...: print(item)
    3
    7
    4
    2
    6

in 与可迭代容器的结合,还用于判断某个元素是否属于此列表:

  1. In [28]: a = [3,7,4,2,6]
    In [30]: 4 in a
    Out[30]: True
  2. In [31]: 5 in a
    Out[31]: False

6 list 与数字

内置的list与数字结合,实现元素的复制,如下所示:

  1. In [32]: ['Hi!'] * 4
    Out[32]: ['Hi!', 'Hi!', 'Hi!', 'Hi!']

表面上这种操作太方便,实际确实也很方便,比如我想快速打印20个 - ,只需下面一行代码:

  1. In [33]: '-'*20
    Out[33]: '--------------------'

使用列表与数字相乘构建二维列表,然后第一个元素赋值为 [1,2] ,第二个元素赋值为 [3,4],第三个元素为 [5] :

  1. In [34]: a = [[]] * 3
    In [35]: a[0]=[1,2]
    In [36]: a[1]=[3,4]
    In [37]: a[2]=[5]
    In [38]: a
    Out[38]: [[1, 2], [3, 4], [5]]

7 列表生成式

列表生成式 是创建列表的一个方法,它与使用 append 等API创建列表相比,书写更加简洁。

使用列表生成式创建1到50的所有奇数列表:

  1. a=[i for i in range(50) if i&1]

列表进阶

8 其他常用API

除了上面提到的方法外,列表封装的其他方法还包括如下:

clear , index , count , sort , reverse , copy

clear 用于清空列表内的所有元素 index 用于查找里面某个元素的索引:

  1. In [4]: a=[1,3,7]
  2. In [5]: a.index(7)
    Out[5]: 2

count 用于统计某元素的出现次数:

  1. In [6]: a=[1,2,3,2,2,5]
  2. In [7]: a.count(2) # 元素2出现3次
    Out[7]: 3

sort 用于元素排序,其中参数 key 定制排序规则。如下列表,其元素为元祖,根据元祖的第二个值由小到大排序:

  1. In [8]: a=[(3,1),(4,1),(1,3),(5,4),(9,-10)]
  2. In [9]: a.sort(key=lambda x:x[1])
  3. In [10]: a
    Out[10]: [(9, -10), (3, 1), (4, 1), (1, 3), (5, 4)]

reverse 完成列表反转:

  1. In [15]: a=[1,3,-2]
  2. In [16]: a.reverse()
  3. In [17]: a
    Out[17]: [-2, 3, 1]

copy 方法在下面讲深浅拷贝时会详细展开。

9 列表实现栈

列表封装的这些方法,实现  这个常用的数据结构比较容易。栈是一种只能在列表一端进出的特殊列表, pop 方法正好完美实现:

  1. In [23]: stack=[1,3,5]
  2. In [24]: stack.append(0) # push元素0到尾端,不需要指定索引
  3. In [25]: stack
    Out[25]: [1, 3, 5, 0]
  4. In [26]: stack.pop() # pop元素,不需指定索引,此时移出尾端元素
    Out[26]: 0
  5. In [27]: stack
    Out[27]: [1, 3, 5]

由此可见Python的列表当做栈用,完全没有问题,push 和 pop 操作的时间复杂度都为 O(1)

但是使用列表模拟队列就不那么高效了,需要借助Python的 collections 模块中的双端队列 deque 实现。

10 列表包含自身

列表的赋值操作,有一个非常有意思的问题,大家不妨耐心看一下。

  1. In [1]: a=[1,3,5]
  2. In [2]: a[1]=a # 列表内元素指向自身

这样相当于创建了一个引用自身的结构。

打印结果显示是这样的:

  1. In [3]: a
    Out[3]: [1, [...], 5]

中间省略号表示无限循环,这种赋值操作导致无限循环,这是为什么?下面分析下原因。

执行 a = [1,3,5] 的时候,Python 做的事情是首先创建一个列表对象 [1, 3, 5],然后给它贴上名为 a 的标签。

执行 a[1] = a 的时候,Python 做的事情则是把列表对象的第二个元素指向 a 所引用的列表对象本身。

执行完毕后, a 标签还是指向原来的那个对象,只不过那个对象的结构发生了变化。

从之前的列表 [1,3,5] 变成了 [1,[...], 5],而这个[...]则是指向原来对象本身的一个引用。

如下图所示:

可以看到形成一个环路:a[1]--->中间元素--->a[1],所以导致无限循环。

11 插入元素性能分析

与常规数组需要预先指定长度不同,Python 中list不需要指定容器长度,允许我们随意的添加删除元素。

但是这种便捷性也会带来一定副作用,就是插入元素的时间复杂度为O(n),而不是O(1),因为insert会导致依次移动插入位置后的所有元素。

为了加深对插入元素的理解,特意把cpython实现 insert 元素的操作源码拿出来。

可以清楚看到 insert 元素时,插入位置处的元素都会后移一个位置,因此插入元素的时间复杂为 O(n) ,所以凡是涉及频繁插入删除元素的操作,都不太适合用 list .

  1. static int
    ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
    {
    assert((size_t)n + 1 < PY_SSIZE_T_MAX);
    if (list_resize(self, n+1) < 0)
    return -1;
  2. if (where < 0) {
    where += n;
    if (where < 0)
    where = 0;
    }
    if (where > n)
    where = n;
    items = self->ob_item;
    //依次移动插入位置后的所有元素
    // O(n) 时间复杂度
    for (i = n; --i >= where; )
    items[i+1] = items[i];
    Py_INCREF(v);
    items[where] = v;
    return 0;
    }

12 深浅拷贝

list 封装的 copy 方法实现对列表的浅拷贝,浅拷贝只拷贝一层,具体拿例子说:

  1. In [38]: c =[1,3,5]
  2. In [39]: cc = c.copy()

c 和 cc 分别指向一片不同内存,示意图如下:

这样修改 cc 的第一个元素,原来 c 不受影响:

  1. In [40]: cc[0]=10 # 修改cc第一个元素
  2. In [41]: cc
    Out[41]: [10, 3, 5]
  3. In [42]: c # 原来 c 不受影响
    Out[42]: [1, 3, 5]

但是,如果内嵌一层列表,再使用copy时只拷贝一层:

  1. In [32]: a=[[1,3],[4,2]]
  2. In [33]: ac = a.copy()
  3. In [34]: ac
    Out[34]: [[1, 3], [4, 2]]

上面的示意图清晰的反映出这一点,内嵌的列表并没有实现拷贝。因此再修改内嵌的元素时,原来的列表也会受到影响。

  1. In [35]: ac[0][0]=10
  2. In [36]: ac
    Out[36]: [[10, 3], [4, 2]]
  3. In [37]: a
    Out[37]: [[10, 3], [4, 2]]

要想实现深度拷贝,需要使用Python模块 copy 中的 deepcopy 方法。

13 列表可变性

列表是可变的,可变的对象是不可哈希的,不可哈希的对象不能被映射,因此不能被用作字典的键。

  1. In [51]: a=[1,3]
    In [52]: d={a:'不能被哈希'} #会抛出如下异常
  2. # TypeError: unhashable type: 'list'

但是,有时我们确实需要列表对象作为键,这怎么办?

可以将列表转化为元祖,元祖是可哈希的,所以能作为字典的键。

总结

以上就是列表专题的所有13个方面总结,目录如下:

  • 列表基础

  • 1 创建列表

  • 2 访问元素

  • 3 添加元素

  • 4 删除元素

  • 5 list 与 in

  • 6 list 与数字

  • 7 列表生成式

  • 列表进阶

  • 8 其他常用API

  • 9 列表实现栈

  • 10 列表包含自身

  • 11 插入元素性能分析

  • 12 深浅拷贝

  • 13 列表可变性

4300 字Python列表使用总结,用心!的更多相关文章

  1. python 列表和字符串

    python 列表中保留所有字符串前三项,并保存到一个新的列表l = [s[:3] for s in data] python 在列表中查找包含所以某个字符串的项,并保存到一个新的列表l = [s f ...

  2. python 列表排序

    转自http://www.iplaypython.com/jinjie/jj114.html reverse()方法 将列表中元素反转排序,比如下面这样>>> x = [1,5,2, ...

  3. python列表、元祖、字典

    python列表   ['a','1','vs2']       里面的值可以改 python元祖   ('a','1','css','sdf12')   里面的值不能改 python字典   {'s ...

  4. Python列表、元组、字典和字符串的常用函数

    Python列表.元组.字典和字符串的常用函数 一.列表方法 1.ls.extend(object) 向列表ls中插入object中的每个元素,object可以是字符串,元组和列表(字符串“abc”中 ...

  5. Python 列表

    python 列表 列表的特点 1.列表是一种可变的数据类型,这点是跟元组有区别的 2.列表中的值是有序的,并且可存放重复的值,这点跟set有区别的 3.python中的列表类似于其它语言中的数组 4 ...

  6. python 列表生成器

    python 列表生成器 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 一个循环 在C语言等其他语言中,for循环一般是这样的 ...

  7. [转载] Python 列表(list)、字典(dict)、字符串(string)常用基本操作小结

    创建列表 sample_list = ['a',1,('a','b')] Python 列表操作 sample_list = ['a','b',0,1,3] 得到列表中的某一个值 value_star ...

  8. Python 列表如何获得一个指定元素所在的下标

    在使用Python3.4读取txt数据到列表,由于编码问题,读取到的数据通常会出现'\ufeffX'(x为你想要的数据).这时候如果需要把列表中的数据由字符串转换到数值型的数据的进行数据分析的话就会出 ...

  9. python列表的常用操作方法

    主要介绍了Python中列表(List)的详解操作方法,包含创建.访问.更新.删除.其它操作等,需要的朋友可以参考下. 1.创建列表.只要把逗号分隔的不同的数据项使用方括号括起来即可 List = [ ...

随机推荐

  1. Pintech品致全新多功能MDO 704E系列示波器全新推出

    2020年 7月,Pintech品致全新推出推出首款具有多个模拟通道和多个数字通道的示波器.每个模拟通道带宽为200 MHz,每个模拟通道采样率同时达1 GSa/s,在一台仪器中,实现精确.可重复的. ...

  2. Linux的VMWare中Centos7的安装

    Windows平台下VMWare 14安装Centos 7 一.虚拟机硬件配置 1.选择创建新的虚拟机: 2.选择自定义(高级)进行自定义配置,单击下一步: 3.选择虚拟机硬件兼容性为默认,单击下一步 ...

  3. What is 测试金字塔?

    我的女朋友是一名测试工程师,但她之前却不知道测试金字塔的概念,为此我曾经在家里的白板上画了一个图一层一层给她讲解过.我和同事在给团队面试测试和开发岗位时,也会必问到这个问题,想到可能有很多开发童鞋都不 ...

  4. Flink状态妙用

    本文主要介绍福布湿在flink实时流处理中,state使用的一些经验和心得.本文默认围观的大神已经对flink有一定了解,如果围观过程中发现了有疑问的地方,欢迎在评论区留言. 1. 状态的类别 1.1 ...

  5. “随手记”开发记录day07

    今天完成了关于我们页面中的相关信息,由于之前没有做过这个东西,只想着用一个view解决 可是发现我们整的太简单了,还是太年轻,最后想出来要跟java代码一起解决这个问题, 效果

  6. JVM系列之:再谈java中的safepoint

    目录 safepoint是什么 safepoint的例子 线程什么时候会进入safepoint safepoint是怎么工作的 总结 safepoint是什么 java程序里面有很多很多的java线程 ...

  7. Eclipse开发Android项目报错解决方案详细教程,最新版一篇就够了!

    本文记录刚接触Android开发搭建环境后新建工程各种可能的报错,并亲身经历漫长的解决过程(╥╯^╰╥),寻找各种偏方,避免大家采坑,希望能帮助到大家. 报错信息 出错一:The import and ...

  8. python中1 is True 的结果为False,is判断与==判断的区别

    python中1 is True 的结果为False,而1 == True的结果为True. python中True的数值就是1,那为什么1 is True 的结果为False呢? 因为is判断和== ...

  9. C#设计模式之6-适配器模式

    适配器模式(Adapter Pattern) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/399 访问. 适配器模式属 ...

  10. C#LeetCode刷题之#706-设计哈希映射(Design HashMap)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4116 访问. 不使用任何内建的哈希表库设计一个哈希映射 具体地说 ...