Python基础
Python是由荷兰人吉多·范罗苏姆(Guido van Rossum)在 1989 年在圣诞节期间创建、1991 年发布的高级编程语言,以简洁易读著称。
越是接近人类的语言就越高级,python就是高级编程语言。相反,越接近机器语言的就越低级,例如汇编。
Python的特点主要有语法简洁、代码量较少、类库强大等特点。
在机器学习领域提供了sklearn,在深度学习领域提供了Pytorch、TensorFlow等方便的库供我们使用,这也是笔者学习Python的主要原因。
1. 基础知识
1.1. 输入输出
输出函数 print()
1 | print() # 括号中填需要输出的内容 |
输入函数 input()
1 | input() # 括号中填需要输入的内容 |
1.2. 缩进
这里要着重说一下python中的缩进,与大多数语言使用{}来表示代码归属不同,python使用缩进来表示代码归属,所以python的缩进一定要严格。python官方推荐使用4个空格作为一级缩进。
1.3. 注释
单行注释
井号
1 | # 这是一个单行注释 |
多行注释
多个井号
1 | #这是一个 |
三引号或三双引号
1 | """ |
这里需要注意三引号的本质,三引号并不是真正的注释而是多行字符串。因为这里并没有赋值给变量,解释器创建后会将其丢弃,因此可以作为多行注释的一种偷懒写法。这也是为什么在代码块中这里显示的是代表字符串的颜色而不是代表注释的颜色。
2. 变量
2.1. 变量需要符合标识符的命名规则
标识符的命名规则:
(1) 字母、数字、下划线组成
(2) 不可以数字开头
(3) 大小写敏感
(4) 不能使用关键字和保留字
2.2 行业通用规范(PEP8规范)
(1) 普通变量:蛇形命名(snake_case)
全部小写,单词之间使用下划线分隔
1 | user_name = "Supzj" |
(2) 常量:
全大写+下划线
1 | PI = 3.14159 |
(3) 类名:大驼峰(PascalCase)
每个单词首字母大写
1 | class UserInfo: |
(4) 私有变量:
单下划线开头,字母小写
1 | _user_pwd = "123456" |
3. 数据类型
3.1 数据类型的分类
(1) 整型(int):
整数
1 | a = 5 |
(2) 浮点型(float):
小数
1 | a = 0.5 |
科学计数法
1 | a = 1e8 # 1 * 10^8 |
(3) 字符串(string):
中英文
1 | a = 'str' |
单引号和双引号换行需要打换行符:\n,三引号和三双引号内部可以直接换行,无需打换行符。除此之外单双引号本质上基本没有差别
(4) 布尔值(bool):
真/假,0/1,True/False
1 | a = True |
(5) 空(None):
没有值/空值/什么都没有
1 | a = None |
(6) 列表、元组、字典、集合等
都是python中常见的数据类型,后面有单独的讲解
3.2. 类型转换
python中类型转换的语法是: b类型(a类型的变量)
这个式子的含义是把a类型的变量转换成b类型的变量
1 | a = int('12345') # 字符串转整型(字符串必须是数字) |
以上的三种转换都是可逆的
3.3. 获取类型信息
(1) type()
用于获取对象的类型
语法:
1 | type(对象) # 返回的是对象的类型 |
例子:
1 | a = 30 |
输出:
1 | <class 'int'> |
(2) isinstance()
用来判断对象的数据类型
语法:
1 | isinstance(对象,数据类型) #返回的是一个布尔值 |
例子:
1 | a = 30 |
输出:
1 | False |
4. 运算符
运算符可以分为七大类
4.1. 算术运算符
1 | # +,-,*,/(除法),//(舍去小数的除法),%(模运算),**(幂运算) |
4.2. 赋值运算符
1 | # =,+=,-=,*=,/=,//=,%=,**= |
这里的等于号并不是我们日常使用的等于号,而是赋值的意思
4.3. 比较运算符
1 | # >,<,>=,<=,==(这里的双等于是我们日常生活中使用的等于号),!=(不等于) |
4.4. 逻辑运算符
1 | # and(与),or(或),not(非) |
4.5. 二进制运算符
二进制运算符的使用是大多数新手的盲区,这里我详细介绍一下
(1) 按位与&
两个二进制位都是1,结果才是1
1 | a = 5 # 101 |
(2) 按位或|
只要有一个二进制位是1,结果才是1
例子:
1 | a = 5 # 101 |
输出:
1 | 7 |
(3) 按位异或^
两个二进制位不同,结果是1;相同,结果是0
例子:
1 | a = 5 # 101 |
输出:
1 | 6 |
(4) 按位取反~
把二进制位取反,1变0,0变1
例子:
1 | a = 5 |
输出:
1 | -6 |
(5) 左移<<
把二进制整体向左移动,右边补0
例子:
1 | a = 5 # 101 |
输出:
1 | 10 |
(6) 右移>>
把二进制整体向右移动
例子:
1 | a = 5 # 101 |
输出:
1 | 2 |
4.6. 成员运算符
1 | # in/not in(判断元素是否在序列中,用于列表、字符串、元组、字典、集合) |
4.7. 身份运算符
1 | # is/is not(判断两个变量是否属于同一个对象) |
5. 流程控制
5.1. 条件判断
(1) 单条件
1 | if 表达式: # 如果表达式为真则执行代码块1,为假则执行代码块2 |
(2) 多条件
1 | if 表达式1: # 如果表达式1为假,则判断表达式2以此类推 |
5.2. 循环流程
(1) while循环
1 | while 表达式: # 只要表达式为真则一直循环执行代码块 |
(2) for循环
1 | for 变量 in 可迭代对象: #将可迭代对象赋值给变量后进入一次循环,有多少次迭代就进行多少次循环 |
(3) range
for经常会搭配range使用,range是一个可迭代对象
1 | range(start=0,stop,step=1) |
start是下标,下标默认从0开始,stop是结束位置,step是步长默认为1
这里需要注意range()是"左开右闭"的,也就是说不包括stop
1 | for i in range(8): #可以不写start和step但是stop一定要写 |
(4) continue
跳出本次循环,后面循环继续执行
(5) break
终止循环
6. 函数
函数就是一段可以被重复使用的代码。函数的核心作用:输入数据 -> 函数处理 -> 输出结果
6.1. 函数的基本语法
Python使用def定义函数
语法:
1 | def 函数名(参数): |
函数定义之后,里面的代码不会立刻执行。只有调用函数时,函数体才会执行。
函数名本质上是一个变量名,它指向一个函数对象。函数名的命名规则和变量名一样。
例子:
1 | def add(a,b): # 函数定义 |
输出:
1 | 30 |
6.2. 参数
参数是函数接收外部数据的入口,在Python里,函数传参时有两个非常重要的概念:
形参:函数定义时写在括号里的变量。上方例子中的a、b是形参
实参:函数调用时真正传进去的值。上方例子中的a1、b1是实参
6.2.1. 位置参数
最普通的参数叫位置参数,位置参数靠顺序匹配。
例子:
1 | def introduce(name, age): |
输出:
1 | 我叫张三,今年18岁 |
如果改变位置参数的顺序:
1 | introduce("张三", 18) |
则会输出:
1 | 我叫18,今年张三岁 |
使用*args来接收多个位置参数
例子:
1 | def func(*args): |
输出:
1 | (1, 2, 3) |
这里的args本质上是一个元组
*args:接收不确定数量的位置参数
这里真正启作用的是“*”,这里的“*”代表会把多出来的位置参数收集成一个元组。“args”只是约定俗成的变量名,是可以更改的,但通常就叫“args”。
6.2.2. 关键字参数
调用参数时,也可以指定参数名,这样就不依赖顺序了
例子:
1 | def introduce(name, age): |
输出:
1 | 我叫张三,今年18岁 |
关键字参数的优点是可读性强
使用**kwargs来接收多个关键字参数
例子:
1 | def func(**kwargs): |
输出:
1 | {'name': '张三', 'age': 18} |
这里的kwargs本质上是一个字典
**kwargs:接收不确定数量的关键字参数
这里真正启作用的是“**”,这里的“**”代表会把多出来的关键字参数收集成一个字典。“kwargs”只是约定俗成的变量名,是可以更改的,但通常就叫“kwargs”。
6.2.3. 默认参数
函数参数可以设置默认值,默认参数必须写在普通参数后面
例子:
1 | def greet(name, message="你好"): |
输出:
1 | 你好,小明 |
如果调用时没有传message,就使用默认值"你好"
6.2.4. 参数顺序
Python函数参数有固定顺序
一般情况下格式是:
1 | def func(普通参数, 默认参数, *args, 关键字专用参数, **kwargs): |
只允许关键字传参
在函数参数中,单独的“*”后面的参数必须用关键字传入。
1 | def create_user(name, *, age, city): |
这样写的好处是可读性更强。
只允许位置传参
在函数参数中,单独的“/”前面的参数只能用位置传参。
1 | def func(a, b, /, c): |
6.3. 返回值
return的作用是返回结果并结束函数
函数中如果没有return则默认返回None
Python函数可以返回多个值
1 | def get_info(): |
输出:
1 | ('张三', 18) |
6.4. 作用域
函数内部定义的变量,一般只能在函数内部使用。
1 | def func(): |
在上面例子中,最后一行会报错,因为x是局部变量。如果你在内函数内部给变量赋值,Python会默认它是局部变量
在函数外面的变量叫全局变量,在函数内部可以使用,但是无法修改。
1 | x = 10 |
输出:
1 | 10 |
global关键字
如果确实想在函数内部修改全局变量,可以使用global关键字
1 | x = 10 |
输出:
1 | 20 |
一般不推荐频繁使用global,他会让函数依赖外部环境,代码更难维护。
6.5. 文档字符串docstring
函数内部第一行字符串可以作为函数说明。
1 | def add(a, b): |
文档字符串可以通过help()和__doc__查看
1 | def add(a, b): |
6.6. lambda函数
lambda函数用来定义简单的匿名函数。
普通函数:
1 | def square(x): |
lambda函数:
1 | square = lambda x: x * x |
lambda函数常用于简单场景,比如排序:
1 | students = [ |
6.7. 函数签名
Python的函数签名是函数对外暴露的接口调用规范,包含:函数名 + 参数列表 + 返回值类型。规定了怎么调用这个函数,编译器也通过签名做类型检查、提示、重载判断等
例子:
1 | def add(a, b): |
它的函数签名可以写成:
1 | add(a, b) |
比较简单的函数签名就是;
1 | 函数名(参数列表) |
也可以加上参数类型标注和返回值类型:
1 | def add(a: int, b: int = 0) -> int: |
函数签名:
1 | add(a: int, b: int = 0) -> int |
格式:
1 | 函数名(参数名: 参数类型 = 默认值) -> 返回值类型 |
这里可以与前面讲过的位置参数、关键字参数、默认参数等等结合。
例子:
1 | def example(a, b, /, c, d=10, *args, e, f=20, **kwargs): |
签名:
1 | example(a, b, /, c, d=10, *args, e, f=20, **kwargs) -> None |
7. 字符串
在用python进行数据清洗的时候,字符串能否准确使用尤为关键。所以这里单开一节,来介绍字符串的应用。
7.1. 转义字符
在python中有一些字符不能直接写,或者有特殊含义,需要使用反斜杠\
(1) 换行\n
例子:
1 | print("Hello\nWorld") |
输出:
1 | Hello |
(2) 制表符\t
相当于Tab,在字符串中插入一段空白,用来对齐文本,默认占8个空格宽度
例子:
1 | print("姓名\t年龄\t城市") |
输出:
1 | 姓名 年龄 城市 |
(3) 反斜杠\\
因为打别的转义字符需要用到反斜杠,所以想单独打一个反斜杠可以通过\
例子:
1 | print("C:\\Users\\supzj\\Desktop") |
输出:
1 | C:\Users\supzj\Desktop |
(4) 单引号\'
如果字符串外层用单引号包裹,但内部还需要输出一个单引号时可以使用
例子:
1 | print('\'str\'') |
输出:
1 | 'str' |
这里其实有一个更加方便的办法:当字符串内部需要输出单引号时,外层就用双引号包裹,反之依然。
(5) 双引号\"
例子:
1 | print("\"str\"") |
输出:
1 | "str" |
7.2. 字符串的索引
字符串可以看成是由一个个字符串组成的序列,每个字符都有位置编号,叫做索引。
1 | s = "Python" |
1 | P y t h o n |
1 | s = "Python" |
这里要注意字符串是不可变类型,也就是说字符串创建之后,不能直接修改其中某一个字节。
1 | s = "Python" |
这样会报错
7.3. 字符串的切片
切片就是从字符串中取出一部分
语法:
1 | 字符串[start:stop:step] # 包含start,不包含stop |
例子:
1 | s = "Python" |
7.4. 字符串拼接
(1) 用+
例子:
1 | a = "Hello" |
输出:
1 | Hello World |
(2) 用*
例子:
1 | s = "ha" |
输出:
1 | hahaha |
(3) join
函数签名:
1 | str.join(iterable, /) |
用前面的分隔符把每一次迭代拼起来
例子:
1 | words = ["Python","is","good"] |
输出:
1 | Python is good |
7.5. 字符串格式化
现在最常用的是f-string
例子:
1 | name = "C++" |
输出:
1 | C++是世界上最好的语言 |
{}中也可以写表达式
例子:
1 | a = 10 |
输出:
1 | 10 + 20 = 30 |
还可以控制小数位数:
1 | pi = 3.1415926 |
输出:
1 | 3.14 |
f-string是Python3.6+的首选字符串格式化方法,性能最快、可读性最高。之前还有几种字符串格式化,但都比较繁琐,这里就不过多赘述了。
7.6. 字符串方法
字符串也有很多自带的方法
7.6.1. len()
len():获取长度
len()
1 | s = "Python" |
7.6.2. upper()和lower()
upper():大写转换
lower():小写转换
函数签名:
1 | str.upper(self, /) -> str |
例子:
1 | s = "Python" |
7.6.3. strip()
strip():去掉两边指定字符
函数签名:
1 | str.strip(self, chars=None, /) -> str |
例子:
1 | s = " hello world " |
输出:
1 | hello world |
注意它只去掉两边,不去掉中间
类似的还有:
1 | str.lstrip(self, chars=None, /) -> str # 只去掉左边的空白 |
7.6.4. replace()
replace():替换内容
函数签名:
1 | str.replace(self, old, new, /, count=-1) -> str |
例子:
1 | s = "I like Jave" |
输出:
1 | I like Python |
注意,原字符串不会被修改,字符串不可变
7.6.5. split()
split():切分字符串
把字符串切成列表
函数签名:
1 | str.split(self, /, sep=None, maxsplit=-1) -> list[str] |
例子:
1 | s = "Python is good" |
输出:
1 | ['Python', 'is', 'good'] |
7.6.6. find()和index()
find():查找字符串
函数签名:
1 | str.find(self, sub, start=0, end=len(self), /) -> int |
例子:
1 | s = "hello python" |
index()
函数签名:
1 | str.index(self, sub, start=0, end=len(self), /) -> int |
作用与find()类似,但如果找不到时会报错而find()不会。
7.6.7. startswith()和endswith()
startswith():判断开头的内容
函数签名:
1 | str.startswith(self, prefix, start=0, end=len(self), /) -> bool |
例子:
1 | filename = "test.py" |
endswith():判断结尾的内容
函数签名:
1 | str.endswith(self, suffix, start=0, end=len(self), /) -> bool |
例子:
1 | filename = "test.py" |
7.6.8. isdigit()
isdigit():判断字符串是否全部由数字字符组成
函数签名:
1 | str.isdigit(self, /) -> bool |
例子:
1 | print("123".isdigit()) # True |
7.7. 字符串前缀
Python 字符串前面可以加一些前缀。
r:原始字符串
比如不会\n当成换行
1 | s = r"C:\Users\test\new" |
f:格式化字符串
这个前面有详细说过,这里就不展开了
b:字节字符串
1 | b = b"hello" |
fr:组合使用
既可以格式化、又可以使用原始字符串
1 | name = "test" |
8. 列表list
Python中的列表是一种可以存放多个元素的数据结构。
比如:
1 | nums = [10, 20, 30, 40] |
它有顺序、可重复、可修改、可以存放不同类型、支持下标访问。
Python列表的下标从0开始。
8.1. 创建列表
直接用方括号创建:
1 | a = [1, 2, 3] |
还可使用**list()**创建
函数签名:
1 | list(iterable=(), /) -> list |
例子:
1 | s = "hello" |
输出:
1 | ['h', 'e', 'l', 'l', 'o'] |
8.2. 列表的引索
列表中的每个元素都有位置编号,这个编号叫引索
1 | nums = [10, 20, 30, 40] |
1 | nums = [10, 20, 30, 40] |
8.3. 修改列表元素
列表是可变对象,所以可以直接修改其中的元素
1 | nums = [10, 20, 30] |
输出:
1 | [10, 200, 30] |
这里与字符串不同,字符串是不可变对象,列表是可变对象
8.4. 列表切片
切片可用于一次取出多个元素
基本格式:
1 | 列表[start:stop:step] # 包含start,不包含stop |
例子:
1 | nums = [10, 20, 30, 40, 50] |
8.5. 列表常用操作
8.5.1. 获取长度:len()
len()
1 | nums = [10, 20, 30] |
输出:
1 | 3 |
8.5.2. 判断元素是否存在
in
1 | nums = [10, 20, 30] |
8.5.3. 列表拼接
+
1 | a = [1, 2] |
输出:
1 | [1, 2, 3, 4] |
8.5.4. 列表重复
*
1 | lst = [1, 2] * 3 |
输出:
1 | [1, 2, 1, 2, 1, 2] |
8.5.5. 列表遍历
直接遍历元素:
1 | nums = [10, 20, 30] |
输出:
1 | 10 |
遍历引索:
1 | nums = [10, 20, 30] |
输出:
1 | 0 10 |
使用enumerate()同时获取引索和值(最常用):
1 | nums = [10, 20, 30] |
输出:
1 | 0 10 |
8.6. 列表方法
8.6.1. append()
append():在末尾添加一个元素
函数签名:
1 | list.append(object, /) -> None |
例子:
1 | nums = [1, 2, 3] |
输出:
1 | [1, 2, 3, 4] |
这里需要注意,append()是把一个对象整体加到列表末尾:
1 | lst = [1, 2] |
输出:
1 | [1, 2, [3, 4]] |
8.6.2. extend()
extend():把可迭代对象中的元素逐个添加进去
函数签名:
1 | list.extend(iterable, /) -> None |
例子:
1 | lst = [1, 2] |
输出:
1 | [1, 2, 3, 4] |
8.6.3. insert()
insert():在指定位置插入元素
函数签名:
1 | list.insert(index, object, /) -> None |
例子:
1 | nums = [10, 20, 30] |
输出:
1 | [10, 99, 20, 30] |
8.6.4. remove()
remove():删除第一个匹配的元素
函数签名:
1 | list.remove(value, /) -> None |
例子:
1 | nums = [10, 20, 30, 20] |
输出:
1 | [10, 30, 20] |
它只删除第一个 20。如果元素不存在,则会报错
8.6.5. pop()
pop():删除并返回指定位置的元素
函数签名:
1 | list.pop(index=-1, /) -> object |
例子:
1 | nums = [10, 20, 30] |
输出:
1 | 20 |
8.6.6. clear()
函数签名:
1 | list.clear() -> None |
例子:
1 | nums = [1, 2, 3] |
输出:
1 | [] |
8.6.7. index()
index():查找元素第一次出现的位置
函数签名:
1 | list.index(value, start=0, stop=sys.maxsize, /) -> int |
例子:
1 | nums = [10, 20, 30, 20] |
输出:
1 | 1 |
index()如果找不到,会报错
8.6.8. count()
count():统计某个元素出现次数
函数签名:
1 | list.count(value, /) -> int |
例子:
1 | nums = [10, 20, 30, 20, 20] |
输出:
1 | 3 |
8.6.9. sort()
sort():原地排序
函数签名:
1 | list.sort(*, key=None, reverse=False) -> None |
例子:
1 | nums = [3, 1, 4, 2] |
输出:
1 | [1, 2, 3, 4] |
按字符串长度排序:
1 | words = ["apple", "hi", "banana"] |
输出:
1 | ['hi', 'apple', 'banana'] |
注意,sort会直接修改原列表
sorted():返回新的排序列表
sorted() 不是列表方法,而是内置函数。
函数签名:
1 | sorted(iterable, /, *, key=None, reverse=False) -> list |
例子:
1 | nums = [3, 1, 4, 2] |
输出:
1 | [3, 1, 4, 2] |
8.6.10. reverse()
reverse():原地反转
函数签名:
1 | list.reverse() -> None |
例子:
1 | nums = [1, 2, 3] |
输出:
1 | [3, 2, 1] |
它也会直接修改原列表
8.6.11. copy()
copy():浅拷贝*
函数签名:
1 | list.copy() -> list |
例子:
1 | a = [1, 2, 3] |
输出:
1 | [1, 2, 3] |
列表是可变对象,因此:
1 | a = [1, 2, 3] |
输出:
1 | [100, 2, 3] |
这里a也改变了,因为b = a不是复制列表,而是让a和b指向同一个列表对象,而copy()则是真正的复制列表
8.7. 列表推导式
列表推导式用于快速生成列表
普通写法:
1 | nums = [] |
列表推导式:
1 | nums = [i for i in range(5)] |
基本格式:
1 | [表达式 for 变量 in 可迭代对象] |
也可以加条件筛选:
1 | nums = [1, 2, 3, 4, 5, 6] |
基本格式:
1 | [表达式 for 变量 in 可迭代对象 if 条件] |
也可对元素进行处理:
1 | names = ["tom", "jack", "alice"] |
8.8. 二维列表
二维列表就是列表中再放列表
1 | matrix = [ |
可将其理解为矩阵
访问元素:
1 | print(matrix[0]) |
输出:
1 | [1, 2, 3] |
有些人会这样创建列表:
1 | grid = [[0] * 3] * 4 |
但这样并不是创建了4个独立的小列表,而是让4行都引用了同一个小列表,因此当修改其中一行时,等于修改所有行。
正确写法:
1 | grid = [[0] * 3 for _ in range(4)] |
二维列表需要注意浅拷贝问题
浅拷贝只能拷贝外层列表:
1 | a = [[1, 2], [3, 4]] |
输出:
1 | [[999, 2], [3, 4]] |
因为 b[0] 和 a[0] 指向的是同一个内层的小列表。
想完全复制二维列表可以用深拷贝:
1 | import copy |
list(a)、a[:]、a.copy() 这几个都是浅拷贝,所以都只会作用于外层的列表。
9. 元组tuple
元组与列表一样,可以存放多个数据,并且有顺序,可以通过下标访问;但元组创建后,不能修改其中的元素引用。
1 | t = (10, 20, 30) |
它的特点是有顺序、可重复、可存放不同类型、不可变、支持索引和切片
9.1. 创建元组
使用圆括号创建
1 | t = (1, 2, 3) |
不写圆括号也可以:
1 | t = 1, 2, 3 |
输出:
1 | (1, 2, 3) |
这里详细说一下:
1 | t1 = () # 正确 |
使用空括号可以创建一个空的元组,但是括号里单独括上一个10只是普通的括号表达式,不是元组。
1 | t = (10) |
输出:
1 | 10 |
正确写法:
1 | t = (10,) |
输出:
1 | (10,) |
还可以使用tuple()创建
函数签名:
1 | tuple(iterable=(), /) -> tuple |
例子:
1 | t1 = tuple() |
输出:
1 | () |
9.2. 元组的引索
与列表一样,元组中的每个元素都有位置编号,这个编号叫引索
1 | nums = (10, 20, 30, 40) |
1 | nums = (10, 20, 30, 40) |
9.3. 元组切片
切片可用于一次取出多个元素
基本格式:
1 | 元组[start:stop:step] # 包含start,不包含stop |
例子:
1 | nums = (10, 20, 30, 40, 50) |
9.4. 元组常用操作
9.4.1. 获取长度:len()
len()
1 | nums = (10, 20, 30) |
输出:
1 | 3 |
9.4.2. 判断元素是否存在
in
1 | nums = (10, 20, 30) |
8.5.3. 元组拼接
+
1 | a = (1, 2) |
输出:
1 | (1, 2, 3, 4) |
8.5.4. 元组重复
*
1 | t = (1, 2) * 3 |
输出:
1 | [1, 2, 1, 2, 1, 2] |
8.5.5. 元组遍历
直接遍历元素:
1 | nums = (10, 20, 30) |
输出:
1 | 10 |
遍历引索:
1 | nums = (10, 20, 30) |
输出:
1 | 0 10 |
使用enumerate()同时获取引索和值(最常用):
1 | nums = (10, 20, 30) |
输出:
1 | 0 10 |
9.5. 元组方法
因为元组不可变,所以列表中的大多数方法元组并不具有
9.5.1. count()
count():统计某个元素出现次数
函数签名:
1 | tuple.count(value, /) -> int |
1 | t = (1, 2, 2, 3, 2) |
输出:
1 | 3 |
9.5.2. index()
index():查找元素第一次出现的位置
函数签名:
1 | tuple.index(value, start=0, stop=sys.maxsize, /) -> int |
例子:
1 | nums = (10, 20, 30, 20) |
输出:
1 | 1 |
index()如果找不到,会报错
9.6. 元组打包与解包
元组打包
多个值用逗号放在一起,会自动打包成元组
1 | t = 1, 2, 3 |
输出:
1 | (1, 2, 3) |
元组解包
可以把元组中的值拆开,赋值给多个变量。
1 | t = (1, 2, 3) |
输出:
1 | 1 |
使用*可接收多个值
1 | t = (1, 2, 3, 4, 5) |
输出:
1 | 1 |
注意,*rest 接收到的是列表,不是元组。
函数返回多个值的情况,一般返回的都是元组
10. 字典dict
字典是Python中的键值对容器
1 | student = { |
其中的每一项都是:
1 | key: value |
字典主要是靠key找value
1 | student = { |
字典是可变对象
key必须是可哈希对象,常见的key:
1 | int |
value可以是任意对象。数字,字符串,列表,字典,函数等都可以
10.1. 创建字典
使用{}创建
1 | d = {} |
直接写键值对
1 | student = { |
使用dict创建
函数签名:
1 | dict(**kwargs) |
例子:
1 | d1 = dict() |
字典推导式
字典推导式和列表推导式类似
1 | squares = {x: x ** 2 for x in range(5)} |
输出:
1 | {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} |
结构是:
1 | {key表达式: value表达式 for 变量 in 可迭代对象} |
10.2. 字典的引索
d[key]
语法:
1 | d[key] |
例子:
1 | student = { |
如果key不存在会报错
使用get()
函数签名:
1 | d.get(key, default=None, /) |
如果key存在,返回对应value;如果key不存在,返回默认值default。如果没有传default,默认返回None。
例子:
1 | student = { |
10.3. 修改字典元素
修改元素
1 | d[key] = value |
这里key如果已经存在,就是修改。
添加元素
同样的语法:
1 | d[key] = value |
这里如果key不存在,就是添加。
删除元素:del
语法:
1 | del d[key] |
例子:
1 | student = { |
输出:
1 | {'name': 'Alice'} |
10.4. 字典常用操作
10.4.1. 判断key是否存在
这里用in判断
语法:
1 | key in d |
例子:
1 | student = { |
10.4.2. 获取字典长度:len()
返回字典中键值对的数量
1 | student = { |
10.4.3. 转成key列表
函数签名:
1 | list(d) -> list |
返回字典所有key组成的列表
1 | student = { |
输出:
1 | ['name', 'age'] |
10.5. 字典方法
10.5.1. clear()
clear():清空字典
函数签名:
1 | d.clear() -> None |
例子:
1 | d = {"a": 1, "b": 2} |
输出:
1 | {} |
10.5.2. copy()
copy():返回字典的浅拷贝
例子:
1 | d1 = {"a": 1, "b": 2} |
输出:
1 | {'a': 1, 'b': 2} |
但它只是浅拷贝:
1 | d1 = {"scores": [90, 95]} |
输出:
1 | {'scores': [90, 95, 100]} |
原因是外层字典被拷贝了,但是里面的列表对象还是同一个
如果想深拷贝:
1 | import copy |
10.5.3. fromkeys()
fromkeys():根据可迭代对象中的元素创建key,所有key对应同一个默认value
函数签名:
1 | dict.fromkeys(iterable, value=None, /) |
例子:
1 | keys = ["name", "age", "score"] |
输出:
1 | {'name': None, 'age': None, 'score': None} |
也可以自行指定默认值,但是注意默认值需要是不可变对象
10.5.4. get()
get():获取key对应的value
1 | student = {"name": "Alice", "age": 18} |
10.5.5. key()
key():返回字典 key 的视图对象
函数签名:
1 | d.keys() |
例子:
1 | student = {"name": "Alice", "age": 18} |
输出:
1 | dict_keys(['name', 'age']) |
keys() 返回的不是列表,而是一个视图对象。
10.5.6. values()
value():返回字典 value 的视图对象
函数签名:
1 | d.values() |
例子:
1 | student = {"name": "Alice", "age": 18} |
输出:
1 | dict_values(['Alice', 18]) |
10.5.7. items()
items():返回字典键值对的视图对象,每一项是一个二元组
函数签名:
1 | d.items() |
例子:
1 | student = {"name": "Alice", "age": 18} |
输出:
1 | dict_items([('name', 'Alice'), ('age', 18)]) |
常见用途是遍历字典:
1 | student = { |
10.5.8. pop()
**pop():删除指定key,并返回被删除的value
函数签名:
1 | d.pop(key, /) |
例子:
1 | student = { |
输出:
1 | 18 |
如果key不存在,并且没有给默认值,会报错
如果给了默认值,key不存在时返回默认值
10.5.9. popitem()
popitem():删除并返回最后插入的键值对
函数签名:
1 | d.popitem() |
例子:
1 | d = { |
输出:
1 | ('c', 3) |
10.5.10. setdefault()
**setdefault():如果key存在,返回原来的value;如果key不存在,插入key:default,返回默认值default
例子:
1 | d = {"name": "Alice"} |
输出:
1 | 18 |
注意,如果key已经存在,则不会把已经存在的value修改
常见用途:给字典里的列表追加元素
10.5.11. update()
update():用另一个字典、映射对象、键值对可迭代对象或关键字参数更新当前字典。如果key已存在,就覆盖原来的value。update() 原地修改字典,并返回None
函数签名:
1 | d.update(**kwargs) |
用字典更新:
1 | d = {"name": "Alice", "age": 18} |
输出:
1 | {'name': 'Alice', 'age': 19, 'score': 95} |
用关键字参数更新:
1 | d = {"name": "Alice"} |
输出:
1 | {'name': 'Alice', 'age': 18, 'score': 95} |
用键值对列表更新:
1 | d = {"name": "Alice"} |
输出:
1 | {'name': 'Alice', 'age': 18, 'score': 95} |
10.6. 字典合并
Python3.9开始支持字典合并运算符:|和|=
d|other
语法:
1 | new_dict = d | other |
返回一个新的合并后的字典。
例子:
1 | a = {"x": 1, "y": 2} |
输出:
1 | {'x': 1, 'y': 20, 'z': 3} |
注意,如果有重复的key,则右边的字典优先
d|=other
语法:
1 | d |= other |
原地更新d
例子:
1 | a = {"x": 1, "y": 2} |
输出:
1 | {'x': 1, 'y': 20, 'z': 3} |
10.7. 遍历字典
默认遍历key
1 | student = { |
输出:
1 | name |
遍历字典本身,默认就是遍历 key
遍历key
1 | for key in student.keys(): |
不过一般直接用上面的默认遍历
遍历value
1 | for value in student.values(): |
同时遍历key和value
最常用:
1 | for key, value in student.items(): |
这里本质上是对每个二元组做解包
10.8. 字典的顺序问题
现代Python中,字典会保持插入顺序
如果修改已有key的value,不会改变它的位置
但如果删除后重新插入,它会跑到最后
10.9. 字典视图对象
前面有说过返回字典视图对象的字典方法,这里详细说一下字典视图对象
1 | d = {"a": 1, "b": 2} |
输出:
1 | dict_keys(['a', 'b']) |
视图对象有点像列表,但它并不是列表,无法进行下标访问,但可以通过**list()**方法将其转换成列表
字典视图对象是动态的,可以随着字典变化实时更新
11. 集合set
Python中的集合类型主要有两种
1 | set # 可变集合 |
平时我们所说的集合,一般指的是set
集合有几个核心特点:元素不重复、无序、可以做集合运算、集合是可变对象、集合中的元素必须是可哈希对象
11.1. 创建集合
使用大括号创建集合
1 | s = {1, 2, 3} |
这是最常见的写法
使用set()函数创建集合
函数签名:
1 | set(iterable=(), /) -> set |
例子:
1 | s = set([1, 2, 2, 3]) |
输出:
1 | ``` |
这创建的是空字典,不是集合
如果要创建空集合,正确的写法是
1 | s = set() |
使用集合推导式创建集合
集合也支持推导式,写法依旧类似列表推导式
1 | s = {x for x in range(5)} |
输出:
1 | {0, 1, 2, 3, 4} |
集合在创建时如果输入重复的元素,则会自动去重
11.2. 添加元素
11.2.1 add()
作用是向集合中添加一个元素
函数签名:
1 | set.add(element, /) -> None |
例子:
1 | s = {1, 2, 3} |
输出:
1 | {1, 2, 3, 4} |
注意,add()是添加一个整体元素:
1 | s = {1, 2} |
输出:
1 | {1, 2, (3, 4)} |
11.2.2. update()
作用是把其他可迭代对象中的元素逐个加入集合
函数签名:
1 | set.update(*others) -> None |
例子:
1 | s = {1, 2} |
输出:
1 | {1, 2, 3, 4, 5} |
11.3. 删除元素
11.3.1. remove()
删除指定元素
函数签名:
1 | set.remove(element, /) -> None |
例子:
1 | s = {1, 2, 3} |
输出:
1 | {1, 3} |
如果指定的元素不存在,则会报错
11.3.2. discard()
也是删除指定元素,但与remove()不同的是:当指定的元素不存在时不会报错
函数签名:
1 | set.discard(element, /) -> None |
例子:
1 | s = {1, 2, 3} |
输出:
1 | {1, 3} |
11.3.3. pop()
随机删除并返回集合中的一个元素
1 | s = {1, 2, 3} |
可能输出:
1 | 1 |
11.3.4. clear()
清空集合
函数签名:
1 | set.clear() -> None |
例子:
1 | s = {1, 2, 3} |
输出:
1 | set() |
这里空集合显示的是set(),不是{},因为{}表示空字典
11.4. 集合的常用操作
11.4.1. 判断元素是否存在
使用in
例子:
1 | s = {1, 2, 3} |
输出:
1 | True |
11.4.2. 获取集合长度
len()
1 | s = {1, 2, 3} |
输出:
1 | 3 |
11.4.3. 遍历集合
1 | s = {"apple", "banana", "orange"} |
注意,不能写依赖集合遍历顺序的代码,因为集合是无序的。
11.5. 集合运算
集合最重要的地方,就是可以做数学集合运算
11.5.1. 并集
两个集合中所有元素合起来
数学上类似:
1 | A ∪ B |
Python中可以这样写:
1 | a | b |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {1, 2, 3, 4, 5} |
也可以用union()
函数签名:
1 | set.union(*other) -> set |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {1, 2, 3, 4, 5} |
union()不会修改原集合,而是返回一个新集合
11.5.2. 交集
两个集合共有的元素
数学上类似:
1 | A ∩ B |
Python中可以这样写:
1 | a & b |
例如:
1 | a = {1, 2, 3} |
输出:
1 | {3} |
也可以用intersection()
函数签名:
1 | set.intersection(*others) -> set |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {3} |
11.5.3. 差集
属于a,但不属于b的元素
数学上类似:
1 | A - B |
Python中可以这样写:
1 | a - b |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {1, 2} |
也可以使用difference()
函数签名:
1 | set.difference(*others) -> set |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {1, 2} |
11.5.4. 对称差集
只属于其中一个集合,但不同时属于两个集合的元素
Python中可以这样写:
1 | a ^ b |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {1, 2, 4, 5} |
11.5.5. 原地并集
update可用于原地并集合
函数签名:
1 | set.update(*others) -> None |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {1, 2, 3, 4, 5} |
也可以写成:
1 | a |= b |
11.5.6. 原地并集
intersection_update相当于原地交集
1 | set.intersection_update(*others) -> None |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {3} |
也可以写成:
1 | a &= b |
11.5.7. 原地差集
difference_update相当于原地交集
1 | set.difference_update(*others) -> None |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {1, 2} |
也可以写成:
1 | a -= b |
11.5.8. 原地对称差集
symmetric_difference_update相当于原地对称差集
1 | set.symmetric_difference_update(other, /) -> None |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {1, 2, 3, 4} |
也可以写成:
1 | a ^= b |
11.6. 集合之间的关系判断
11.6.1. 判断是否是子集
issubset()
函数签名:
1 | set.issubset(other, /) -> bool |
例子:
1 | a = {1, 2} |
输出:
1 | True |
也可以用:
1 | a <= b |
11.6.2. 判断是否是真子集
用<
1 | a < b |
例子:
1 | a = {1, 2} |
输出:
1 | True |
11.6.3. 判断是否为超集
issuperset()
函数签名:
1 | set.issuperset(other, /) -> bool |
例子:
1 | a = {1, 2} |
输出:
1 | True |
也可以用:
1 | b >= a |
11.6.4. 判断是否为真超集
用>
1 | b > a |
例子:
1 | a = {1, 2} |
输出:
1 | True |
11.6.5. 判断是否没有交集
isdisjoint(other, /) -> bool
例如:
1 | a = {1, 2, 3} |
输出:
1 | True |
11.7. 复制集合
copy()
1 | set.copy() -> set |
例子:
1 | a = {1, 2, 3} |
输出:
1 | {1, 2, 3} |
11.8. 不可变集合frozenset
set 是可变的
frozenset 是不可变的
创建方式:
1 | fs = frozenset([1, 2, 3]) |
函数签名:
1 | frozenset(iterable=(), /) |
例子:
1 | fs = frozenset([1, 2, 2, 3]) |
输出:
1 | frozenset({1, 2, 3}) |
frozenset不能添加,删除元素,因为它是不可变类型
因为frozenset是不可变的,所以它可以作为集合中的元素,也可以作为字典中的key