CiMorns
7477 words
37 minutes
Python and Pytorch Notes
T1T2T2T2
PytorchPT1 数据操作
PT1.1 生成张量
PT1.2 返回类型和数量
PT1.3 改变形状和连接
PT1.4 向量和矩阵运算
PT1.5 逻辑运算
PT1.6 广播机制(张量自动补行列)
PT1.7 索引和写入
PT1.8 张量转标量
PT2 自动微分
PT2.1 变元函数
PT2.2 变元求导
PT2.3 正反向求导
PT2.4 梯度计算
PT3 范数
PythonPY1 数据操作
PY1.1 数据类型转换
PY1.2 逻辑运算符
PY1.3 字符串格式化
a.format
b.f-string
PY2 条件和循环语句
PY2.1 条件语句
PY2.2 循环语句
a. while
b. for
PY3 列表、字典、类
PY3.1 列表
PY3.2 字典
PY3.3 类
PythonPY4 自定义函数PY5 文本读写PY6 捕捉异常

Pytorch#

Markdown文档可以放在Jupyter上查看

PT1 数据操作#

张量表示一个由数值组成的数组.

具有一个轴的张量对应数学上的向量

具有两个轴的张量对应数学上的矩阵

import torch

PT1.1 生成张量#

#########################
## 顺序生成
#########################
## 做运算要带小数点
x=torch.arange(12)
print( x )
## 顺序生成
## tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])


#########################
## 元素全为0
#########################
## torch.zeros(1,2,3)
## tensor([[[0., 0., 0.],
##          [0., 0., 0.]]])
## 先看大行有几个(中间空格隔开), 在看大行里有几行(第2个分量),  最后看数元素有几个(第3个分量)
## 第一层: 第1个维度有1个括号(元素)
## 第二层: 第2个维度有2个括号(元素)
## 第三层:第3个维度有3个元素


#########################
## 元素全为1
#########################
torch.ones(3,2,1)
## tensor([[[1.],
##          [1.]],
##
##         [[1.],
##          [1.]],
##
##         [[1.],
##          [1.]]])
## 第一层: 第1个维度有3个括号(元素)
## 第二层: 第2个维度有2个括号(元素)
## 第三层:第3个维度有1个元素


#########################
## 随机生成
#########################
torch.randn(3, 4)
## 每个元素都从均值为0、标准差为1的标准高斯分布(正态分布)
## tensor([[ 0.6600, -0.2045,  0.6985, -0.5108],
##         [ 0.7388,  1.2005,  0.1106, -0.6696],
##         [-0.5243, -0.3365, -0.5573,  1.0866]])


#########################
## 自定义元素
#########################
torch.tensor( [[2,1,3,1],[2,1,3,4],[1,3,3,2]] )
## tensor([[2, 1, 3, 1],
##         [2, 1, 3, 4],
##         [1, 3, 3, 2]])

PT1.2 返回类型和数量#

#########################
## 返回类型
#########################
x.shape
## torch.Size([12])


#########################
## 返回数量
#########################
x.numel()
## 12

PT1.3 改变形状和连接#

#########################
## 改变形状
#########################
y=x.reshape(3,4)
print( y )
## tensor([[ 0,  1,  2,  3],
##         [ 4,  5,  6,  7],
##         [ 8,  9, 10, 11]])
### 这个时候改变y的某个值, x也会被改变


#########################
## 连接
#########################
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
## dtype=torch.float32 张量的数据类型为 32 位浮点数
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0)
## dim=0, 按照第一个分量求和
## (tensor([[ 0.,  1.,  2.,  3.],
##          [ 4.,  5.,  6.,  7.],
##          [ 8.,  9., 10., 11.],
##          [ 2.,  1.,  4.,  3.],
##          [ 1.,  2.,  3.,  4.],
##          [ 4.,  3.,  2.,  1.]]),
torch.cat((X, Y), dim=1)
## dim=1, 按照第二个分量求和
##  tensor([[ 0.,  1.,  2.,  3.,  2.,  1.,  4.,  3.],
##          [ 4.,  5.,  6.,  7.,  1.,  2.,  3.,  4.],
##          [ 8.,  9., 10., 11.,  4.,  3.,  2.,  1.]]))

PT1.4 向量和矩阵运算#

sum()求和mean()求均值, 其他函数同样用法

#########################
## 向量运算
#########################
x=torch.tensor( [1.0,2,4,1] )
y=torch.tensor( [2,3,1,4] )
x+y,x-y,x*y,x/y,x**y
## 求幂运算
## (tensor([3., 5., 5., 5.]),
##  tensor([-1., -1.,  3., -3.]),
##  tensor([2., 6., 4., 4.]),
##  tensor([0.5000, 0.6667, 4.0000, 0.2500]),
##  tensor([1., 8., 4., 1.]))
torch.exp(x)
## 每个元素求指数
## tensor([ 2.7183,  7.3891, 54.5982,  2.7183])
x.sum()
## x的元素求和
## tensor(8.)
torch.dot(x,x)
## 内积
## tensor(14., grad_fn=<DotBackward0>)


#########################
## 矩阵运算
#########################
A=torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1],[4, 3, 2, 1]])
## tensor([[2., 1., 4., 3.],
##         [1., 2., 3., 4.],
##         [4., 3., 2., 1.],
##         [4., 3., 2., 1.]])

A.T
## 矩阵的转置
## tensor([[2., 1., 4., 4.],
##         [1., 2., 3., 3.],
##         [4., 3., 2., 2.],
##         [3., 4., 1., 1.]])

A*(A.T)
## 矩阵元素对应想乘
## tensor([[ 4.,  1., 16., 12.],
##         [ 1.,  4.,  9., 12.],
##         [16.,  9.,  4.,  2.],
##         [12., 12.,  2.,  1.]])
torch.matmul(A,(A.T))
## 或者 torch.mm(A,A.T)
## 矩阵乘法
## tensor([[30., 28., 22., 22.],
##         [28., 30., 20., 20.],
##         [22., 20., 30., 30.],
##         [22., 20., 30., 30.]])

