元素和下标

元素是组成列表和元组的基本单元,而下标表示了元素的顺序号。只要知道某个元素的下标,那么就可以通过下标快速的定位到该元素所在的位置。

元素从1开始,一直排到最后,而下标则从0开始,一直排到最后,一定要注意,元素和下标是不一样的。

字符串比较特殊,它也可以使用元素和下标。以字符串abcdefg为例,前面提过,字符串就是由多个字符串在一起。这里每个字符就是一个元素,比如第一个元素字符a,最后一个元素字符g。相信这对初学者来说也是相当简单的。

graph TD a --> 第1个元素 b --> 第2个元素 c --> 第3个元素 d --> 第4个元素 e --> 第5个元素 f --> 第6个元素 g --> 第7个元素

接下来同样以字符串abcdefg为例,下标表示的是元素的顺序号,每个元素都有一个下标,下标从0开始。第一个元素字符a的下标是0,最后一个元素字符g的下标是6。元素和下标一定要区分开。

graph TD a --> 下标0 b --> 下标1 c --> 下标2 d --> 下标3 e --> 下标4 f --> 下标5 g --> 下标6

在代码里只用下标而不用元素,元素主要是为了方便交流。下标在变量后面用一对[]表示,在[]里的数字就表示下标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
string = 'abcdefg'
print(string[0])
print(string[1])
print(string[2])
print(string[3])
print(string[4])
print(string[5])
------运行结果---------
a
b
c
d
e
f

在可变数据类型里,通常是用下标来定位需要修改的位置、查看和获取下标元素的内容。在不可变数据类型里,都是用来查看和获取。因为不可变,所以不能进行修改。

列表(List)

列表是一种有序的集合,可以随时添加和删除其中的元素,还可以存储任意数据类型的集合,如果有过其他语言编程基础,那么列表就相当于数组,使用却比数组更简单、更方便。

列表的基本用法

列表最基本的操作就是增删改查,只有把这基本操作学会了,才能对后面的高级用法有更好的理解。

列表使用[]创建,在[]里可以是任意数据,并且数据类型可以不相同,每个元素之间用英文逗号,英文逗号,很多初学者都会在这里出错),通过下面的列子来创建一个列表。

1
2
3
4
5
6
lis = ["小明",15,1.76,True]
print(lis)
print(type(lis))
------运行结果---------
['小明', 15, 1.76, True]
<class 'list'>

例子里创建了一个列表,列表的元素有字符串、整数、浮点数和布尔值,将列表赋值给了lis变量,最后输出变量和类型,可以看到输出变量的值也是用[],说明这个输出结果是个列表,里面的元素和创建时的元素完全相同。

如果列表了什么都没有,那么称为空列表。

1
2
3
4
5
6
lis = []
print(lis)
print(type(lis))
------运行结果---------
[]
<class 'list'>

访问其实在讲解元素和下标的时候就已经大概的讲解过了,这里我们来更详细的讲讲列表元素的访问,这个点是最重要的,因为有关访问的方式很多,很自由,也是使用最多的。

从最简单的单个元素的访问开始,这里单个元素访问和前面讲到下标用法完全一致,只要在变量后面加上[],然后在[]里添上下标即可访问到需要访问的元素了。

1
2
3
4
5
6
7
8
9
10
lis = ["小明",15,1.76,True]
print(lis[0])
print(lis[1])
print(lis[2])
print(lis[3])
------运行结果---------
小明
15
1.76
True

相信大家对单个元素的访问应该的得心应手了。接下来要讲解的是反向访问,所谓的反向访问就是反着方向来访问每个元素,对于前面,我们一直使用的都是正向访问

前面讲到下标是从0开始依次加一,这是正向,从左到右,如果是反向,那么就是从-1开始,从右往左以此减一,请注意,反向是从-1开始的,不是0,这也是初学者经常范的错。比如有个列表["小明","小红","小东"],使用反向访问,从右往左,最右边的小东的下标是-1,然后小红是-2,最后小明是-3。

1
2
3
4
5
6
7
8
lis = ["小明","小红","小东"]
print(lis[-1])
print(lis[-2])
print(lis[-3])
------运行结果---------
小东
小红
小明

使用反向访问后就能从右边开始访问了,现在我们不仅可以正向,还能反向,那什么时候用正向,什么时候用反向呢?

  1. 当知道元素的位置的时候应优先使用正向,因为正向会更容易理解。
  2. 当元素数量大,且只想访问最后几个元素的时候,应使用反向,因为这样调试会更方便。

了解完正向和反向的访问后,我们就要了解更高级的访问方式了,叫做切片,就是只访问指定一段下标的元素。

切片也是用[]来表示下标,不同的是,切片在[]里多了两个英文冒号:,完整格式是[起始下标:结束下标:步数],因为切片是非常灵活的,所以拆成几步讲解。

