Python基础语法(三)

Python基础语法(三)

列表和元组

列表是什么, 元组是什么

编程中, 经常需要使用变量, 来保存/表示数据.

如果代码中需要表示的数据个数比较少, 我们直接创建多个变量即可

num1 = 10
num2 = 20
num3 = 30
......

但是有的时候, 代码中需要表示的数据特别多, 甚至也不知道要表示多少个数据. 这个时候, 就需要用到列表.

列表是一种让程序猿在代码中批量表示/保存数据的方式

就像我们去超市买辣条, 如果就只是买一两根辣条, 那咱们直接拿着辣条就走了.

但是如果一次买个十根八根的, 这个时候用手拿就不好拿, 超市老板就会给我们个袋子.

这个袋子, 就相当于 列表

元组和列表相比, 是非常相似的, 只是列表中放哪些元素可以修改调整, 元组中放的元素是创建元组的时 候就设定好的, 不能修改调整.

创建列表

  • 创建列表主要有两种方式. [ ] 表示一个空的列表。
alist = [ ]

alist = list()

print(type(alist))
  • 如果需要往里面设置初始值, 可以直接写在 [ ] 当中.

可以直接使用 print 来打印 list 中的元素内容

alist = [1, 2, 3, 4]

print(alist)
  • 列表中存放的元素允许是不同的类型. (这一点和 C++ Java 差别较大).
alist = [1, 'hello', True]
print(alist)

因为 list 本身是 Python 中的内建函数, 不宜再使用 list 作为变量名, 因此命名为 alist

访问下标

  • 可以通过下标访问操作符 [ ] 来获取到列表中的任意元素.

我们把 [ ] 中填写的数字, 称为 下标 或者 索引 .

alist = [1, 2, 3, 4]
print(alist[2])

image-20221229204537902

注意: 下标是从 0 开始计数的, 因此下标为 2 , 则对应着 3 这个元素.

  • 通过下标不光能读取元素内容, 还能修改元素的值.
alist = [1, 2, 3, 4]
alist[2] = 100
print(alist)
  • 如果下标超出列表的有效范围, 会抛出异常.
alist = [1, 2, 3, 4]
print(alist[100])

image-20221229204911509

  • 因为下标是从 0 开始的, 因此下标的有效范围是 [0, 列表长度 - 1]. 使用 len 函数可以获取到列表的 元素个数.

    alist = [1, 2, 3, 4]
    print(len(alist))
    
  • 下标可以取负数. 表示 “倒数第几个元素”

    alist = [1, 2, 3, 4]
    print(alist[3])
    print(alist[-1])
    

    alist[-1] 相当于 alist[len(alist) - 1]

    切片操作

    通过下标操作是一次取出里面第一个元素.

    通过切片, 则是一次取出一组连续的元素, 相当于得到一个子列表

    • 使用 [ : ] 的方式进行切片操作.
alist = [1, 2, 3, 4]
print(alist[1:3])

image-20221229205250920

alist[1:3] 中的 1:3 表示的是 [1, 3) 这样的由下标构成的前闭后开区间.

也就是从下标为 1 的元素开始(2), 到下标为 3 的元素结束(4), 但是不包含下标为 3 的元素.

所以最终结果只有 2, 3

  • 切片操作中可以省略前后边界
alist = [1, 2, 3, 4]
print(alist[1:])        # 省略后边界, 表示获取到列表末尾
print(alist[:-1])       # 省略前边界, 表示从列表开头获取
print(alist[:])         # 省略两个边界, 表示获取到整个列表
Python基础语法(三)_第1张图片
  • 切片操作还可以指定 “步长” , 也就是 “每访问一个元素后, 下标自增几步”
alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(alist[::1])
print(alist[::2])
print(alist[::3])
print(alist[::5])

Python基础语法(三)_第2张图片

  • 切片操作指定的步长还可以是负数, 此时是从后往前进行取元素. 表示 “每访问一个元素之后, 下标自减几步”
alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(alist[::-1])
print(alist[::-2])
print(alist[::-3])
print(alist[::-5])

Python基础语法(三)_第3张图片

  • 如果切片中填写的数字越界了, 不会有负面效果. 只会尽可能的把满足条件的元素过去到.
alist = [1, 2, 3, 4]
print(alist[100:200])
image-20221229205823689

遍历列表元素