torch.mm(A,A.T)

a=2
a*A
## a乘矩阵的每个元素
## tensor([[4., 2., 8., 6.],
##         [2., 4., 6., 8.],
##         [8., 6., 4., 2.],
##         [8., 6., 4., 2.]])

A.sum(axis=0)
## 降了一维度
## 第一个维度求和, axis=1(第2个)
## 比如shape=[2,5,3],axis=1, 开了True, 会变成shape=[2,3]
## tensor([11.,  9., 11.,  9.])
A.sum(axis=0,keepdims=True)
## 保持原有维度不变
## tensor([[11.,  9., 11.,  9.]])
## 比如shape=[2,5,3],axis=1, 开了True, 会变成shape=[2,1,3]

A.sum()
## 矩阵所有元素求和
## tensor(40.)

A.cumsum(axis=1)
## axis=0 沿着第一个轴累加
## 第一行不变, R2=R2+R1, R3=R3+R2...
## axis=1 沿着第二个轴累加
## 第一列不变, C2=C2+C1, C3=C3+C2...
## tensor([[ 2.,  3.,  7., 10.],
##         [ 1.,  3.,  6., 10.],
##         [ 4.,  7.,  9., 10.],
##         [ 4.,  7.,  9., 10.]])

PT1.5 逻辑运算#

X == Y
## 如果X和Y在该位置相等, 则新张量中相应项的值为1
## 这意味着逻辑语句X == Y在该位置处为真, 否则该位置为0. 
## tensor([[False,  True, False,  True],
##         [False, False, False, False],
##         [False, False, False, False]])

PT1.6 广播机制(张量自动补行列)#

通过适复制元素来扩展一个或两个数组, 以便在转换之后, 两个张量具有相同的形状;

对生成的数组执行按元素操作.

a = torch.arange(3).reshape((3, 1))
## (tensor([[0],
##          [1],
##          [2]]),
b = torch.arange(2).reshape((1, 2))
##  tensor([[0, 1]]))

## 矩阵a将复制列,  矩阵b将复制行, 然后再按元素相加. 

a + b
## tensor([[0, 1],
##         [1, 2],
##         [2, 3]])

PT1.7 索引和写入#

#########################
## 索引
#########################
X[-1]
## [-1]选择最后一个元素
## (tensor([ 8.,  9., 10., 11.]),
X[1:3]
##  tensor([[ 4.,  5.,  6.,  7.],
##          [ 8.,  9., 10., 11.]]))


#########################
## 写入
#########################
X[1, 2] = 9
## tensor([[ 0.,  1.,  2.,  3.],
##         [ 4.,  5.,  9.,  7.],
##         [ 8.,  9., 10., 11.]])

X[0:2, :] = 12
## [0:2, :]访问第1行和第2行
## tensor([[12., 12., 12., 12.],
##         [12., 12., 12., 12.],
##         [ 8.,  9., 10., 11.]])

PT1.8 张量转标量#

a = torch.tensor([3.5])
a, a.item(), float(a), int(a)
## (tensor([3.5000]), 3.5, 3.5, 3)

PT2 自动微分#

PT2.1 变元函数#

函数类型标量变元向量变元矩阵变元
标量函数f(x)=i=0naixif(x)=\sum\limits_{i = 0}^{n}a_{i}x^{i}aia_{i}为常数)

f(x)=2x2+3x+1f(x)=2x^{2}+3x + 1

f(2)=2×22+3×2+1=15f(2)=2×2^{2}+3×2 + 1 = 15
f(x)=aTx=i=1naixif(\boldsymbol{x})=\boldsymbol{a}^T\boldsymbol{x}=\sum\limits_{i = 1}^{n}a_{i}x_{i}a\boldsymbol{a}为常向量)

a=(1,2,3)\boldsymbol{a}=(1,2,3), x=(x1,x2,x3)\boldsymbol{x}=(x_1,x_2,x_3), 则f(x)=1×x1+2×x2+3×x3f(\boldsymbol{x})=1\times x_1+2\times x_2 + 3\times x_3

f(1,2,3)=1×1+2×2+3×3=14f(1,2,3)=1×1 + 2×2 + 3×3 = 14
f(X)=det(X)f(\boldsymbol{X})=\text{det}(\boldsymbol{X})

X=[1234]\boldsymbol{X}=\begin{bmatrix}1&2\\3&4\end{bmatrix}, f(X)=1×42×3=2f(\boldsymbol{X})=1\times4 - 2\times3=-2
向量函数f(x)=(f1(x),,fm(x))T\boldsymbol{f}(x)=(f_1(x),\cdots,f_m(x))^T

f(x)=[x2sin(x)]\boldsymbol{f}(x)=\begin{bmatrix}x^{2}\\\sin(x)\end{bmatrix}

f(π2)=[(π2)2sin(π2)]=[π241]\boldsymbol{f}(\frac{\pi}{2})=\begin{bmatrix}(\frac{\pi}{2})^{2}\\\sin(\frac{\pi}{2})\end{bmatrix}=\begin{bmatrix}\frac{\pi^{2}}{4}\\1\end{bmatrix}
f(x)=Ax\boldsymbol{f}(\boldsymbol{x})=\boldsymbol{A}\boldsymbol{x}

A=[1234]\boldsymbol{A}=\begin{bmatrix}1&2\\3&4\end{bmatrix}, x=(x1,x2)T\boldsymbol{x}=(x_1,x_2)^T, f(x)=[1×x1+2×x23×x1+4×x2]\boldsymbol{f}(\boldsymbol{x})=\begin{bmatrix}1\times x_1+2\times x_2\\3\times x_1 + 4\times x_2\end{bmatrix}

f(2,3)=[1×2+2×33×2+4×3]=[818]\boldsymbol{f}(2,3)=\begin{bmatrix}1×2 + 2×3\\3×2 + 4×3\end{bmatrix}=\begin{bmatrix}8\\18\end{bmatrix}

f(X)=(f1(X),,fm(X))T\boldsymbol{f}(\boldsymbol{X})=(f_1(\boldsymbol{X}),\cdots,f_m(\boldsymbol{X}))^T