先不考虑步数,当不考虑步数的时候,第二个冒号和步数可以省略不写,省略步数后的格式[起始下标:结束下标]。起始下标和结束下标无论用正向还是反向都是可以的。这里要重点讲的是结束下标,结束下标有些特殊,结束下标不是真正的结束位置,而正真的结束位置是结束下标减1。比如结束下标写的是3,那结束的位置是在下标2。通过例子来看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
name = ["小明","小红","小东","小磊","小黄","小白"]
# 直接打印出列表
print(name)
# 都是正向
print(name[1:4])
# 结束是反向
print(name[1:-2])
# 起始是反向
print(name[-5:4])
# 都是反向
print(name[-5:-2])
------运行结果---------
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小红', '小东', '小磊']
['小红', '小东', '小磊']
['小红', '小东', '小磊']
['小红', '小东', '小磊']

例子里无论是正向还是反向,结束的位置都是在结束下标减1,这里推荐大家使用都是正向或者结束是反向,同样的优先正向,当数量大的时候才时候反向。当起始位置是从头开始的,则可以省略起始下标。同样的当结束位置是末尾的时候,则可以省略结束下标,但是,冒号不能省略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
name = ["小明","小红","小东","小磊","小黄","小白"]
# 直接打印出列表
print(name)
# 省略起始下标
print(name[:2])
# 省略结束下标
print(name[3:])
# 起始下标和结束下标都省略
print(name[:])
------运行结果---------
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小明', '小红']
['小磊', '小黄', '小白']
['小明', '小红', '小东', '小磊', '小黄', '小白']

最后就是步数了,步数是个非常有趣的东西,有种特殊的场景里,不仅要切片,还有隔一个元素访问,这时候就可以发挥步数的作用了。

1
2
3
4
5
6
7
8
9
10
11
name = ["小明","小红","小东","小磊","小黄","小白"]
# 直接打印出列表
print(name)
# 从左到右
print(name[::2])
# 从右到左
print(name[::-2])
------运行结果---------
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小明', '小东', '小黄']
['小白', '小磊', '小红']

例子里你会发现,当步数为正数的时候,从左往右,每次下标都加上步数,当步数为负数的时候,从右往左,每次下标都减去步数。从这就能看出步数的用途了。这里还有一个小点,就是当步数为1的时候,就是相当于[起始下标:结束下标],当步数为-1的时候,就是反向访问了所有的元素。

1
2
3
4
5
6
7
8
name = ["小明","小红","小东","小磊","小黄","小白"]
# 从左到右
print(name[::1])
# 从右到左
print(name[::-1])
------运行结果---------
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小白', '小黄', '小磊', '小东', '小红', '小明']

学会了访问的知识后,你就可以随心所欲的,花式访问元素了。当然在访问的时候还有个非常重要的问题就是超出界限,也叫越界,这个知识放到最后面讲解。

删除相对来说比较简单,使用关键字del即可,删除可以分成删除某个元素和整个列表删除,当需要删除某个元素的时候,只需要在变量后面使用下标即可,而删除整个列表只需要变量。

1
2
3
4
5
6
7
name = ["小明","小红","小东","小磊","小黄","小白"]
print(name)
del name[1]
print(name)
------运行结果---------
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小明', '小东', '小磊', '小黄', '小白']

前面讲到的访问方法同样也是适用的,可以花样删除,这个留给你们自己去尝试。删除整个列表就更简单了。

1
2
3
4
5
6
7
8
9
10
name = ["小明","小红","小东","小磊","小黄","小白"]
print(name)
del name
print(name)
------运行结果---------
['小明', '小红', '小东', '小磊', '小黄', '小白']
Traceback (most recent call last):
...省略内容
print(name)
NameError: name 'name' is not defined

删除后输出了一堆从来没见过的东西,这是一种错误提示,NameError是python的错误的一种,后面是描述name ‘name’ is not defined,意思是name这个变量名没有定义,前面我们把变量name删了,那自然就没有name这个变量了。所以再使用name这个变量的时候就会出错,提示没有定义name变量。

修改同样也可以修改单个元素或者多个元素,当修改单个元素的时候使用下标,修改多个元素的时候使用切片,但是,修改多个元素的时候修改的数据也需要是个列表,修改就像赋值,需要修改的元素在左边,修改的数据在右边,被修改数据 = 修改的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
name1 = ["小明","小红","小东","小磊","小黄","小白"]
print(name1)
# 单个元素修改
name1[1] = "A"
print(name1)

name2 = ["小明","小红","小东","小磊","小黄","小白"]
print(name2)
# 多个元素修改
name2[1:3] = ["A","D"]
print(name2)
------运行结果---------
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小明', 'A', '小东', '小磊', '小黄', '小白']
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小明', 'A', 'D', '小磊', '小黄', '小白']

