专业编程基础技术教程

网站首页 > 基础教程 正文

1.4「Python」第四章 序列

ccvgpt 2024-11-27 12:05:27 基础教程 6 ℃

人工智能入门与实战第一季:python基础语法


1.4「Python」第四章 序列

什么是序列?

序列指的是一种包含多项数据的容器,序列包含的多个数据项按顺序排列,可通过索引来访问成员。


以上序列我们命名为pro_lans,存储了四个数据项:python、java、PHP、100

分别对应的索引范围:[0, 3];索引也可以为负值:[-4, -1];两者等价,均对应第一个数据一直到第四个数据。

于是我们可以知道,pro_lans[0]、pro_lans[-4]均表示序列中的第一个数据'python'

python有三种基本序列:list、tuple、range

其中list是可变序列,即可以对其存储的数据进行修改;tuple、range是不可变序列,即无法对其存储的数据进行修改,只能提取。

列表:list

列表是可变序列,是最常用的序列之一。

列表的几种创建方式

1、使用一对方括号来表示空列表

list1 = []

2、使用方括号,其中的项以逗号分隔

list2 = ["python","java","PHP","swift"]

3、使用列表推导式(后面学到循环语句会更容易理解)

list3 = [1,2,3,4]
list4 = [x for x in list3]
#把list3中的数乘以2再存到list5中
list5 = [x*2 for x in list3]
print(list4)
print(list5)

输出结果:

[1, 2, 3, 4]
[2, 4, 6, 8]

思路扩展:找出list3中的偶数

# x % 2 == 0表示能够被2整除
list5_even = [x for x in list3 if x % 2 == 0]
print(list5_even)

输出结果:

[2, 4]

4、使用类型的构造器

#使用字符串
s = "hello"
list6 = list(s)
print(list6)

#使用元组
t = (1,2,3)
list7 = list(t)
print(list7)

#使用range 
list8 = list(range(1,10,2))
print(list8)

输出结果:

['h', 'e', 'l', 'l', 'o']
[1, 2, 3]
[1, 3, 5, 7, 9]

元组tuple、range的用法本章后面会讲述

序列的通用操作

list、tuple、range 均具有以下操作:



以上这个表格的内容是我从官网直接拿过来的,不是我懒惰而是官网总结的已经很完善,这些操作是不是似曾相识,是的,我们在字符串那一章节已经讲过,因为字符串也是序列。

有个细节需要注意的是以上的运算优先级按升序排列,也就是越向下优先级越高,如果以上操作放在一个表达式里面我们需要了解他们运算的优先级,我们在第二章也提到了运算符的优先级。

下面开始对上述各种操作进行举例,我们使用list举例,案例中用到的列表我们在这里提前定义好:

pro_lans = ['python', 'php', 'java', 'swift']
other_pro_lans = ['r', 'go', 'js']

1、in、not in

print('python' in pro_lans)
print('ruby' in pro_lans)

输出结果:

True
False

2、序列拼接 +

print(pro_lans + other_pro_lans)

输出结果:

['python', 'php', 'java', 'swift', 'r', 'go', 'js']

这里需要注意的是拼接不可变序列会生成新的对象,会产生额外的性能开销,所以对于不可变序列,在拼接时请查看具体对应的文档说明,这里就不深入讨论了。

3、序列复制

print(pro_lans * 2)

输出结果:

['python', 'php', 'java', 'swift', 'python', 'php', 'java', 'swift']

4、通过索引访问序列元素
以pro_lans列表举例,它的正值索引范围[0, len(pro_lans)-1],即[0, 3];负值索引范围[-len(pro_lans), -1],即 [-4, -1]

print('pro_lans的长度:%d' % len(pro_lans))

输出结果:

pro_lans的长度:4

索引0和索引-4表示的是同一个数据

print(pro_lans[0], pro_lans[-4])
# print(pro_lans[4])   # 索引超出范围会报错 IndexError: list index out of range

输出结果:

python python

python中序列的索引值可以为负值,这在其他编程语言中很少见,这就是python语言的便捷之处,实际上在用负值作为索引的时候,python会自动将其转换成正值索引,例如pro_lans[-4],会做如下转换:pro_lans[-4 + len(pro_lans) ],转换之后即为pro_lans[0]

5、切片
切片在字符串章节已经做了详细的讲解,这里再次以list举例,操作完全一样

print(pro_lans[:])  # 输出全部,等价于print(pro_lans[0:4:1]),输出的索引范围[0, 3],步长1

print(pro_lans[1:3])  # 输出索引为[1, 2]的元素