f(X)=[tr(X)det(X)]\boldsymbol{f}(\boldsymbol{X})=\begin{bmatrix}\text{tr}(\boldsymbol{X})\\\text{det}(\boldsymbol{X})\end{bmatrix}

f(X)=[1+41×42×3]=[52]\boldsymbol{f}(\boldsymbol{X})=\begin{bmatrix}1 + 4\\1\times4 - 2\times3\end{bmatrix}=\begin{bmatrix}5\\-2\end{bmatrix}
矩阵函数F(x)=(fij(x))m×n\boldsymbol{F}(x)=(f_{ij}(x))_{m\times n}

F(x)=[xx2x3x4]\boldsymbol{F}(x)=\begin{bmatrix}x&x^{2}\\x^{3}&x^{4}\end{bmatrix}

F(3)=[3323334]=[392781]\boldsymbol{F}(3)=\begin{bmatrix}3&3^{2}\\3^{3}&3^{4}\end{bmatrix}=\begin{bmatrix}3&9\\27&81\end{bmatrix}
F(x)=(fij(x))m×n\boldsymbol{F}(\boldsymbol{x})=(f_{ij}(\boldsymbol{x}))_{m\times n}

F(x)=[x1+x2x1x2x1x2x1+x2]\boldsymbol{F}(\boldsymbol{x})=\begin{bmatrix}x_1 + x_2&x_1 - x_2\\x_1 - x_2&x_1 + x_2\end{bmatrix}

F(4,1)=[4+141414+1]=[5335]\boldsymbol{F}(4,1)=\begin{bmatrix}4 + 1&4 - 1\\4 - 1&4 + 1\end{bmatrix}=\begin{bmatrix}5&3\\3&5\end{bmatrix}
F(X)=AXB+C\boldsymbol{F}(\boldsymbol{X})=\boldsymbol{A}\boldsymbol{X}\boldsymbol{B}+\boldsymbol{C}

A=[1001]\boldsymbol{A}=\begin{bmatrix}1&0\\0&1\end{bmatrix}, B=[1111]\boldsymbol{B}=\begin{bmatrix}1&1\\1&1\end{bmatrix}, C=[0000]\boldsymbol{C}=\begin{bmatrix}0&0\\0&0\end{bmatrix}, X=[abcd]\boldsymbol{X}=\begin{bmatrix}a&b\\c&d\end{bmatrix}

F(X)=[a+ba+bc+dc+d]\boldsymbol{F}(\boldsymbol{X})=\begin{bmatrix}a + b&a + b\\c + d&c + d\end{bmatrix}

F([2345])=[2+32+34+54+5]=[5599]\boldsymbol{F}(\begin{bmatrix}2&3\\4&5\end{bmatrix})=\begin{bmatrix}2 + 3&2 + 3\\4 + 5&4 + 5\end{bmatrix}=\begin{bmatrix}5&5\\9&9\end{bmatrix}

PT2.2 变元求导#

函数类型Jacobian 形式梯度形式
向量变元的实值标量函数f(x)f(\boldsymbol{x})Dxf(x)=f(x)xT=[fx1,fx2,,fxn]D_{\boldsymbol{x}}f(\boldsymbol{x})=\frac{\partial f(\boldsymbol{x})}{\partial\boldsymbol{x}^T} = \left[\frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, \cdots, \frac{\partial f}{\partial x_n}\right]xf(x)=f(x)x=[fx1,fx2,,fxn]T\nabla_{\boldsymbol{x}}f(\boldsymbol{x})=\frac{\partial f(\boldsymbol{x})}{\partial\boldsymbol{x}} = \left[\frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, \cdots, \frac{\partial f}{\partial x_n}\right]^T
矩阵变元的实值标量函数f(X)f(\boldsymbol{X})DXf(X)=k=1mnfxijekekTD_{\boldsymbol{X}}f(\boldsymbol{X})=\sum\limits_{k = 1}^{mn}\frac{\partial f}{\partial x_{ij}}\boldsymbol{e}_k\boldsymbol{e}_k^T,Xf(X)=i=1mj=1nfxijEij\nabla_{\boldsymbol{X}}f(\boldsymbol{X})=\sum\limits_{i = 1}^{m}\sum\limits_{j = 1}^{n}\frac{\partial f}{\partial x_{ij}}\boldsymbol{E}_{ij}
矩阵变元的实矩阵函数F(X)\boldsymbol{F}(\boldsymbol{X})DXF(X)=(IqDvecXvec(F(X)))(InEm×p)D_{\boldsymbol{X}}\boldsymbol{F}(\boldsymbol{X}) = (\boldsymbol{I}_q\otimes\text{D}_{\text{vec}\boldsymbol{X}}\text{vec}(\boldsymbol{F}(\boldsymbol{X})))(\boldsymbol{I}_n\otimes\boldsymbol{E}_{m\times p})XF(X)=k=1pl=1qXFkl(X)ekelT\nabla_{\boldsymbol{X}}\boldsymbol{F}(\boldsymbol{X})=\sum\limits_{k = 1}^{p}\sum\limits_{l = 1}^{q}\nabla_{\boldsymbol{X}}F_{kl}(\boldsymbol{X})\otimes\boldsymbol{e}_k\boldsymbol{e}_l^T

PT2.3 正反向求导#

正向求导

已知f(x)=3x+2f(x)=3x + 2g(y)=y2g(y)=y^2, 复合函数h(x)=g(f(x))=(3x+2)2h(x)=g(f(x))=(3x + 2)^2

要求f(x)f^\prime(x)dh(x)dx\frac{dh(x)}{dx}.

  • f(x)=df(x)dx=3f^\prime(x)=\frac{df(x)}{dx}=3

  • dh(x)dx=dg(f(x))df(x)df(x)dx=2y(3x+2)=18x+12\frac{dh(x)}{dx}=\frac{dg(f(x))}{df(x)}\cdot\frac{df(x)}{dx}=2y(3x + 2)=18x + 12

