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 是一个序列,相当于将序列中的每个元素依次append
l.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
类型的错误