print(pro_lans[::2])  # 步长为2,从第一个开始,每次跳过一个输出
print(pro_lans[-1::-1])  # 步长为-1,从最后一个开始,倒序输出,简写:print(pro_lans[::-1])
print(pro_lans[-2:])   # 从倒数第二个开始输出,直到最后

输出结果:

['python', 'php', 'java', 'swift']
['php', 'java']
['python', 'java']
['swift', 'java', 'php', 'python']
['java', 'swift']

6、计算序列的长度、最大项、最小项(格式化输出如果忘了请参考第三章字符串)

print("序列pro_lans的长度:%d" % len(pro_lans))
print("序列pro_lans的最小项:%s" % min(pro_lans))   # 字符比较的是对应的ASCII码值
print("序列pro_lans的最大项:%s" % max(pro_lans))   # 字符比较的是对应的ASCII码值

输出结果:

序列pro_lans的长度:4
序列pro_lans的最小项:java
序列pro_lans的最大项:swift

补充知识:ASCII,美国标准信息交换代码,简单理解即每个字母、符号在计算机中都有一个对应的编码。

print(ord('A'))  # 打印字符A对应的ASCII码值
print(chr(66))  # 把ASCII码值转成对应的字符

输出结果:

65
B

7、index 方法

print(pro_lans.index('java'))  # 等价于pro_lans.index('java', 0, 3),即在索引[0, 3]范围内查找
# print(pro_lans.index('java', 0, 1))  # 在索引[0,1]范围内查找,查找不到,会报错 ValueError: 'java' is not in list

输出结果:

2

对于上面的报错语句,我们可以使用try: except: 捕捉异常,并处理:

try:
    print(pro_lans.index('java', 0, 1))
except ValueError:
    print('sorry,在你给的范围内没找到')

所以我们在写程序的过程中对于可能存在的不确定性可以通过异常捕获来增加程序的健壮性,关于异常处理,后面章节会详细讲解。

8、count 方法

print(pro_lans.count('python'))

输出结果:

1

可变序列操作

list是可变序列,所以list拥有以下操作:



这个表格的内容依然是从官网拿过来的,这些操作是专门针对可变序列的,因为我们发现这些操作都做了同样一件事,那就是在修改序列。所以tuple、range、str这些不可变序列将不具有这些操作能力。

接下来依然以列表list来举例说明这些操作的用法,但这一次我不打算全部举例,没有讲到的操作可以作为你的练习,可以自己动手试一试。

这里我要提前申明一下,由于我们下面的每一个操作都会修改列表的内容,为了避免影响演示效果,我们假设每次使用的list都是如下list:

pro_lans = ['python', 'php', 'java', 'swift']
other_pro_lans = ['r', 'go', 'js']

1、通过索引修改对应的数据

pro_lans[1] = 'oc'
print(pro_lans)

输出结果:

['python', 'oc', 'java', 'swift']

2、通过切片来批量替换

pro_lans[1:4] = other_pro_lans
print(pro_lans)

输出结果:

['python', 'r', 'go', 'js']

我们发现列表pro_lans从第2个元素开始一直到最后全部被替换成列表other_pro_lans的数据了,真的很方便,有没有?

3、使用del通过索引从列表中删除元素

del pro_lans[1]
print(pro_lans)

输出结果:

['python', 'java', 'swift']

也可以通过切片的方式进行批量删除,这个不再举例了。

4、通过remove删除指定的元素

pro_lans.remove('python')
print(pro_lans)

输出结果:

['php', 'java', 'swift']

5、通过append方法添加元素

pro_lans.append('asp')
print(pro_lans)

输出结果:

['python', 'php', 'java', 'swift', 'asp']

6、通过insert方法插入元素

pro_lans.insert(1,'x')
print(pro_lans)

输出结果:

['python', 'x', 'php', 'java', 'swift']

7、使用sort方法给列表排序
为了演示效果,我们创建一个使用数字组成的列表:

num_list = [9, 6, 3, 1, 2, 5, 8]
# 默认升序,reverse=True 降序
num_list.sort()
# num_list.sort(reverse=True)
print(num_list)

输出结果:

[1, 2, 3, 5, 6, 8, 9]

多维列表

我们知道列表中可以存放任何对象,当然也可以存放列表,我们把列表other_pro_lans存放到列表pro_lans中

pro_lans.append(other_pro_lans)
print(pro_lans)

输出结果:

['python', 'php', 'java', 'swift', ['r', 'go', 'js']]

访问多维列表中的数据