反向求导

已知h(x)=g(f(x))=(3x+2)2h(x)=g(f(x))=(3x + 2)^2和损失函数L=h(x)2=(3x+2)4L = h(x)^2=(3x + 2)^4

要求计算Lh(x)\frac{\partial L}{\partial h(x)}, Lf(x)\frac{\partial L}{\partial f(x)}Lx\frac{\partial L}{\partial x}

  • Lh(x)=2h(x)=2(3x+2)2\frac{\partial L}{\partial h(x)} = 2h(x)=2(3x + 2)^2

  • Lf(x)=Lh(x)h(x)f(x)=2h(x)2f(x)=2(3x+2)22(3x+2)=4(3x+2)3\frac{\partial L}{\partial f(x)}=\frac{\partial L}{\partial h(x)}\cdot\frac{\partial h(x)}{\partial f(x)}=2h(x)\cdot 2f(x)=2(3x + 2)^2\cdot 2(3x + 2)=4(3x + 2)^3

  • Lx=Lh(x)h(x)f(x)f(x)x=2h(x)2f(x)3=12(3x+2)3\frac{\partial L}{\partial x}=\frac{\partial L}{\partial h(x)}\cdot\frac{\partial h(x)}{\partial f(x)}\cdot\frac{\partial f(x)}{\partial x}=2h(x)\cdot 2f(x)\cdot 3=12(3x + 2)^3

PT2.4 梯度计算#

#########################
## 标量反向传播
#########################
## 我们对$y=2\mathbb{x^T}x$,对$x$是列向量求导
x = torch.arange(4.0)
## 需要内存来存储梯度
x.requires_grad_(True)  
## 等价于x=torch.arange(4.0,requires_grad=True)
y = 2 * torch.dot(x, x)
## 对x做内积
## tensor(28., grad_fn=<MulBackward0>)

## 接下来, 通过调用反向传播函数来自动计算y关于x每个分量的梯度, 并打印这些梯度
y.backward()
x.grad
## tensor([ 0.,  4.,  8., 12.])

## 验证这个梯度是否计算正确. 
x.grad == 4 * x
## tensor([True, True, True, True])

## 在默认情况下, PyTorch会累积梯度, 我们需要清除之前的值
x.grad.zero_()
## _是指重写的意思
## tensor([0., 0., 0., 0.])


#########################
## 非标量反向传播
#########################
## 对非标量调用backward需要传入一个gradient参数, 该参数指定微分函数关于self的梯度. 
## 本例只想求偏导数的和, 所以传递一个1的梯度是合适的
x.grad.zero_()
y = x * x
## 等价于y.backward(torch.ones(len(x)))
y.sum().backward()
x.grad
## tensor([0., 2., 4., 6.])


#########################
## 分离计算
#########################
## 清零 x 的梯度
x.grad.zero_()

## 构建了计算图
y = x * x

## detach() 方法会返回一个新的张量 u
## 它和 y 共享数据但没有计算图的连接
## 即 u 不会参与梯度的反向传播
u = y.detach()

## 计算 z, 这里是 u 和 x 的逐元素相乘
z = u * x

## 对 z 的所有元素求和, 并进行反向传播计算梯度
## 因为 x 是可求导的, 会根据链式法则计算 x 的梯度
z.sum().backward()
x.grad
## tensor([0., 1., 4., 9.])


#########################
## 控制流的梯度计算
#########################
def f(a):
    b = a * 2
    while b.norm() < 1000:
        b = b * 2
    if b.sum() > 0:
        c = b
    else:
        c = 100 * b
    return c

a = torch.randn(size=(), requires_grad=True)
## 一个服从标准正态分布的随机标量张量 a, 并且设定该张量需要计算梯度. 
d = f(a)
d.backward()
a.grad
## tensor(409600.)

PT3 范数#

x=torch.tensor([3.0,-4.0])
### L_1范数:所有元素的绝对值求和
torch.abs(x).sum()
## tensor(7.)


### L_2范数(矩阵中的F范数):所有元素平方和开根号
torch.norm(x)
## tensor(5.)
torch.abs(x).sum()
## tensor(7.)

Python#

PY1 数据操作#

PY1.1 数据类型转换#

#########################
# float():整数转换为浮点数
#########################
num_float= float(10) 
# 输出 10.0


#########################
# int():浮点数转换为整数
#########################
num_int= float(3.14) 
# 输出 3


#########################
# str(): 转字符串
#########################
str_int = str(123) 
# 输出 '123'
str_float = str(3.14) 
# 输出 '3.14'


#########################
# tuple():列表转换为元组
#########################
list_data = [1, 2, 3]
tuple_data = tuple(list_data)
# 输出 (1, 2, 3)


#########################
# list():元组转换为列表
#########################
# 原始元组(不可变)
fixed_data = ("apple", "banana", 3.14, 100)
# 转换为列表以进行修改
mutable_list = list(fixed_data)

#########################
# set(): 列表或元组转换为集合, 集合会自动去重
#########################
list_data = [1, 2, 2, 3]
set_data = set(list_data)
# 输出 {1, 2, 3}

PY1.2 逻辑运算符#

#########################
# and 连接两个条件, 两个条件都为 True 时, 整个表达式才为 True
#########################
# 语法格式:condition1 and condition2
x = 5  
y = 10 
# 检查 x 是否大于 0 并且 y 是否小于 20
if x > 0 and y < 20:
    print("两个条件都满足")  
    # 如果上述两个条件都满足, 打印此信息


#########################
# or 连接两个条件, 只要有一个条件为 True, 整个表达式就为 True
#########################
# 语法格式:condition1 or condition2
x = 5  
y = 10 
# 检查 x 是否小于 0 或者 y 是否大于 5
if x < 0 or y > 5:
    print("至少有一个条件满足")  
    # 如果上述两个条件至少有一个满足, 打印此信息


#########################
# not 逻辑运算符用于对条件取反, 它的优先级高于 and 和 or
#########################
# 语法格式:not condition
x = 5 
# 对 x > 10 这个条件取反, 即检查 x 是否不大于 10
if not x > 10:
    print("x 不大于 10")  
    # 如果 x 不大于 10, 打印此信息