“遍历” 指的是把元素一个一个的取出来, 再分别进行处理.

  • 最简单的办法就是使用 for 循环
alist = [1, 2, 3, 4]

for elem in alist:
    print(elem)
  • 也可以使用 for 按照范围生成下标, 按下标访问
alist = [1, 2, 3, 4]

for i in range(0, len(alist)):
    print(alist[i])
  • 还可以使用 while 循环. 手动控制下标的变化
alist = [1, 2, 3, 4]

i = 0
while i < len(alist):
    print(alist[i])
    i += 1

新增元素

  • 使用 append 方法, 向列表末尾插入一个元素(尾插).
alist = [1, 2, 3, 4]
alist.append('hello')
print(alist)

image-20221229210117451

  • 使用 insert 方法, 向任意位置插入一个元素

insert 第一个参数表示要插入元素的下标

alist = [1, 2, 3, 4]
alist.insert(1, 'hello')
print(alist)

image-20221229210243464

PS: 什么是 “方法” (method)

方法其实就是函数. 只不过函数是独立存在的, 而方法往往要依附于某个 “对象”.

像上述代码 alist.append , append 就是依附于 alist, 相当于是 “针对 alist 这个列表, 进行尾插操作”.

查找元素

  • 使用 in 操作符, 判定元素是否在列表中存在. 返回值是布尔类型.
alist = [1, 2, 3, 4]
print(2 in alist)
print(10 in alist)

image-20221229210352352

  • 使用 index 方法, 查找元素在列表中的下标. 返回值是一个整数. 如果元素不存在, 则会抛出异常.\
alist = [1, 2, 3, 4]
print(alist.index(2))
print(alist.index(10))

删除元素

  • 使用 pop 方法删除最末尾元素
alist = [1, 2, 3, 4]
alist.pop()
print(alist)

image-20221229210528429

  • pop 也能按照下标来删除元素
alist = [1, 2, 3, 4]
alist.pop(2)
print(alist)

image-20221229210628686

  • 使用 remove 方法, 按照值删除元素
alist = [1, 2, 3, 4]
alist.remove(2)
print(alist)

image-20221229210723720

连接列表

  • 使用 + 能够把两个列表拼接在一起.

此处的 + 结果会生成一个新的列表. 而不会影响到旧列表的内容.

alist = [1, 2, 3, 4]
blist = [5, 6, 7]
print(alist + blist)

image-20221229210841427

  • 使用 extend 方法, 相当于把一个列表拼接到另一个列表的后面.

    a.extend(b) , 是把 b 中的内容拼接到 a 的末尾. 不会修改 b, 但是会修改 a.

alist = [1, 2, 3, 4]
blist = [5, 6, 7]
alist.extend(blist)
print(alist)
print(blist)

image-20221229211004626

关于元组

元组的功能和列表相比, 基本是一致的.

元组使用 ( ) 来表示.

atuple = ( )
atuple = tuple()

元组不能修改里面的元素, 列表则可以修改里面的元素

因此, 像读操作,比如访问下标, 切片, 遍历, in, index, + 等, 元组也是一样支持的.

但是, 像写操作, 比如修改元素, 新增元素, 删除元素, extend 等, 元组则不能支持.

另外, 元组在 Python 中很多时候是默认的集合类型. 例如, 当一个函数返回多个值的时候.

def getPoint():
    return 10, 20
    
result = getPoint()
print(type(result))

image-20221229211244209

此处的 result 的类型, 其实是元组.

问题来了, 既然已经有了列表, 为啥还需要有元组?

元组相比于列表来说, 优势有两方面:

  • 你有一个列表, 现在需要调用一个函数进行一些处理. 但是你有不是特别确认这个函数是否会把你的列表数据弄乱. 那么这时候传一个元组就安全很多.
  • 我们马上要讲的字典, 是一个键值对结构. 要求字典的键必须是 “可hash对象” (字典本质上也 是一个hash表). 而一个可hash对象的前提就是不可变. 因此元组可以作为字典的键, 但是列表 不行.

小结

列表和元组都是日常开发最常用到的类型. 最核心的操作就是根据 [ ] 来按下标操作.

在需要表示一个 “序列” 的场景下, 就可以考虑使用列表和元组.

如果元素不需要改变, 则优先考虑元组.

如果元素需要改变, 则优先考虑列表.

字典

字典是什么

字典是一种存储 键值对 的结构.

