「BUAA Python Programming」Notes

Posted by saltyfishyjk on 2022-09-01
Words 2.7k and Reading Time 11 Minutes
Viewed Times

「BUAA Python Programming」Notes

Part 0 前言

尽管Python暑期课已经告一段落,但是和Python的旅程并没有迎来结束Python在做胶水方面实在太强大辣,因此,在这里开一篇新博客记录一些常用的笔记备忘。

Part 1 json处理

Python的json库提供了强大的json处理工具,在工作中十分常用。

读取json

json.load

从文件中读取json。

e.g.

1
2
3
4
file_dir = "./data.json" # 文件中存储了多个json
with open(file_dir, 'r', encoding='utf-8') as f: # 设置utf-8以正常读取中文字符
s = json.load(f) # 读取后,s为一个dict,每个元素是一个list
print("Yes")

Part 2 字符串处理

strip()

移除字符串头尾指定字符(通常为空格和换行符)

e.g.

1
str.strip([chars]) # chars : 移除字符串头尾指定的字符序列

replace()

以指定字符串替换字符串中指定子串,还可以用来实现删除字符串中全部指定子串。

e.g.

1
2
3
4
5
s = "Hello, BUAA!\nHello, TsingHua\n"
s1 = s.replace("Hello", "Wow") # 替换Hello为Wow
print("s1 : \n" + s1)
s2 = s.replace("Hello", "") # 删除全部Hello
print("s2 : \n" + s2)

output:

1
2
3
4
5
6
7
s1 : 
Wow, BUAA!
Wow, TsingHua

s2 :
, BUAA!
, TsingHua

Part 3 文件处理

python提供了强大的文件处理能力,掌握这些接口可以方便地造轮子(bushi)

判断文件存在与删除

1
2
3
4
5
import os
flag_path = os.path.exists(path) # 判断是否存在path路径下的文件,不区分文件和文件夹
flag_file = os.path.isfile(file_name) # 判断是否存在file_name文件
if flag_path:
os.remove(path) # 删除文件

文件读写操作

参考:python 写入文件 wb_一篇搞懂python文件读写操作(r/r+/rb/w/w+/wb/a/a+/ab)

Part 4 加密

在WEB开发等工作中,对于密码等涉密信息加密是常见的操作,python提供了简洁优雅的加密函数与接口。

md5加密

1
2
3
4
5
6
import hashlib
def md5_encode(s):
s_new = s
hl = hashlib.md5()
hl.update(s_new.encode("utf-8"))
return hl.hexdigest()

Part 5 Matplotlib绘图

在写论文时,经常会遇到需要绘制示意图的情况。对于科研绘图,网络上有各种建议,这里记录使用Python绘图的笔记。

相比于Visio、PowerPoint等绘图方式,Python绘图的突出优点包括图片由代码生成,具有高可复用性并且对手残友好,且其导出的svg矢量图也十分适合论文排版;对于有一定代码经验和基础的同学较为友好,语法较为简单;数学方面的图表支持较为强大,对于坐标等对精度有较高要求的绘制可以通过代码精确控制,避免手绘的随机性。

以下是一些质量较高的参考资料:

Matplotlib简介

matplotlib是2D绘图领域使用较为广泛的套件,性能强大,语法简单。更多介绍可以参考Matplotlib 教程-Runoob

导入相关包

1
2
3
import matplotlib.pyplot as plt
import numpy as np
import matplotlib

设置支持中文字体

matplotlib.rc(‘font’, family=’FangSong’) # 这里以仿宋字体为例,其他支持的字体可以自行搜索

更多字体设置,可以参考彻底解决Python里matplotlib不显示中文的问题-ZhiHu

设置坐标轴刻度显示范围

1
2
3
# 设置x,y坐标轴的刻度显示范围
plt.xlim(-120, 120)
plt.ylim(-120, 120)

获得figure和axes

figure可以类比“纸”;axes可以类比“区域”。更详细的介绍可以参考Matplotlib中的plt和ax都是啥?-ZhiHu

1
fig, ax = plt.subplots(figsize=(8, 8))

预览

1
plt.show()

保存图片

1
2
# 参数分别为图片保存名,dpi,格式
plt.savefig("img.svg", dpi=300, format="svg")

标记文字

满足需要在特定位置显示特定文字的需求