x = 5
y = 10
z = 15
# 先计算 not (x > 10), 结果为 True
# 再计算 True and (y < 20), 结果为 True
# 最后计算 True or (z > 20), 结果为 True
result = not (x > 10) and (y < 20) or (z > 20)
print(result)

PY1.3 字符串格式化#

a.format#

#########################
# 简单的填充
#########################
# 在字符串中使用花括号 `{}` 作为占位符, 然后通过 `format()` 方法传入要填充的值. 
name = "Alice"
age = 20
message = "My name is {} and I am {} years old.".format(name, age)
print(message)
# 第一个 `{}` 会被 `name` 的值替换, 第二个 `{}` 会被 `age` 的值替换. 


#########################
# 通过索引指定填充顺序
#########################
# 可以在花括号中指定索引, 来明确填充值的顺序. 
name = "Bob"
age = 25
message = "I am {1} years old and my name is {0}.".format(name, age)
print(message)
# 这里 `{0}` 对应 `format()` 方法中的第一个参数 `name`, `{1}` 对应第二个参数 `age`. 


#########################
# 通过关键字参数指定填充
#########################
# 可以使用关键字参数来指定填充的值, 在花括号中使用关键字. 
message = "My name is {name} and I am {age} years old.".format(name="Charlie", age=30)
print(message)
# 在这个例子中, `{name}` 会被 `"Charlie"` 替换, `{age}` 会被 `30` 替换. 


#########################
# 指定小数位数
#########################
pi = 3.1415926
formatted_pi = "The value of pi is {:.2f}".format(pi)
print(formatted_pi)
# `{:.2f}` 表示将数字格式化为浮点数, 并保留两位小数. 


#########################
# 添加千位分隔符
#########################
number = 1234567
formatted_number = "The number is {:,}".format(number)
print(formatted_number)
# `{:,}` 表示为数字添加千位分隔符. 


#########################
# 格式化日期和时间
#########################
import datetime
now = datetime.datetime.now()
formatted_date = "Today is {:%Y-%m-%d %H:%M:%S}".format(now)
print(formatted_date)
# `{:%Y-%m-%d %H:%M:%S}` 是日期和时间的格式化字符串, 用于指定日期和时间的显示格式. 

b.f-string#

name = "Alice"
age = 25
message = f"My name is {name} and I am {age} years old."
print(message)
# `{name}` 会被变量 `name` 的值 `"Alice"` 替换, `{age}` 会被变量 `age` 的值 `25` 替换. 


#########################
# 支持任意表达式
#########################
# `{}` 内不仅可以是简单的变量名, 还能是任意有效的 Python 表达式. 
num1 = 10
num2 = 20
result = f"The sum of {num1} and {num2} is {num1 + num2}."
print(result)
# `{num1 + num2}` 会先计算 `num1 + num2` 的结果, 再将结果替换到字符串中. 


#########################
# 指定小数位数
#########################
pi = 3.1415926
formatted_pi = f"The value of pi is {pi:.2f}"
print(formatted_pi)
# `{pi:.2f}` 表示将 `pi` 的值格式化为浮点数并保留两位小数. 


#########################
# 添加千位分隔符
#########################
number = 1234567
formatted_number = f"The number is {number:,}"
print(formatted_number)
# `{number:,}` 表示为 `number` 的值添加千位分隔符. 


#########################
# 格式化日期和时间
#########################
# f-string 同样支持结合 `strftime()` 方法对日期和时间进行格式化. 
import datetime
now = datetime.datetime.now()
formatted_date = f"Today is {now:%Y-%m-%d %H:%M:%S}"
print(formatted_date)
# `{now:%Y-%m-%d %H:%M:%S}` 是日期和时间的格式化字符串, 用来指定日期和时间的显示格式. 


PY2 条件和循环语句#

PY2.1 条件语句#

# if condition1:
#     # 当 condition1 为真时执行的代码
#     statement1
#     statement2
#     ...
# elif condition2:
#     # 当 condition1 为假且 condition2 为真时执行的代码
#     statement3
#     statement4
#     ...
# elif condition3:
#     # 当 condition1 和 condition2 都为假且 condition3 为真时执行的代码
#     statement5
#     statement6
#     ...
# else:
#     # 当所有条件都为假时执行的代码
#     statement7
#     statement8
#     ...

# 定义变量 x 并赋值为 15
x = 15
# 进行条件判断, 若 x 的值小于 10
if x < 10:
    # 当条件满足时, 打印信息
    print("x 小于 10")
# 若上面的条件不满足, 继续判断 x 是否小于 20
elif x < 20:
    # 当此条件满足时, 打印信息
    print("x 大于等于 10 且小于 20")
# 若前面的条件都不满足, 即 x 大于等于 20
else:
    # 打印相应信息
    print("x 大于等于 20")

PY2.2 循环语句#

a. while#

# while condition:
#     # 当条件为真时执行的代码块
#     statement1
#     statement2
# else:
#     statement3

count = 0
while count < 5:
    print(count)
    count = count + 1
else:
    print("循环正常结束")


#########################
# break 语句用于提前终止循环
#########################
count = 0
while count < 10:
    if count == 5:
        break
    print(count)
    count = count + 1
# 当 count 的值等于 5 时, 执行 break 语句, 循环立即终止, 不会再继续执行后续的循环. 


#########################
# continue 语句用于跳过当前循环的剩余部分, 直接进入下一次循环的条件判断
#########################
count = 0
while count < 10:
    count = count + 1
    if count % 2 == 0:
        continue
    print(count)
# 当 count 为偶数时, 执行 continue 语句, 跳过 print(count) 这一行代码, 直接进入下一次循环的条件判断. 

b. for#

# for 变量 in 可迭代对象:
#     # 循环体, 每次迭代执行的代码
#     语句1
#     语句2
#     ...


#########################
# 遍历列表
#########################
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)
# fruits 是一个列表. for 循环每次迭代时, fruit 变量会依次被赋值为列表中的元素, 然后打印出来. 