啥是键值对? 这是计算机/生活中一个非常广泛使用的概念.

把 键(key) 和 值(value) 进行一个一对一的映射, 然后就可以根据键, 快速找到值.

举个栗子, 学校的每个同学, 都会有一个唯一的学号.

知道了学号, 就能确定这个同学.

此处 “学号” 就是 “键”, 这个 “同学” 就是 “值”.

创建字典

  • 创建一个空的字典. 使用 { } 表示字典

    a = { }
    b = dict()
    
    print(type(a))
    print(type(b))
    
    • 也可以在创建的同时指定初始值
    • 键值对之间使用 , 分割, 键和值之间使用 : 分割. (冒号后面推荐加一个空格).
    • 使用 print 来打印字典内容
    student = { 'id': 1, 'name': 'zhangsan' }
    print(student)
    

    image-20221229212208054

  • 为了代码更规范美观, 在创建字典的时候往往会把多个键值对, 分成多行来书写.

student = {
    'id': 1,
    'name': 'zhangsan'
}
  • 最后一个键值对, 后面可以写 , 也可以不写.
student = {
    'id': 1,
    'name': 'zhangsan',
}

查找 key

  • 使用 in 可以判定 key 是否在 字典 中存在. 返回布尔值
student = {
    'id': 1,
    'name': 'zhangsan',
}

print('id' in student)
print('score' in student)

image-20221229212505739

  • 使用 [ ] 通过类似于取下标的方式, 获取到元素的值. 只不过此处的 “下标” 是 key. (可能是整数, 也 可能是字符串等其他类型).
student = {
    'id': 1,
    'name': 'zhangsan',
}

print(student['id'])
print(student['name'])

image-20221229212540229

  • 如果 key 在字典中不存在, 则会抛出异常.
student = {
    'id': 1,
    'name': 'zhangsan',
}

print(student['score'])

image-20221229212635827

新增/修改元素

使用 [ ] 可以根据 key 来新增/修改 value.

  • 如果 key 不存在, 对取下标操作赋值, 即为新增键值对
student = {
    'id': 1,
    'name': 'zhangsan',
}

student['score'] = 90
print(student)

image-20221229212758977

  • 如果 key 已经存在, 对取下标操作赋值, 即为修改键值对的值.
student = {
    'id': 1,
    'name': 'zhangsan',
    'score': 80
}

student['score'] = 90
print(student)

image-20221229212852297

删除元素

  • 使用 pop 方法根据 key 删除对应的键值对.
student = {
    'id': 1,
    'name': 'zhangsan',
    'score': 80
}

student.pop('score')
print(student)

image-20221229213038470

遍历字典元素

直接使用 for 循环能够获取到字典中的所有的 key, 进一步的就可以取出每个值了.

student = {
    'id': 1,
    'name': 'zhangsan',
    'score': 80
}

for key in student:
    print(key, student[key])

Python基础语法(三)_第4张图片

取出所有 key 和 value

  • 使用 keys 方法可以获取到字典中的所有的 key
student = {
    'id': 1,
    'name': 'zhangsan',
    'score': 80
}

print(student.keys())

image-20221229213421266

此处 dict_keys 是一个特殊的类型, 专门用来表示字典的所有 key. 大部分元组支持的操作对于 dict_keys 同样适用.

  • 使用 values 方法可以获取到字典中的所有 value
student = {
    'id': 1,
    'name': 'zhangsan',
    'score': 80
}

print(student.values())

image-20221229213600177

此处 dict_values 也是一个特殊的类型, 和 dict_keys 类似

  • 使用 items 方法可以获取到字典中所有的键值对.
student = {
    'id': 1,
    'name': 'zhangsan',
    'score': 80
}

print(student.items())

image-20221229213705164

此处 dict_items 也是一个特殊的类型, 和 dict_keys 类似.

合法的 key 类型

不是所有的类型都可以作为字典的 key.

字典本质上是一个 哈希表, 哈希表的 key 要求是 “可哈希的”, 也就是可以计算出一个哈希值.

  • 可以使用 hash 函数计算某个对象的哈希值.

  • 但凡能够计算出哈希值的类型, 都可以作为字典的 key.

print(hash(0))
print(hash(3.14))
print(hash('hello'))
print(hash(True))
print(hash(()))           # ( ) 是一个空的元组

