L2-Python语法基础
预备知识
- Python 中的语句可以直接执行
- 用
#表示从此开始到行尾都是注释 - 段落注释采用''' (三引号中间的是注释掉的部分) '''
- 变量赋值不用事先声明、不用写类型
- 数组都是
object*[]类型,所以可以混着存任意的对象
- 数组都是
- 用
type(x)函数获取对象类型,用dir(x)函数获取对象的方法,用id(x)函数获取对象的 ID,(其实是对象的地址)
# 例子:
a = 43 # 在内存中申请一个空间存放 43,再用 a 指向它,id(a) 为 6
b = a # 将 b 指向 a 指向的东西,id(b) 为 6
print(x)函数用于输出指定内容,例如print(123),也可以传入多个值,如print(1, 2, 3)
1. 常见数据类型
| 类型 | 名称 | 例子 |
|---|---|---|
| int | 整数 | -100 |
| complex | 复数 | 1 + 2j |
| bool | 布尔型 | 只有 True 和 False |
| float | 浮点数 | 3.1416 |
| str | 字符串 | 'hello', "abc" |
| list | 列表 | [1, 0.3, 'hello'] |
| tuple | 元组 | ('hello', 10) |
| set | 集合 | {1, 2, 3} |
| dict | 字典 | {'dogs': 5, 'pigs': 3} |
| NoneType | 只有 None |
注意:
- int 没有大小限制,可以做任意大的整数运算
- float 是 64 位浮点数,相当于 C/C++ 中的 double 类型
- bool 类型只有首字母大写的
True和False - NoneType 是特殊的类型,它只有
None这一个值/对象实例,通常被用来表示空值
1.1 数值运算
# 基本算术运算
1 + 2 # 3
1 - 2 # -1
2 * 3 # 6
4 / 2 # 2.0 注意:无论结果在数学上是否是整数,一定是 float 类型
5 // 2 # 2 向下取整除法
5 % 2 # 1 取余
2**10 # 1024 幂次
# 原地运算
a = 1
a += 2 # a 变为 3
# 逻辑运算
True and False # False
True or False # True
not True # False
# 数学函数
abs(-3) # 3 绝对值
min(3, 4) # 3
max(3, 4) # 4
int(-3.9) # -3 向 0 取整
round(-3.9) # -4 就近取整
# 科学计数法、进制表示
1e-6, 0xFF, 0o67, 0b1110 # (1e-06, 255, 55, 14)
1.2 比较操作
1 == 2 # False 等于
1 != 2 # True 不等于
1 < 2 # True 小于
1 <= 2 # True 小于等于
1 > 2 # False 大于
1 >= 2 # False 大于等于
1 == 1.0 # True
[1, 2, 3] == [1.0, 2.0, 3.0] # True
== 和 != 是基于值做判断的;is 是基于 id 判断的,即判断两个东西是不是同一个对象
a = 1
b = 1.0
a == b # True
a is b # False
a = [1, 2, 3]
b = [1, 2, 3]
a == b # True
a is b # False
注意:"不是" 一般写作 a is not b
注意:关于 None 的判断用 is 和 is not 而不是 == 和 !=,理由是 None 这个对象是唯一的,我们只需要根据 id 判等,而不是根据值判等
a = None
b = 1
c = None
a is b # False
a is c # True
python 中的比较操作可以串着写
1 < 2 < 3 # True,等价于 1 < 2 and 2 < 3
# 可以串任意比较操作、任意多个
1 < 2 != 3 < 4 > 0 == 0 # True
# 等价于 1 < 2 and 2 != 3 and 3 < 4 and 4 > 0 and 0 == 0
1.3 字符串
可以写成单引号或者双引号:'abc'、"abc"
特殊字符需要转义操作\:'123\n456'
单引号字符串中的单引号、双引号字符串中的双引号,也需要转义操作:'123\'456'
但单引号字符串中的双引号、双引号字符串中的单引号不需要转义操作,所以一般来说写成下面这样:"123'456"
使用 3 个单/双引号的字符串可以跨行:
'''第一行
第二行
第三行'''
字符串操作:(注意:字符串是不可变的,任何操作都会返回新的字符串对象)
- 拼接:
'ab' + 'cd' -> 'abcd' - 重复:
'ab' * 3 -> 'ababab' - 分割:
a.split(b),以字符串 b 为界分割 a
"1 2 3".split(" ") # ['1', '2', '3']
- 连接:
a.join(b),以字符串 a 来将字符串序列 b 中元素连接起来
" ".join(["1", "2", "3"]) # '1 2 3'
- 替换:
a.replace(b,c),将字符串 a 中的 b 都替换为 c
"1,2,3".replace(",", "@") # '1@2@3'
- 大小写转化:upper()、lower()
"abcd123ABCD".upper() # 'ABCD123ABCD'
"abcd123ABCD".lower() # 'abcd123abcd'
字符串转换:
str(a): 将 a 转化为字符串hex(a),oct(a),bin(a): 将整数 a 转化为 16、8、2 进制字符串int(str,b): 将字符串 str 转化为 b 进制整数float(str): 将字符串 str 转化为浮点数
str(3.4), hex(234), int("FA", 16), float("5.78")
# ('3.4', '0xea', 250, 5.78)
Raw 字符串:在引号前面加 r,表示不将 \ 视为转义。
r"C:\abc\def" # 'C:\\abc\\def'
模板字符串:在前面加 f,在需要用到变量值时非常方便,只需要用 {} 括起来
a = 1
b = 2
f"a 的值是 {a},b 的值是 {b}" # 'a 的值是 1,b 的值是 2'
# 除了变量名,也可以是其他表达式
f"{2**10 + a}" # '1025'
可以用类似 C 中 printf 的语法对浮点数格式化:
a = 1.2345678
f"a ≈ {a:.3f}" # 'a ≈ 1.235' 3位小数
如果需要用到单纯的{或者}字符,需要写两遍表示转义:
a = "b"
f"{{ a }} vs {a}" # '{ a } vs b'
1.4 索引和切片
索引:
对于一个有序序列,可以通过索引的方法来访问对应位置的值。字符串便是一个有序序列的例子,使用[]来对有序序列进行索引。
索引是从 0 开始的,索引 0 对应与序列的第 1 个元素,当索引值大于最大值时,就会报错。
python 中还有负索引值,其为从后向前计数。
str = "abcdefghijk"
print(str[8], str[-2]) # i j
切片:
可以从序列中取出想要的子序列,其用法为:
var[lower:upper:step]
左闭右开,即包括 lower,不包括 upper;step 表示取值的步长。
这三个参数可以省略一部分,例如
a[:]:从头到尾,即创建副本a[1:]:从 1 到结尾a[:3]、a[:-2]:从 0 到 3、从 0 到倒数第二a[::-1]:逆序
str = "abcdefghijk"
print(str[0:4], str[0:7:2]) # abcd aceg
1.5 列表
列表在Python中非常有用,列表是一个有序的序列。列表用一对 [] 生成,中间的元素用 , 隔开,其中的元素不需要是同一类型,同时列表的长度也不固定。也可以利用list()或[]来生成空的列表
a = [1, 2.0, "abc"]
a, type(a), list() # ([1, 2.0, 'abc'], list, [])
列表的操作同字符串类似,如下:
len():输出列表的长度+:拼接*:重复
a = [1, 2]
b = [4, 5]
a + b, len(a + b), a * 3 # ([1, 2, 4, 5], 4, [1, 2, 1, 2, 1, 2])
数组的索引和切片可以读取也可以赋值
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
a[0], a[7], a[3:6], a[::3] # (1, 8, [4, 5, 6], [1, 4, 7])
# 切片赋值
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
a[5:7] = ["a", "b", "c", "d"]
print(a) # [1, 2, 3, 4, 5, 'a', 'b', 'c', 'd', 8, 9]
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
a[5:7] = []
print(a) # [1, 2, 3, 4, 5, 8, 9]
还可以用 del 删除
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
del a[0:3]
print(a) # [4, 5, 6, 7, 8, 9]
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
del a[::3]
print(a) # [2, 3, 5, 6, 8, 9]
- 测试从属关系:
in - 计数和索引:
l.count(a)返回列表 l 中 a 的个数;l.index(a)返回列表 l 中 a 第一次出现的索引位置,不存在会报错 - 添加,插入和移除:
l.append(a)在列表最后加入 al.extend(a)如果 a 是一个序列,相当于将序列中的每个元素依次appendl.insert(idx,a)在列表的 idx 索引处插入 al.remove(a)移除第一次出现的 a,不存在会报错
- 排序和反向:
a.sort()对 a 排序,但是改变 a 中的值;sorted()返回排序的索引,不改变原有值;reverse()列表反向
1.6 元组
- 与列表相似,元组也是个有序序列,可以索引和切片,但是其是不可变的
- 空元组:
()或tuple() - 注意:单元素元组应该写为
(1,),以避免和普通括号表达式产生歧义
t = (1, 3, 4, 6, 7, 56, 83, 3)
print(t[0], t[2:5], t[::2]) # 1 (4, 6, 7) (1, 4, 7, 83)
type((12,)), type((12)) # (tuple, int)
一般的,元组可以用来作为函数的多返回值,同时也可以用来对多变量进行赋值:
w, x, y, z = 1, 2, 3, 4
x = 1, 2, 3, 4
print(x, type(x)) # (1, 2, 3, 4) <class 'tuple'>
1.7 字典
字典,是一种由键值对组成的数据结构,常用于处理一对多的函数映射关系。
基本操作
创建字典: 可以通过 {} 或者 dict() 来创建空字典,同样也可以在创建时使用 key:value 这样的结构来初始化。
a = {}
b = dict()
c = {"1": "a1", "2": "a2"}
print(type(a), type(b), c["1"]) # <class 'dict'> <class 'dict'> a1
b[1] = "b1"
b["2"] = "b2"
print(b) # {1: 'b1', '2': 'b2'}
注意:
- 字典的键必须是不可变的类型,比如整数,字符串,元组等,而值可以是任意的 python 对象
- 一般不使用浮点数来作为键,因为其存在存储精度问题
字典方法
- 取值:
d.get(key),相比于使用d[key],其在字典中键不存在是不会报错,而是返回None。 - 删除元素:
d.pop(key),删除并返回键为key的键值对,如果没有返回None。同样可以使用del d[key]来进行删除。 - 更新字典:
d.update(d'),将字典d'中元素更新到d中。 - 查询字典:
a in d, 查询键a是否在字典d中。
注意:"不在" 一般写作 a not in d 而不是 not a in d
- keys 方法:
d.keys(), 返回所有键构成的序列。 - values 方法:
d.values(), 返回所有值构成的序列。 - items 方法:
d.items(), 返回所有键值对元组构成的序列。
1.8 集合
集合 set 是一种无序的序列,故当其中有两个相同的元素,只会保留一个;并且为了保证其中不包含相同元素,放入集合中元素只能是确定性对象。
集合的生成可以通过 {} 或者 set() 进行创建,但是在创建空集合,只能通过 set() 创建,因为 {} 表示空字典。
a = set()
b = {}
c = set([1, 2, 3, 2]) # 自动去除相同的元素
d = {1, 2, 3}
print(type(a), type(b), c, d) # <class 'set'> <class 'dict'> {1, 2, 3} {1, 2, 3}
集合操作:
- 并:
a.union(b)或者a | b - 交:
a.intersection(b)或者a & b - 差:
a.difference(b)或者a - b;在a中不在b中的元素 - 对称差:
a.symmetric_difference(b)或者a ^ b;在a或b中,但是不同时在a,b中的元素
2. 流程控制
2.1 if
- 基本结构是
if <条件>: - 不像 C 语言一样需要
{},而是用缩进来区分层级 elif是 else if 的含义- False,None,0,空字符串,空列表,空字典,空集合,都会被当做
False
a = 1
if a < 0:
if a < -1:
print("a < -1")
elif a == -1:
print("a = -1")
else:
print("-1 < a < 0")
else:
print("a >= 0") # 输出:a >= 0
# 因为缩进是必须的,而缩进后的内容又不能为空,所以我们通常写个 pass,它不会做任何事
# 在编写代码时,想要暂时先不写某个分支,可以用 pass 临时占位
if True:
pass
2.2 while
- 基本格式是
while <条件>: - 可以用
break跳出,用continue进入下一次循环
i = 0
total = 0
while i < 1000000:
total += i
i += 1
print(total) # 499999500000
2.3 for 和 range / zip / enumerate
- 基本格式是
for <变量> in <可迭代对象>,可迭代对象如列表、字符串、range、打开的文件等 - range 用于创建一串等差数列
range(3)-> 0, 1, 2range(1, 5)-> 1, 2, 3, 4range(1, 10, 2)-> 1, 3, 5, 7, 9,从 1 开始到 10,步长为 2
- 同样可以用
break和continue - 可选:可以接
else,当循环正常退出而非break退出时会执行
a = [1, 2, 3]
for i in a:
if i == 1:
print("a 里有 1")
break
else:
print("a 里没有 1") # 不会执行,因为break了
python 中的一个编程习惯是用 _ 变量表示不使用的值,比如我们想循环 3 次但不需要循环变量:
for _ in range(3):
print(233)
列表推导式
比 for-append 更快地创建列表
a = []
for i in range(10):
a.append(i * i)
# 等价于
a = [i * i for i in range(10)]
可以有 if
a = []
for i in range(10):
if i % 2 == 0:
a.append(i * i)
# 等价于
a = [i * i for i in range(10) if i % 2 == 0]
可以有多重循环
a = []
for i in range(10):
for j in range(i, 10):
a.append(i + j)
# 等价于
a = [i + j for i in range(10) for j in range(i, 10)]
zip
用于同时迭代多个可迭代对象,迭代次数以最短的那个为准
for x, y, z in zip("1234567", "abcdefg", "ABCDE"):
print(x, y, z)
# 输出:
# 1 a A
# 2 b B
# 3 c C
# 4 d D
# 5 e E
enumerate
用于同时迭代下标和值
a = "abcdefg"
for i, j in enumerate(a):
print(i, j)
# 输出:
# 0 a
# 1 b
# 2 c
# 3 d
# 4 e
# 5 f
# 6 g
3. 函数
- 格式:
def 函数名(参数列表): - 参数列表直接写变量名称,同样不用写类型
- 用
=定义关键字参数,类似 C++ 中的默认参数 - 用
return返回返回值,可以是任意类型
# 什么都不做的函数
def f():
pass
# 加法
def add(x, y):
a = x + y
return a
add(1, 2) # 3
python 不会检查传入的参数类型,这样既有灵活性,又有隐患:
add("abc", "def") # 'abcdef'
add("abc", 123) # 报错:TypeError
两种传参模式:
- 位置模式:按照位置传入参数
- 关键字模式:使用
a=123这样显式的指定参数名
可以混合这两种模式,但是位置模式必须在关键字模式之前。
print(add(x=2, y=3)) # 5
print(add(y="foo", x="bar")) # barfoo
print(add(2, y=3)) # 5
设定参数默认值
def quad(x, a=1, b=0, c=0):
return a * x**2 + b * x + c
print(quad(2.0)) # 4.0
print(quad(2.0, b=3)) # 10.0
接收不定长参数
*args 表示将多余的位置参数作为元组传给 args
def add(x, *args):
total = x
for arg in args:
total += arg
return total
print(add(1, 2, 3, 4)) # 10
print(add(1, 2)) # 3
**kwargs 表示将多余的关键字参数作为字典传给 kwargs
def add(x, **kwargs):
total = x
for arg, value in kwargs.items():
print("adding ", arg)
total += value
return total
print(add(10, y=11, z=12, w=13)) # 46
返回多个值
def f():
return 1, 2, 3
a, b, c = f()
print(a, b, c) # 1 2 3
4. 输入输出
用 input 函数获取输入:
a = input("请输入:") # 在 vs code 里运行时会在上方弹出一个输入框
输出用 print:
print(123)
a = 123
print("a 的值是:", a) # a 的值是: 123
更复杂的输出可以利用模板字符串:
a = 3
b = 3.1415926535
print(f"a 的值是 {a:03d},b 的值是 {b:.2f}") # a 的值是 003,b 的值是 3.14
5. 文件操作
# 写文本文件
with open("123.txt", "w", encoding="utf8") as f:
f.write("这是一行\n")
f.write("这是另一行\n")
with open("123.txt", "a", encoding="utf8") as f:
f.write("再给你加一行\n")
# 读取文本文件
with open("123.txt", "r", encoding="utf8") as f:
for i in f: # 迭代每一行
print(i)
with open("123.txt", "r", encoding="utf8") as f:
a = f.read() # 返回一个字符串
with open("123.txt", "r", encoding="utf8") as f:
a = f.readlines() # 返回每一行的字符串的列表
6. 包
类似 C/C++ 中的 #include 语句,我们可以用 import 导入我们希望用的包
import math
math.sin(math.pi / 4) # 0.7071067811865475
# 只导入部分函数
from math import sin
sin(1) # 0.8414709848078965
# 导入多个函数
from math import sin, cos
cos(1) # 0.5403023058681398
# 给导入的函数换个名字
from math import sin as a_ba_a_ba
a_ba_a_ba(1) # 0.8414709848078965
# 导入包中的全部内容(不推荐)
from math import *
sin(pi / 2) # 1.0
7. 类
基本格式如下
class A:
def __init__(self):
self.a = 1
def f(self, x):
self.b = 1
return self.a + x
- python 中以
__开头和结尾的是特殊的函数或变量 - 这里
__init__函数会在对象创建时执行,可以理解为构造函数 - 不以
_或__开头的函数都是public的 - 非静态类成员函数在被调用时会将类对象作为第一个参数传入,一般约定用
self作为参数名 - 在任何函数中,都可以通过
self.xxx = xxx的方式给对象添加新的属性
如果需要继承,基本格式如下
class B(A):
def __init__(self):
super().__init__()
...
这里 super() 会返回它所继承的父类(即 A),super().__init__() 表示调用父类的 __init__ 函数。
8. 异常处理
基本格式如下
try:
...
except ...:
...
else: # 可省略
...
finally: # 可省略
...
try后面接可能会出错的代码except后面接要捕获的错误类型,不接等价于except Exception,能捕获大部分错误类型;里面写出错后要执行的代码else后面是不出错时执行的代码finally后面是无论出不出错都会执行的代码- 用
raise抛出一个指定类型的错误 - 用
assert在断言为假时抛出一个AssertionError类型的错误