# 遍历字符串
message = "Hello"
for char in message:
    print(char)
# message 是一个字符串. for 循环会逐个遍历字符串中的字符, 并打印出来

# 遍历元组
numbers = (1, 2, 3, 4, 5)
for num in numbers:
    print(num)
#numbers 是一个元组, for 循环会依次将元组中的元素赋值给 num 变量并打印. 

# 遍历字典的键、值、键值对
student = {
    "name": "Alice",
    "age": 20,
    "major": "Computer Science"
}
for key in student:
    print(key)
# 遍历的是字典的键
for value in student.values():
    print(value)
# 遍历的是字典的值
for key, value in student.items():
    print(f"{key}: {value}")
# 遍历字典的键值对


#########################
# break 语句用于提前终止循环
#########################
numbers = [1, 2, 3, 4, 5]
for num in numbers:
    if num == 3:
        break
    print(num)
# 当 num 等于 3 时, break 语句会使循环立即终止. 


#########################
# continue 语句用于跳过当前循环的剩余部分, 直接进入下一次循环. 
#########################
numbers = [1, 2, 3, 4, 5]
for num in numbers:
    if num == 3:
        continue
    print(num)
# 当 num 等于 3 时, continue 语句会跳过 print(num) 这一行, 直接进入下一次循环. 


PY3 列表、字典、类#

PY3.1 列表#

#########################
# 创建一个空列表
#########################
empty_list = []
# 创建一个包含整数的列表
numbers = [1, 2, 3, 4, 5]
# 创建一个包含不同数据类型的列表
mixed_list = [1, "hello", True, 3.14]

# 访问首先元素
first_element = numbers[0]
# 访问最后元素
last_element = numbers[-1]
# 访问数组元素
subset = numbers[1:4]
print(subset)  
# 输出 [2, 3, 4]


#########################
# 修改元素
#########################
numbers[2] = 10


#########################
# append():添加元素
#########################
numbers = [1, 2, 3]
numbers.append(4)
print(numbers)  # 输出 [1, 2, 3, 4]


#########################
# extend():扩展元素
#########################
numbers = [1, 2, 3]
new_numbers = [4, 5]
numbers.extend(new_numbers)
print(numbers)  # 输出 [1, 2, 3, 4, 5]


#########################
# insert():插入一个元素
#########################
numbers = [1, 2, 3]
numbers.insert(1, 10)
print(numbers)  # 输出 [1, 10, 2, 3]


#########################
# remove():删除元素
#########################
numbers = [1, 2, 3, 2]
numbers.remove(2)
print(numbers)  # 输出 [1, 3, 2]


#########################
# pop():删除并返回指定索引位置的元素
#########################
numbers = [1, 2, 3]
popped = numbers.pop(1)
print(popped)  # 输出 2
print(numbers)  # 输出 [1, 3]


#########################
# len():返回长度
#########################
numbers = [1, 2, 3]
length = len(numbers)
print(length)  # 输出 3


#########################
# sort():对列表进行排序, 默认是升序
#########################
numbers = [3, 1, 2]
numbers.sort()
print(numbers)  # 输出 [1, 2, 3]


#########################
# reverse():反转顺序
#########################
numbers = [1, 2, 3]
numbers.reverse()
print(numbers)  # 输出 [3, 2, 1]

PY3.2 字典#

#########################
# 创建一个空字典
#########################
empty_dict = {}
# 创建一个包含键值对的字典
student = {
    "name": "Alice",
    "age": 20,
    "major": "Computer Science"
}


#########################
# dict() :创建字典
#########################
# 通过传入键值对参数创建字典
person = dict(name="Bob", age=25, occupation="Engineer")
# 通过传入包含键值对元组的列表创建字典
scores = dict([("math", 90), ("english", 85), ("science", 92)])


#########################
# 键访问值
#########################
name = student["name"]
print(name)  # 输出 "Alice"


#########################
# get() 访问值
#########################
# 键存在, 返回对应的值
age = student.get("age")
print(age)  # 输出 20
# 键不存在, 返回默认值(这里默认值为 None)
grade = student.get("grade")
print(grade)  # 输出 None


#########################
# 修改已有值
#########################
# 修改年龄
student["age"] = 21
print(student)  # 输出 {'name': 'Alice', 'age': 21, 'major': 'Computer Science'}



#########################
# 添加新的键值对
#########################
student["grade"] = "A"
print(student)  # 输出 {'name': 'Alice', 'age': 20, 'major': 'Computer Science', 'grade': 'A'}


#########################
# pop() :删除键值
#########################
# 删除并返回指定键的值
major = student.pop("major")
print(major)  # 输出 "Computer Science"
print(student)  # 输出 {'name': 'Alice', 'age': 20}


#########################
# keys()/values():返回一个包含字典所有键的视图对象, 可以将其转换为列表. 
#########################
keys = student.keys()
print(list(keys))  # 输出 ['name', 'age', 'major']


#########################
# values():返回一个包含字典所有值的视图对象, 可以将其转换为列表. 
#########################
values = student.values()
print(list(values))  # 输出 ['Alice', 20, 'Computer Science']


#########################
# items():返回一个包含字典所有键值对元组的视图对象, 可以将其转换为列表. 
#########################
items = student.items()
print(list(items))  # 输出 [('name', 'Alice'), ('age', 20), ('major', 'Computer Science')]


#########################
# len():返回字典中键值对的数量
#########################
student = {
    "name": "Alice",
    "age": 20,
    "major": "Computer Science"
}
length = len(student)
print(length)  # 输出 3

PY3.3 类#

# class 类名:
#     # 类属性(可选)
#     类属性名 = 属性值

#     def __init__(self, 参数列表):
#         # 实例属性的初始化
#         self.实例属性名 = 参数

#     def 方法名(self, 参数列表):
#         # 方法体, 实现具体功能的代码
#         语句1
#         语句2
#         ...
#         return 返回值  
#         # 可选, 用于返回方法的执行结果