Python基础语法(三)_第5张图片

  • 列表无法计算哈希值.
print(hash([1, 2, 3]))
image-20221229214010013
  • 字典也无法计算哈希值
print(hash({ 'id': 1 }))

image-20221229214053813

小结

字典也是一个常用的结构. 字典的所有操作都是围绕 key 来展开的. 需要表示 “键值对映射” 这种场景时就可以考虑使用字典.

文件

文件是什么

变量是把数据保存到内存中. 如果程序重启/主机重启, 内存中的数据就会丢失.

要想能让数据被持久化存储, 就可以把数据存储到硬盘中. 也就是在 文件 中保存.

在 Windows “此电脑” 中, 看到的内容都是 文件.

通过文件的后缀名, 可以看到文件的类型. 常见的文件的类型如下:

  • 文本文件 (txt)
  • 可执行文件 (exe, dll)
  • 图片文件 (jpg, gif)
  • 视频文件 (mp4, mov)
  • office 文件 (.ppt, docx)

文件路径

一个机器上, 会存在很多文件, 为了让这些文件更方面的被组织, 往往会使用很多的 “文件夹”(也叫做目录) 来整理文件.

实际一个文件往往是放在一系列的目录结构之中的.

为了方便确定一个文件所在的位置, 使用 文件路径来进行描述.

例如, 上述截图中的 QQ.exe 这个文件, 描述这个文件的位置, 就可以使用路径 D:\program\qq\Bin\QQ.exe 来表示.

  • D: 表示 盘符. 不区分大小写.
  • 每一个 \ 表示一级目录. 当前 QQ.exe 就是放在 “D 盘下的 program 目录下的 qq 目录下的 Bin 目 录中” .
  • 目录之间的分隔符, 可以使用 \ 也可以使用 / . 一般在编写代码的时候使用 / 更方便.

上述以 盘符 开头的路径, 我们也称为 绝对路径. 除了绝对路径之外, 还有一种常见的表示方式是 相对路径. 相对路径需要先指定一个基准目录, 然后 以基准目录为参照点, 间接的找到目标文件. 咱们课堂上暂时不详细介绍. 描述一个文件的位置, 使用 绝对路径 和 相对路径 都是可以的. 对于新手来说, 使用 绝对路径 更简 单更好理解, 也不容易出错.

文件操作

要使用文件, 主要是通过文件来保存数据, 并且在后续把保存的数据读取出来.

但是要想读写文件, 需要先 “打开文件”, 读写完毕之后还要 “关闭文件”.

1. 打开文件

使用内建函数 open 打开一个文件.

f = open('d:/test.txt', 'r')
  • 第一个参数是一个字符串, 表示要打开的文件路径

  • 第二个参数是一个字符串, 表示打开方式. 其中 r 表示按照读方式打开. w 表示按照写方式打开. a 表示追加写方式打开.

  • 如果打开文件成功, 返回一个文件对象. 后续的读写文件操作都是围绕这个文件对象展开.

  • 如果打开文件失败(比如路径指定的文件不存在), 就会抛出异常.

image-20221229215048922

2. 关闭文件

使用 close 方法关闭已经打开的文件.

f.close()

使用完毕的文件要记得及时关闭!

一个程序能同时打开的文件个数, 是存在上限的.

flist = []
count = 0
while True:
    f = open('d:/test.txt', 'r')
    flist.append(f)
    count += 1
    print(f'count = {count}')

如上面代码所示, 如果一直循环的打开文件, 而不去关闭的话, 就会出现上述报错.

当一个程序打开的文件个数超过上限, 就会抛出异常.

注意: 上述代码中, 使用一个列表来保存了所有的文件对象. 如果不进行保存, 那么 Python 内置的垃 圾回收机制, 会在文件对象销毁的时候自动关闭文件.

但是由于垃圾回收操作不一定及时, 所以我们写代码仍然要考虑手动关闭, 尽量避免依赖自动关闭.

3. 写文件

文件打开之后, 就可以写文件了.

  • 写文件, 要使用写方式打开, open 第二个参数设为 ‘w’
  • 使用 write 方法写入文件.
f = open('d:/test.txt', 'w')
f.write('hello')
f.close()

image-20221229215754267

用记事本打开文件, 即可看到文件修改后的内容.

  • 如果是使用 ‘r’ 方式打开文件, 则写入时会抛出异常.