print(pro_lans[-1])
print(pro_lans[-1][0])
print(pro_lans[4][0])

输出结果:

['r', 'go', 'js']
r
r

一个关于内存的有趣问题

我们创建一个以列表为元素的列表,即二维列表

lists = [[]] * 3
print(lists)

输出结果:

[[], [], []]

现在向其中一个子列表存放数据,结果我们发现其他子列表包含了同样的数据,为什么?

lists[0].append(3)
print(lists)

输出结果:

[[3], [3], [3]]

我们打印三个子列表的内存地址,发现都是同一个内存地址,也就是说这三个子列表是同一个列表。

sub_list1 = lists[0]
sub_list2 = lists[1]
sub_list3 = lists[2]
print(id(sub_list1))
print(id(sub_list2))
print(id(sub_list3))

输出结果:

4469333896
4469333896
4469333896

所以我们得出的结论是 [[]] * 3 操作并没有创建三个空列表,而是一个空列表被引用了三次,画个内存图你就清楚了(图画的丑了点):


如果要避免以上问题,我们可以这样来创建以不同列表为元素的列表:

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

输出结果:

[[3], [5], [7]]

如果你对程序的内存感兴趣的话,还可以了解一下list的深拷贝、浅拷贝等内容,AI方向的同学,关于内存的相关内容了解即可。

元组tuple

我们知道元组是不可变的序列,同样可以存储多项数据。

元组的几种创建方式

1、使用一对圆括号来表示空元组

t1 = ()

2、使用一个后缀的逗号来表示单元组(如果只有一个元素不加逗号,创建的类型不是元组,这点需要注意)

t2 = 1,
t3 = (1,)
print(t2)
print(t3)

输出结果:

(1,)
(1,)

3、使用以逗号分隔的多个项

t4 = (1, 2, 3)
print(t4)

输出结果:

(1, 2, 3)

4、使用构造器将构造一个元组

t5 = tuple()
t6 = tuple('abc')
t7 = tuple([1, 2, 3])
print(t5)
print(t6)
print(t7)

输出结果:

()
('a', 'b', 'c')
(1, 2, 3)

元组的操作

元组拥有序列的通用操作,即拥有在序列通用操作表格中的所有操作,我们拿出部分操作举例,先定义两个元组:

class1 = ('james', 'tom', 'judy')
class2 = ('lilei', 'hanmeimei')

1、拼接、复制

print(class1 + class2)
print(class1 * 2)

输出结果:

('james', 'tom', 'judy', 'lilei', 'hanmeimei')
('james', 'tom', 'judy', 'james', 'tom', 'judy')

2、通过索引访问序列元素

print(class1[1])

输出结果:

tom

元组其他操作可以参考list的讲解,这里就不一一举例了。

到这里我们发现元组tuple和列表list除了一个是不可变序列,一个是可变序列之外,似乎没有其他区别,是的,在使用场景上如果我们存储的数据不会被修改,那么我们首选是元组tuple,如果存储的数据需求修改则使用列表list。

由于列表list是可变序列,所以不可以作为字典的键、不能作为集合的元素,而元组tuple则可以,这一点了解即可。

range

range是不可变的数字序列,通常用于在 for循环中循环指定的次数,也常用来创建list

range的创建

range必须通过构造器来创建:range(start, stop[, step])
start为起始整数元素,如果省略 start 参数,其默认值为 0
stop为结束整数元素,但不包含
step为步长,是整数元素,可为正负,但不可为0,如果省略 step 参数,其默认值为 1

r = range(0, 20, 2)
print(r)

输出结果:

range(0, 20, 2)

使用range创建list

print(list(range(0, 20, 2)))

输出结果:

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

使用range在for循环中

在后面的控制语句中会一起讲解

range的操作

range是不可变序列,拥有序列的通用操作,可以参考list的讲解,但是拼接和复制除外。

print(1 in r)
print(2 in r)
print(r[1])

输出结果:

False
True
2

本章作业

1、回顾一下list、tuple、range的创建方式都有哪些?
2、创建一个列表叫names,里面存放你朋友的名字,最后再把你的新朋友"猪弟爸爸",放在names中的倒数第1个位置。
3、使用range生成一个1-20之间的奇数列表

本章总结

学完本章之后,我们需要掌握下面几个知识点,第一个是序列有哪几种类型?第二个是列表list和元组tuple、range有何区别?以及他们在何种场合使用?最后我们要掌握序列的通用操作和可变序列的特殊操作。本章的内容就到这里, 我是猪弟爸爸,有问题给我留言,我们下节见!

Tags:

最近发表
标签列表