# __init__ 用于在创建类的实例时初始化实例属性. 
# self 是一个约定俗成的参数名, 它代表类的实例本身, 在类的方法中必须作为第一个参数. 

# 定义一个名为 Person 的类, 用于表示一个人
class Person:
    # 类属性, 所有 Person 类的实例都共享这个属性
    # 这里表示人的物种为智人
    species = "Homo sapiens"

    # 类的构造方法, 在创建 Person 类的实例时自动调用
    # self 代表类的实例本身, name 和 age 是初始化实例所需的参数
    def __init__(self, name, age):
        # 实例属性, 每个实例都有自己独立的这些属性值
        # 将传入的 name 参数赋值给实例的 name 属性
        self.name = name
        # 将传入的 age 参数赋值给实例的 age 属性
        self.age = age

    # 定义一个实例方法, 用于让 Person 类的实例进行自我介绍
    # self 代表类的实例本身
    def introduce(self):
        # 使用 f-string 格式化字符串, 返回一个包含实例名字和年龄的自我介绍信息
        return f"My name is {self.name} and I am {self.age} years old."

# 创建 Person 类的一个实例, 名为 person1
# 传入参数 "Alice" 作为名字, 25 作为年龄
person1 = Person("Alice", 25)
# 调用 person1 实例的 introduce 方法, 打印自我介绍信息
print(person1.introduce())
# 访问 person1 实例的类属性 species, 打印物种信息
print(person1.species)


#########################
# 单继承
#########################
# class 子类名(父类名):
#     # 子类可以添加自己的属性和方法
#     def __init__(self, 参数列表):
#         # 调用父类的构造方法
#         super().__init__(参数列表)
#         # 子类特有的实例属性初始化
#         self.子类实例属性名 = 参数

#     def 子类方法名(self, 参数列表):
#         # 子类特有的方法实现
#         语句1
#         语句2
#         ...
#         return 返回值  # 可选
# 定义一个名为 Student 的类, 它继承自 Person 类
# 这意味着 Student 类会拥有 Person 类的属性和方法, 并可以在此基础上进行扩展
class Student(Person):
    # 定义 Student 类的构造函数, 用于初始化实例的属性
    # 参数 name 代表学生的姓名, age 代表学生的年龄, student_id 代表学生的学号
    def __init__(self, name, age, student_id):
        # 调用父类 Person 的构造函数, 将 name 和 age 传递给父类进行初始化
        # 这样可以复用父类中对 name 和 age 属性的初始化逻辑
        super().__init__(name, age)
        # 为 Student 类的实例添加特有的属性 student_id
        self.student_id = student_id

    # 定义一个名为 study 的实例方法, 用于描述学生正在学习的行为
    def study(self):
        # 使用 f-string 格式化字符串, 返回一个包含学生姓名和学号的学习信息
        return f"{self.name} (ID: {self.student_id}) is studying."

# 创建 Student 类的一个实例, 名为 student1
# 传入参数 "Bob" 作为学生姓名, 20 作为学生年龄, "S12345" 作为学生学号
student1 = Student("Bob", 20, "S12345")
# 调用 student1 实例从父类 Person 继承而来的 introduce 方法, 打印自我介绍信息
print(student1.introduce())
# 调用 student1 实例自身的 study 方法, 打印学习信息
print(student1.study())


#########################
# 多继承
#########################
# class 子类名(父类名1, 父类名2, ...):
#     # 子类可以添加自己的属性和方法
#     def __init__(self, 参数列表):
#         # 调用父类的构造方法
#         super().__init__(参数列表)
#         # 子类特有的实例属性初始化
#         self.子类实例属性名 = 参数

#     def 子类方法名(self, 参数列表):
#         # 子类特有的方法实现
#         语句1
#         语句2
#         ...
#         return 返回值  # 可选
# 定义一个名为 Worker 的类, 代表工作人员
class Worker:
    # 类的构造函数, 用于初始化 Worker 类实例的属性
    # job_title 参数表示工作人员的职位
    def __init__(self, job_title):
        # 将传入的 job_title 参数赋值给实例的 job_title 属性
        self.job_title = job_title

    # 定义一个实例方法 work, 用于描述工作人员正在工作的状态
    def work(self):
        # 使用 f-string 格式化字符串, 返回包含工作人员职位的工作信息
        return f"Working as a {self.job_title}."

# 定义一个名为 WorkingStudent 的类, 它继承自 Student 类和 Worker 类
# 这体现了多继承, 意味着 WorkingStudent 类可以拥有 Student 类和 Worker 类的属性和方法
class WorkingStudent(Student, Worker):
    # 定义 WorkingStudent 类的构造函数, 用于初始化其实例的属性
    # name 表示学生姓名, age 表示学生年龄, student_id 表示学生学号, job_title 表示工作职位
    def __init__(self, name, age, student_id, job_title):
        # 调用 Student 类的构造函数, 初始化从 Student 类继承的属性
        Student.__init__(self, name, age, student_id)
        # 调用 Worker 类的构造函数, 初始化从 Worker 类继承的属性
        Worker.__init__(self, job_title)

    # 定义一个实例方法 balance, 用于描述在职学生平衡学习和工作的状态
    def balance(self):
        # 使用 f-string 格式化字符串, 返回包含学生姓名的平衡学习与工作的信息
        return f"{self.name} is balancing study and work."


# 创建 WorkingStudent 类的一个实例, 名为 working_student1
# 传入参数 "Charlie" 作为学生姓名, 22 作为学生年龄, "S67890" 作为学生学号, "Intern" 作为工作职位
working_student1 = WorkingStudent("Charlie", 22, "S67890", "Intern")
# 调用 working_student1 实例从 Person 类(通过 Student 类继承)继承而来的 introduce 方法, 打印自我介绍信息
print(working_student1.introduce())
# 调用 working_student1 实例从 Student 类继承而来的 study 方法, 打印学习信息
print(working_student1.study())
# 调用 working_student1 实例从 Worker 类继承而来的 work 方法, 打印工作信息
print(working_student1.work())
# 调用 working_student1 实例自身的 balance 方法, 打印平衡学习与工作的信息
print(working_student1.balance())