f = open('d:/test.txt', 'r')
f.write('hello')
f.close()

image-20221229215849484

  • 使用 ‘w’ 一旦打开文件成功, 就会清空文件原有的数据.
  • 使用 ‘a’ 实现 “追加写”, 此时原有内容不变, 写入的内容会存在于之前文件内容的末尾.
f = open('d:/test.txt', 'w')
f.write('hello')
f.close()

f = open('d:/test.txt', 'a')
f.write('world')
f.close()
  • 使用 ‘w’ 一旦打开文件成功, 就会清空文件原有的数据.
  • 使用 ‘a’ 实现 “追加写”, 此时原有内容不变, 写入的内容会存在于之前文件内容的末尾.
f = open('d:/test.txt', 'w')
f.write('hello')
f.close()

f = open('d:/test.txt', 'a')
f.write('world')
f.close()

image-20221229220018071

  • 针对已经关闭的文件对象进行写操作, 也会抛出异常.
f = open('d:/test.txt', 'w')
f.write('hello')
f.close()
f.write('world')

4. 读文件

  • 读文件内容需要使用 ‘r’ 的方式打开文件
  • 使用 read 方法完成读操作. 参数表示 “读取几个字符”
f = open('d:/test.txt', 'r')
result = f.read(2)
print(result)
f.close()

image-20221229220226320

  • 如果文件是多行文本, 可以使用 for 循环一次读取一行.

Python基础语法(三)_第6张图片

先构造一个多行文件.

f = open('d:/test.txt', 'r')
for line in f:
    print(f'line = {line}')
f.close()

注意: 由于文件里每一行末尾都自带换行符, print 打印一行的时候又会默认加上一个换行符, 因此 打印结果看起来之间存在空行.

使用 print(f’line = {line}‘, end=’') 手动把 print 自带的换行符去掉.

  • 使用 readlines 直接把文件整个内容读取出来, 返回一个列表. 每个元素即为一行.

    f = open('d:/test.txt', 'r')
    lines = f.readlines()
    print(lines)
    f.close()
    

    image-20221229220608274

此处的 \n 即为换行符.

关于中文的处理

当文件内容存在中文的时候, 读取文件内容不一定就顺利. 同样上述代码, 有的同学执行时可能会出现异常

image-20221229220818499

计算机表示中文的时候, 会采取一定的编码方式, 我们称为 “字符集”

所谓 “编码方式” , 本质上就是使用数字表示汉字.

我们知道, 计算机只能表示二进制数据. 要想表示英文字母, 或者汉字, 或者其他文字符号, 就都要通 过编码.

最简单的字符编码就是 ascii. 使用一个简单的整数就可以表示英文字母和阿拉伯数字.

但是要想表示汉字, 就需要一个更大的码表.

一般常用的汉字编码方式, 主要是 GBK 和 UTF-8

必须要保证文件本身的编码方式, 和 Python 代码中读取文件使用的编码方式匹配, 才能避免出现上述问题.

Python3 中默认打开文件的字符集跟随系统, 而 Windows 简体中文版的字符集采用了 GBK, 所以 如果文件本身是 GBK 的编码, 直接就能正确处理.

如果文件本身是其他编码(比如 UTF-8), 那么直接打开就可能出现上述问题

使用记事本打开文本文件, 在 “菜单栏” -> “文件” -> “另存为” 窗口中, 可以看到当前文件的编码方式.

image-20221229221031544

  • 如果此处的编码为 ANSI , 则表示 GBK 编码.
  • 如果此处为 UTF-8 , 则表示 UTF-8 编码.

此时修改打开文件的代码, 给 open 方法加上 encoding 参数, 显式的指定为和文本相同的字符集, 问题 即可解决.

f = open('d:/test.txt', 'r', encoding='utf8')

PS: 字符编码问题, 是编程中一类比较常见, 又比较棘手的问题. 需要对于字符编码有一定的理解, 才 能从容应对.

使用上下文管理器

打开文件之后, 是容易忘记关闭的. Python 提供了 上下文管理器 , 来帮助程序猿自动关闭文件.

  • 使用 with 语句打开文件.
  • 当 with 内部的代码块执行完毕后, 就会自动调用关闭方法
with open('d:/test.txt', 'r', encoding='utf8') as f:
    lines = f.readlines()
    print(lines)

你可能感兴趣的:(Python,python,开发语言)