1
2
3
4
x1, y1 = 3, 4
text = r"$\alpha _1$"
ax.text(x1, y1, text)
# 三个参数分别为横坐标x,纵坐标y,显示文字text,并且text支持LaTeX公式

绘制线

这里的绘制线是基础行为,后续的直线绘制、圆绘制、曲线绘制等都基于此

1
2
3
4
5
# 绘制一条直线,x范围为[x1, x2],y范围为[y1, y2]
x1, y1 = 1, 2
x2, y2 = 4, 5
ax.plot([x1, x2], [y1, y2], color='black', linestyle='-', zorder=1, label=r'example line')
# 前两个参数为横纵坐标范围,是必选项;后面参数是可选项:color设置颜色,linestyle设置线的类型,zorder设置图层级别

由于上文中对plt和ax的介绍,我们后续会更多的采用ax来使代码更具扩展性

label参数支持 $\LaTeX$数学公式,可以使用$$编辑并显示行内公式

关于color的更多资料,可以参考Matplotlib 绘图线-Runoob

关于linestyle的更多资料,可以参考Matplotlib 绘图线-Runoob

关于zorder的更多资料,可以参考Zorder演示-Zorder中文网

绘制点

1
2
3
x3, y3 = 4, 2
ax.scatter(x3, y3, color='black', color='black', linewidth=4, zorder=20, marker='.', label='example point')
# 前两个参数为横纵坐标,是必选项;后面参数是可选项:color设置颜色,linewidth设置点的大小,zorder设置图层级别,marker设置点的类型,label设置图例中的文字说明

关于marker的更多资料,可以参考Matplotlib 绘图标记-Runoob

绘制箭头

1
2
3
4
x1, y1 = 2, 3
x2, y2 = 7, 6
ax.arrow(x1, y1, x2 - x1, y2 - y1, head_width=4, head_length=4, color='black')
# 前四个参数分别为起点x,起点y,deltax, deltay

关于arrow的更多资料,可以参考matplotlib.axes.Axes.arrow()函数

绘制圆

1
2
3
4
5
6
# 绘制圆
theta = np.linspace(0, 2 * np.pi, 200) # 设置角
circle_x = 100 * np.cos(theta) # 设置x
circle_y = 100 * np.sin(theta) # 设置y
fig, ax = plt.subplots(figsize=(8, 8))
ax.plot(circle_x, circle_y, color="black", linewidth=1, label=r'理想编队队形, $R=100m$', linestyle='--')# 以x和y绘图,本质上是用了x=r*cos(theta), y=r*sin(theta)

以圆弧绘制角符号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def draw_angle_with_points(x0, y0, x1, y1, x2, y2, r=10, dx=0, dy=0, text=None, show_text=False):
if y1 > y0:
x1_high, y1_high = x1, y1
x1_low, y1_low = x0, y0
else:
x1_high, y1_high = x0, y0
x1_low, y1_low = x1, y1
delta_y1 = y1_high - y1_low
delta_x1 = x1_high - x1_low
angle1 = np.arctan(delta_y1 / delta_x1)
if y2 > y0:
x2_high, y2_high = x2, y2
x2_low, y2_low = x0, y0
else:
x2_high, y2_high = x0, y0
x2_low, y2_low = x2, y2
delta_y2 = y2_high - y2_low
delta_x2 = x2_high - x2_low
angle2 = np.arctan(delta_y2 / delta_x2)
draw_angle(x=x0, y=y0, r=r, st=angle1, ed=angle2, dx=dx, dy=dy, text=text, show_text=show_text)

思路其实不复杂:给出圆心、弧的起始角度、弧的终点角度即可计算出圆

图层

有时候会遇到希望某个图形显示在其他图形上面或下面的需求,这时候可以利用库提供的图层属性,使用类似PR的逻辑处理图形之间的关系。

在上文中其实已经有所介绍,即使用zorder设置图层级别,更详细的使用方法可以参考Zorder演示 | Matplotlib 中文

图片比例

笔者在应用中发现,可能会遇到明明应该是长宽比1:2,但是看起来却很不像,这可能是因为绘图时自动根据布局进行调整。我的解决办法是在四边较远的地方都放置透明且图层级别最低的点,这样“撑”起了图的正确比例。

Part 6 Numpy科学计算

Numpy简介

