文章目录
- 前言
- 基础杂项
- 变量和数据
- 变量与运算
- 数值
- 字符串
- 列表(list)、元组(tuple)和range
- 序列类型(sequence types)和切片(slicing)
- 集合(set)和字典(dict)
- 引用、浅拷贝、深拷贝
- 流程控制语句
- if / else 和 match / case
- while 和 for in
- 循环中的 break、continue 和 else
- pass
- 后记
前言
这篇文章主要用于记录Python3相关语法,方便自己查阅使用。
Python3基础使用相关内容可以参考下面文章:
https://blog.csdn.net/Naisu_kun/article/details/129986780
这篇文章主要参考自官方文档中 教程(Tutorial) 部分:
英文文档:https://docs.python.org/3/
中文文档:https://docs.python.org/zh-cn/3/
基础杂项
注释
# 这是单行注释(#号及后面内容为注释)
"""
这是多行注释
使用 """ """ 或者 ''' ''' 包围的是多行注释
多行注释根据所在的位置不同也可以成为文档注释、函数注释、多行字符串等
"""
缩进
Python不像大多数语言那样使用 { } 表示代码块,而使用缩进方式。可以使用空格或者tab缩进(推荐使用 4个空格 方式,非tab),同一代码块中同一层级代码需要使用相同的缩进格式:
下划线
Python中有很多下划线开头或结尾的变量或函数,这其中有的是属于语言内置内容,有些属于编码规范,常见的一些形式如下:
__xx__ # 通常这是Python内置的魔法函数(dunders)
_xx # 通常表示仅供内部使用,相当于很多语言中的私有成员(private)
# 需要注意的是上面的私有只是一种建议,并非强制(有的IDE可能会把它看作强制私有)
__xx # 通常用来表示类的私有成员,防止被子类改写
# 这个其实在执行中会触发name mangling规则,变成_classname__xx的形式,从而防止被子类改写
xx_ # 如果变量名和Python关键词冲突可以使用这个方式
此外在解释器中 _
可以用来表示上一条表达式的结果;在表示数值时可以用来提高可读性(比如 1_000_000
)。
PEP 8
PEP 8 是官方主要推荐的Python代码编写样式指南(编码规范),具体内容可以参考下面链接:
https://peps.python.org/pep-0008/
其中大多数内容主要时为了方便阅读代码而设计的,比如缩进、空格、空行等。这里提一下该规范中推荐的单行最大长度为79个字符,当长度超出时可以用常见的 \
符号来换行,当然该规范中推荐使用 ( )
包围同一行的内容,而不是使用 \
。
print 和 input
print(*objects, sep=' ', end='\n', file=None, flush=False)
是Python3中一个内置函数,用于打印输出信息。 *objects
是需要打印的内容,可以有多个; sep
是多个内容间的分隔内容, end
是打印结尾添加的内容,默认为换行符号; file
表示打印输出到指定文件,不指定则输出到标准输出; flush
表示是否强制刷新。
input(prompt)
也是内置函数,用于接收用户输入信息, prompt
是可选内容,是提示信息。
变量和数据
变量与运算
Python中变量不需要任何关键词进行声明,直接使用 name = value
方式声明加赋值即可,之后就可以直接使用变量名来使用了。变量声明赋值后也可以再次使用 name = value
方式进行赋值。
编程最终是处理数据,主要就是各种运算等。Python3中常见的有下面一些运算符(优先级从高到低):
运算符 | 描述 |
---|---|
(expressions...), [expressions...], {key: value...}, {expressions...} | 绑定或加圆括号的表达式,列表显示,字典显示,集合显示 |
x[index], x[index:index], x(arguments...), x.attribute | 抽取,切片,调用,属性引用 |
await x | await 表达式 |
** | 乘方 |
+x, -x, ~x | 正,负,按位非 NOT |
*, @, /, //, % | 乘,矩阵乘,除,整除,取余 |
+, - | 加和减 |
<<, >> | 移位 |
& | 按位与 AND |
^ | 按位异或 XOR |
| | 按位或 OR |
in, not in, is, is not, <, <=, >, >=, !=, == | 比较运算,包括成员检测和标识号检测 |
not x | 布尔逻辑非 NOT |
and | 布尔逻辑与 AND |
or | 布尔逻辑或 OR |
[on_true] if [expression] else [on_false] | 条件表达式 |
lambda | lambda 表达式 |
:= | 赋值表达式 |
除了上面这些,各种 += -= *= /= ...
这种符合的赋值运算符也是支持的。
数值
数值类型是所有编程语言中最基本的数据类型,Python因为是弱类型的语言,所以一般不太用关系具体的数值类型是什么,当然硬要说的话目前Python3主要分为 int
float
complex
:
各个类型默认的构造方法可以用作类型转换。不同的类型有不同类型细节操作上特有的优势。
Python3中布尔类型在运算中会被视作整形来处理, True = 1
False = 0
:
字符串
Python3中字符串和其它语言差不多,只有少数一些自己特有的东西:
str1 = "Hello" # 使用 " " 或者 ' ' 包围的内容是字符串
str2 = 'Naisu\n' # 这里的 \ 是转义符
str3 = r'123\n456\n789' # 这里前面的 r 表示后面的是原始字符串,会忽略其中的转义操作
# 使用 """ """ 或者 ''' ''' 包围的是多行字符串
# 下面的 \ 用于忽略多行字符转中的该符号所在行的换行(注意其后不能有空格)
str4 = """\
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
"""
print(str1, str2)
print(str1 + str2) # 可以使用 + 操作来连接字符串
print(str1 * 3) # 可以使用 * 操作来倍乘
print(str3)
print(str4)
字符串有非常多的方法可用,可以用来进行大小写转化、查找、替换、分割、拼接等工作,详细的内容可以参考官方文档中 标准库(Standard Library)部分。
列表(list)、元组(tuple)和range
Python中的列表有点像其它语言中是数组(当然Python中也可以使用内置的 array
模块来支持真正的数组功能),但是列表中可以保存不同类型的数据,只不过通常列表中都是保存同一种类型的数据。
相比传统的数组来说 Python中的列表 操作山更加灵活:
arr1 = [0, 1, 2, 3] # 创建列表
# arr1 = list([0, 1, 2, 3]) # 也可以使用构造方法来创建,构造方法可以将其它类型转换成列表
arr2 = arr1 * 3
arr3 = arr1 + ['A', 'B', 'C']
print(arr1, arr2, arr3)
print(arr3[0], arr3[4], arr3[6])
print(arr3[-3], arr3[-1]) # 使用负数索引获取列表元素
列表提供了 append
extend
insert
remove
pop
clear
count
reverse
等一些方法。和其它语言中的数组类似,列表也经常拿来做堆栈和队列等使用,不过因为Python中列表头部插入或删除元素性能比较差,所以通常使用内置的 collections.deque
来做队列。
Python中的元组和列表很像,元组两端使用 ( )
包围,元组的一旦创建,元组中的元素就不可修改(可以近似理解为元组是个只读的列表):
range
也是Python中的一个内置类型,不过通常只用它的构造方法,它的功能是生成一串数字序列:
# class range(stop)
# class range(start, stop[, step])
# range对象没法直接打印,下面转成list来打印
print(list(range(4))) # 生成 0 1 2 3
print(list(range(3, 8))) # 生成 3 4 5 6 7
print(list(range(0, 10, 2))) # 生成 0 2 4 6 8
print(range(4)[1]) # range对象也可以用下标取值
# range最常用的功能是用在for循环中
for value in range(4):
print(value, end=' ')
序列类型(sequence types)和切片(slicing)
上面出现的字符串、列表、元组这些都属于序列类型。序列类型简单理解就是里面的元素是按照一定的顺序排列的,可以使用 [index]
来获取其中元素。字符串和元组属于不可变序列类型,创建后不可修改;列表属于可变序列类型,创建后可以修改其中内容。
序列类型一般都支持以下操作:
运算 | 功能 | 备注 |
---|---|---|
x in s 和 x not in s | 判断 s 中是否有值为 x 的项 | |
s + t 和 s * n n * s | s 与 t 相拼接 和 s 与自身进行 n 次拼接 | |
s[i] 和 s[i] = x | 获取某项 和 给某项赋值 | 只有可变序列能赋值 |
s[i:j] 和 s[i:j] = t | 获取 s 从 i 到 j 的切片 和 给替换该切片段 | 只有可变序列能替换 |
s[i:j:k] 和 s[i:j:k] = t | 获取 s 从 i 到 j 步长为 k 的切片 和 给替换该切片段 | 只有可变序列能替换 |
del s[i:j] 和 del s[i:j:k] | 删除 s 中切片段 | 可变序列 |
len(s) | 获取 s 长度 | |
min(s) 和 max(s) | 获取 s 中最小项 和 最大项 | |
s.index(x[, i[, j]]) | x 在 s 中首次出现项的索引号 (索引号在 i 或其后且在 j 之前) | |
s.count(x) | x 在 s 中出现的总次数 | |
s.append(x) | 将 x 添加到序列的末尾 | 可变序列 |
s.clear() | 从 s 中移除所有项 | 可变序列 |
s.copy() | 创建 s 的浅拷贝 | 可变序列 |
s.extend(t) 或 s += t | 用 t 的内容扩展 s | 可变序列 |
s *= n | 使用 s 的内容重复 n 次来对其进行更新 | 可变序列 |
s.insert(i, x) | 在由 i 给出的索引位置将 x 插入 s | 可变序列 |
s.pop() 或 s.pop(i) | 提取在 i 位置上的项,并将其从 s 中移除 默认 i = -1 ,相当于移除最后一项 | 可变序列 |
s.remove(x) | 删除 s 中第一个 s[i] 等于 x 的项目 | 可变序列 |
s.reverse() | 就地将列表中的元素逆序 | 可变序列 |
上面表格中多次出现了切片,切片是序列类型中非常常用的一个操作。切片的功能是获取序列中的一部分内容的引用,对于可变序列的切片还可以通过切片来修改原序列。
list1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ls1 = list1[2:4] # 获得list1中序号 2~3 的切片
ls2 = list1[:3] # 获得list1中序号 开头~2 的切片
ls3 = list1[6:] # 获得list1中序号 6~结尾 的切片
ls4 = list1[-4:-1] # 获得list1中序号 -4~-1 的切片
ls5 = list1[-2:] # 获得list1中序号 -2~结尾 的切片
ls6 = list1[2:9:3] # 获得list1中序号 2~8中步进为3 的切片
print(ls1, ls2, ls3, ls4, ls5, ls6)
集合(set)和字典(dict)
Python中的集合是由不重复元素组成的无序容器。基本用法包括成员检测、消除重复元素。集合对象支持合集、交集、差集、对称差分等数学运算。创建集合用 {}
或 set()
函数。
print({2, 2, 3, 3}) # 只会输出{2, 3},重复的元素会自动忽略
s1 = {1, 2, 3, 4}
s2 = {3, 4, 5}
print(s1 | s2) # 合并两个集合
print(s1 & s2) # 取两个集合的公共元素,得到新集合
print(s1 - s2) # 取s1中s2没有的元素,得到新集合
print(s1 ^ s2) # 取s1中s2不共有的元素,得到新集合
注意,创建空集合只能用 set()
,不能用 {}
, {}
创建的是空字典。
集合有个不可变类型 frozenset
。
字典和集合一样,也是使用 {}
,只不过字典中保存的是键值对( ket: value
),字典中的键名是字符串,键名不会重复。字典中元素通过 dictname[key]
方式进行访问:
d = {'one': 1, 'two': 2, 'three': 3}
print(d)
print(d['two']) # 通过键名访问字典元素
d["four"] = 4 # 直接添加新元素
print(d)
需要注意的是集合和字典内部元素排列是无序的,使用时需要特别注意。但是从 Python 3.6 版本开始,字典中元素排列变成有序的了。
引用、浅拷贝、深拷贝
对于数值变量来说如果将一个变量赋值给另一个变量那会直接拷贝其中数据,这时候修改其中一个变量不会引起另一个变量改变:
列表、元组、集合、字典这种数据类型的变量往往有很多数据,而变量名可以看作是这一堆数据的起始地址,所以这些变量创建副本的时候需要特别注意引用、浅拷贝、深拷贝的问题。
通常直接通过变量名赋值得到的只是原始变量的引用而已,修改其中一个变量中的元素同时也会反映在另一个上,因为底层指向的是同一个对象:
有时候我们会需要这些对象的副本,而不是引用,这就需要用到浅拷贝和深拷贝了。浅拷贝操作上比较简单,常见的有下面方式:
浅拷贝的对象中只有数值这种简单类型下使用上一般不会有问题,但是如果对象中又包含了列表、元组、集合、字典这种类型的话就会有问题出现了:
可以看到如果原始对象中有可变类型的引用的话使用浅拷贝可能出现意料之外的情况了。需要特别注意。因为这个问题,所以还有一个深拷贝的概念。深拷贝简单来说就是把所有内容都生成一份副本,这些相互之间就不会有影响了。比较常用的深拷贝方式是使用 copy.deepcopy()
函数:
因为引用和浅深拷贝这些问题存在,所以在创建多维列表等的时候需要特别注意:
list1 = [[0] * 列 ] * 行 # 错误的方法,因为后面的 *行 只是对前者进行多次引用
list2 = [[0] * 列 for i in range(行)] # 正确的方法,当然方法有很多
同样因为这个问题,在函数使用时,如果传递的是可变类型,需要注意在函数内部修改该参数中的元素也会改变原始数据,这是引用传递;如果传递是不可变类型则没关系,这是值传递。
流程控制语句
if / else 和 match / case
if / else
是最常见的条件选择语句,用法比较简单:
Python没有 switch / case
语句,但后来在3.10版本中加入了 match / case
语句,功能上相当于在传统的 switch / case
上加上一点扩展:
match / case
语句可以部分匹配使用:
while 和 for in
while
是常见的循环语言,基本用法比较简单:
Python中的 for in
用来迭代序列类型元素:
配合 range()
使用可以用来当作常用的 for
循环使用:
for in
也可以用来遍历集合和字典:
循环中的 break、continue 和 else
循环语句中可以使用 break
来跳出循环,使用 continue
来跳过本次循环进入下一次循环:
比较特殊的是Python的循环语句中可以使用 else
来处理循环结束后执行语句(中途使用 break
跳出不算):
pass
大多数语言中某个分支如果不需要执行任何语句可以空着什么都不写,但是Python中空着就会报错,所以需要使用 pass
来占个位:
if True:
pass # 这里的pass语句相当于什么都不做,但是不写pass这里会报错
后记
由于篇幅原因这里只是介绍了最基本的变量和流程控制语句相关内容,剩下的最主要用到的还有函数和类等内容,会在接下来的文章中进行记录。