这里需要特别说明下修改多个元素。如果修改多个元素时,无论修改的数据里列表元素的数量是否和被修改的数据数量相同,都是可以的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 大于被修改的数量
name = ["小明","小红","小东","小磊","小黄","小白"]
print(name)
name[1:3] = ["A","D","G"]
print(name)

# 小于被修改的数量
name = ["小明","小红","小东","小磊","小黄","小白"]
print(name)
name[1:3] = ["A"]
print(name)

# 空列表,相当于删除
name = ["小明","小红","小东","小磊","小黄","小白"]
print(name)
name[1:3] = []
print(name)
------运行结果---------
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小明', 'A', 'D', 'G', '小磊', '小黄', '小白']
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小明', 'A', '小磊', '小黄', '小白']
['小明', '小红', '小东', '小磊', '小黄', '小白']
['小明', '小磊', '小黄', '小白']

列表嵌套

列表的嵌套也是比较常见的,就比如,列表里的元素也是个列表,那就是嵌套了。

1
2
3
4
5
person = [["小明",15],["小红",14]]

print(person)
------运行结果---------
[['小明', 15], ['小红', 14]]

在有嵌套情况下,访问数据也就需要一层一层的访问了。比如最外面的列表的第一个元素是[“小明”,15],这个元素也是个列表,这个列表的第一个元素是小明,那么,要直接访问到小明这个元素,则需要先访问最外层的下标0,然后接着访问里层的下标0。

1
2
3
4
5
6
7
person = [["小明",15],["小红",14]]

print(person)
print(person[0][0])
------运行结果---------
[['小明', 15], ['小红', 14]]
小明

元组(Tuple)

如果列表的能学好的话,那么元组就会变得很简单,因为元组和列表是相似的,唯一的不同就是元组的数据是不可变的,所以元组只有创建和访问,或者删除整个元组。

元组的基本用法

元组的创建使用(),也是使用英文逗号隔开每个元素。

1
2
3
4
5
6
name = ("小明", "小红", "小东", "小白", "小黄")
print(name)
print(type(name))
------运行结果---------
('小明', '小红', '小东', '小白', '小黄')
<class 'tuple'>

当创建的元组只有一个元素的时候一定一定要在元素后面加上一个逗号,因为()不仅是元组的意思,还是运算里的优先级的意思,如果不带上逗号,python会认为这是运算,还不是创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 数字类型
number = (1)
print(number)
print(type(number))

# 元组类型
number2 = (1,)
print(number2)
print(type(number2))
------运行结果---------
1
<class 'int'>
(1,)
<class 'tuple'>

看,number变量没有在元素后面加上逗号,python认为这是个运算,优先运算括号里的,而括号里并没有任何运算符号,所有就直接变成了数字了。还有,从输出的变量也能看出不同,元素是有()的。

最后就是创建空元组了,虽然空元组没什么用,但还是需要在这里讲下方法,空元组连元素都没了,那怎么创建呢?那就需要使用tuple()方法了。直接通过方法来创建元组,那就能解决创建空元组的问题。

1
2
3
4
5
6
number = tuple()
print(number)
print(type(number))
------运行结果---------
()
<class 'tuple'>

元组的访问和列表基本没什么区别,列表能怎么访问,元组也能怎么访问。

1
2
3
4
5
6
7
8
9
10
name = ("小明", "小红", "小东", "小白", "小黄")
print(name)
print(name[1])
print(name[3:])
print(name[::-1])
------运行结果---------
('小明', '小红', '小东', '小白', '小黄')
小红
('小白', '小黄')
('小黄', '小白', '小东', '小红', '小明')

元组的删除只能是删除整个元组,同样是用del关键字来删除。

1
2
3
4
5
6
7
8
9
10
number = (1,2)
print(number)
del number
print(number)
------运行结果---------
(1, 2)
Traceback (most recent call last):
...省略部分
print(number)
NameError: name 'number' is not defined

越界

越界主要是指,试图访问不存在的元素而引起的一种错误,比如列表有6个元素,最后一个元素的下标是5,而我试图去访问下标6,那么就会引发越界错误。能发生越界的一般都是列表、元组和字符串,越界也是非常头疼的一种错误,如果不能清楚的知道元素的数量,那么就很容已越界。

通过代码来看下越界引发的过程

1
2
3
4
5
6
7
8
9
10
11
12
13
name = ["小明","小红","小东"]
print(name[0])
print(name[1])
print(name[2])
print(name[3])
------运行结果---------
小明
小红
小东
Traceback (most recent call last):
...省略部分
print(name[3])
IndexError: list index out of range

这里创建了一个拥有3个元素的列表,当访问前3个元素的时候,完全没什么问题,当试图去访问第4个元素的时候,就报错了,IndexError错误,这是个索引错误,也可以叫越界错误或者下标错误。这个错误是最常见的,很多时候都会范这个错误。错误的描述是list index out of range,意思是列表的索引超出范围,也就是越界的意思。