近年来,Matlab的使用在内地越来越被限制,在具有敏感背景的高校更是如此。在这样的环境下,使用python是优秀的选择,BUAA《数学建模》课程与数学建模国赛都更推荐python。其中,Numpy库起到了重要的作用。

NumPy 通常与 SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用, 这种组合广泛用于替代 MatLab,是一个强大的科学计算环境,有助于我们通过 Python 学习数据科学或者机器学习。更多的介绍,可以参考NumPy 教程-Runoob

导入相关包

numpy社区推荐导入时使用:

1
import numpy as np

矩阵$\times$向量

@运算符用于矩阵和向量之间的乘法,其中第二位运算数会被转置。

e.g.:

1
2
3
x0 = np.array([2,1,1])
mat = np.array([[0.6, 0.1, 0.3], [0.1, 0.9, 0], [0.3, 0, 0.7]])
ans = mat @ x0

Part 7 处理Excel

参考:python实现——处理Excel表格(超详细)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 获取文件全名
excel_name = excel_file.name
# 获取文件名
mobile = os.path.splitext(excel_name)[0]
# 获取文件后缀
ext = os.path.splitext(excel_name)[1]
# 重定义文件名
excel_name = f'avatar-{mobile}{ext}'
# 从配置文件中加载excel保存路径
excel_path = os.path.join(EXCEL_UPLOAD, excel_name)
# 保存文件
with open(excel_path, 'wb') as fp:
fp.write(excel_file.read())
# 解析文件
os.chdir(EXCEL_UPLOAD)
workbook = openpyxl.load_workbook(excel_name)
sheet = workbook['Sheet1']
ret_json = []
n = 0
for i in sheet.iter_rows():
key = 'None'
value = 'None'
for j in i:
print('i = ' + str(i) + ' j = ' + str(j) + ' value = ' + str(j.value))
if key == 'None':
key = str(j.value)
else:
value = str(j.value)
ret_json.append({key: value})

Part 8 自定义类与排序

e.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 用于计算用户推荐商品排序
class UserGoodClass(object):
# id为编号,like为是否收藏,num为购物车中数量(没有加入购物车即为0)
def __init__(self, id, name, price, seller_id, maker, picture, description, date, shelf_life, like, num):
self.id = id
self.name = name
self.price = price
self.seller_id = seller_id
self.maker = maker
self.picture = picture
self.description = description
self.date = date
self.shelf_life = shelf_life
self.like = like
self.num = num
self.value = 5 * self.num + 3 * like
# print('name : ' + self.name + ' value : ' + str(self.value))
# 定义小于符号
def __lt__(self, other):
return self.value > other.value
1
2
3
4
5
6
# 生成该类的对象
goodObj = UserGoodClass(id=good_id, name=good.name, price=good.price, seller_id=good.seller_id, maker=good.maker, picture=good.picture, description=good.description, date=good.date, shelf_life=good.shelf_life, like=like, num=num)
# 扩充入列表
ret_list.append(goodObj)
# 排序
ret_list.sort()

Part 9 yield

参考:

yield 是 python 中的关键字,用于定义生成器函数。当一个函数中使用了 yield 函数时,它即被标记为生成器函数,而非普通的函数(这里笔者理解普通函数的行为是调用后即进入函数逐条语句执行)。生成器函数的执行不会像普通函数一样立即返回结果,而是在迭代器调用时逐步生成数据,并在调用 yield 时暂停执行并保存当前状态。yield 的优势在于处理大量数据,可以按需生成数据,无需一次性加载所有数据到内存中,在深度学习中比较常用。

e.g.

1
2
3
4
5
6
7
8
9
10
11
12
# input: batch大小、特征矩阵和标签向量
def data_iter(batch_size, features, labels):
num_examples = len(features) # 计算样本总数
indices = list(range(num_examples)) # 创建一个 0 到 num_examples - 1 的整数列表以表示样本的索引
# 这些样本是随机读取的,没有特定的顺序
random.shuffle(indices) # 随机打乱样本的索引列表
for i in range(0, num_examples, batch_size):
# 在索引列表 indices 中以 batch_size 为步长迭代遍历,每次迭代获取一个批次大小的样本
batch_indices = torch.tensor(
indices[i: min(i + batch_size, num_examples)])
# 使用 yield,将当前批次大小的特征数据和标签数据作为生成器的输出
yield features[batch_indices], labels[batch_indices]

This is copyright.