Python#

PY4 自定义函数#

# def 函数名(参数列表):
#     # 函数体, 实现具体功能的代码
#     语句1
#     语句2
#     ...
#     return 返回值  # 可选, 用于返回函数的执行结果

def greet(name):
    """
    此函数用于向指定的人打招呼
    :param name: 要打招呼的人的名字
    :return: 打招呼的字符串
    """
    message = f"Hello, {name}!"
    return message


#########################
# 调用函数
#########################
result = greet("Alice")
print(result)
# greet 是函数名, name 是参数, 函数体里构建了一个打招呼的字符串并返回.
# 调用函数时传入 "Alice" 作为参数, 函数返回的结果存储在 result 变量中并打印.


#########################
# 位置参数
#########################
def add(a, b):
    return a + b

result = add(3, 5)
print(result)
# 这里 a 和 b 是位置参数, 调用 add 函数时, 3 对应 a, 5 对应 b. 


#########################
# 可变参数
#########################
# *args 用于接收任意数量的位置参数, **kwargs 用于接收任意数量的关键字参数. 
# *args 示例
def sum_numbers(*args):
    total = 0
    for num in args:
        total += num
    return total

result = sum_numbers(1, 2, 3, 4, 5)
print(result)

# **kwargs 示例
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=20, city="New York")


#########################
# 关键字参数
#########################
def describe_person(name, age):
    return f"{name} is {age} years old."

result = describe_person(age=25, name="Bob")
print(result)


#########################
# returen 值
#########################
def get_name_and_age():
    name = "Alice"
    age = 20
    return name, age

name, age = get_name_and_age()
print(name)
print(age)
# 函数返回多个值时, 实际上是返回一个元组. 

PY5 文本读写#

  • file_path:文件的路径, 可以是绝对路径或相对路径.
  • mode:文件的打开模式, 常见的模式如下:
    • 'r':只读模式, 用于读取文件内容(默认模式).
    • 'w':写入模式, 用于创建新文件或覆盖已有文件内容.
    • 'a':追加模式, 用于在文件末尾添加新内容.
    • 'x':创建模式, 用于创建新文件, 如果文件已存在则会抛出错误.
    • 'b':二进制模式, 与其他模式结合使用, 如 'rb' 表示以二进制只读模式打开文件.
    • '+':读写模式, 与其他模式结合使用, 如 'r+' 表示以读写模式打开文件.

使用 with 语句打开文件时, 文件会在 with 代码块结束时自动关闭. 如果不使用 with 语句, 需要手动调用 close() 方法关闭文件

# 使用 `open()` 函数打开文件
file_object = open(file_path, mode)


#########################
# 逐行读取
#########################
file_path = 'example.txt'
try:
    with open(file_path, 'r') as file:
        # 逐行读取文件内容
        for line in file:
            print(line.strip())  # strip() 方法用于去除每行末尾的换行符
except FileNotFoundError:
    print(f"文件 {file_path} 未找到. ")


#########################
# 一次性读取文件的全部内容
#########################
file_path = 'example.txt'
try:
    with open(file_path, 'r') as file:
        # 一次性读取文件的全部内容
        content = file.read()
        print(content)
except FileNotFoundError:
    print(f"文件 {file_path} 未找到. ")
# `read()` 方法会将文件的全部内容读取为一个字符串. 


#########################
# 读取指定数量的字符
#########################
file_path = 'example.txt'
try:
    with open(file_path, 'r') as file:
        # 读取前 10 个字符
        partial_content = file.read(10)
        print(partial_content)
except FileNotFoundError:
    print(f"文件 {file_path} 未找到. ")
# `read(n)` 方法可以读取指定数量 `n` 的字符. 


#########################
# 覆盖写入
#########################
file_path = 'new_file.txt'
content = "这是要写入文件的内容. "
try:
    with open(file_path, 'w') as file:
        # 将内容写入文件
        file.write(content)
    print(f"内容已成功写入文件 {file_path}. ")
except Exception as e:
    print(f"写入文件时发生错误: {e}")
# 使用 `'w'` 模式打开文件时, 如果文件已存在, 会先清空文件内容, 再写入新内容;如果文件不存在, 则会创建新文件. 


#########################
# 加写入
#########################
file_path = 'existing_file.txt'
new_content = "\n这是追加的内容. "
try:
    with open(file_path, 'a') as file:
        # 在文件末尾追加内容
        file.write(new_content)
    print(f"内容已成功追加到文件 {file_path}. ")
except FileNotFoundError:
    print(f"文件 {file_path} 未找到. ")
except Exception as e:
    print(f"追加内容时发生错误: {e}")
# 使用 `'a'` 模式打开文件时, 会在文件末尾添加新内容, 不会覆盖原有内容. 

PY6 捕捉异常#

#########################
# try-except-else 语句
#########################
# try:
#     # 可能会引发异常的代码块
#     语句1
#     语句2
#     ...
# except 异常类型:
#     # 当指定异常类型发生时执行的代码块
#     语句3
#     语句4
#     ...
# else:
#     # 当 try 代码块没有引发异常时执行的代码块
#     语句5
#     语句6
#     ...

try:
    num1 = 10
    num2 = 2
    result = num1 / num2
except ZeroDivisionError:
    print("除数不能为零!")
else:
    print(f"结果是: {result}")


#########################
# try-except-finally 语句
#########################
try:
    # 可能会引发异常的代码块
    语句1
    语句2
    ...
except 异常类型:
    # 当指定异常类型发生时执行的代码块
    语句3
    语句4
    ...
finally:
    # 无论是否发生异常都会执行的代码块
    语句5
    语句6
    ...

file = None
try:
    file = open("example.txt", "r")
    content = file.read()
    print(content)
except FileNotFoundError:
    print("文件未找到!")
finally:
    if file:
        file.close()  # 确保文件被关闭
Python and Pytorch Notes
https://blog.mcj.life/posts/250314python-and-pytorch-notesmd/
Author
CiMorn
Published at
2025-03-19