0%

1
2
3
4
5
6
7
8
9
10
11
12
import os, re
import random
import numpy as np
import pandas as pd
from datetime import date, datetime, timedelta

from pyecharts.charts import Kline, Line, Bar, Grid,Map,Pie,Timeline,Geo
from pyecharts.commons.utils import JsCode
from pyecharts import options as opts
from pyecharts.globals import CurrentConfig, NotebookType,ThemeType,ChartType, SymbolType
from pyecharts.faker import Faker

创建一个条形图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
outpath = r"C:\Users\xiaoyx\Desktop"

# 赋值
bar = Bar()

# 添加x轴的数据列表
bar.add_xaxis(Faker.choose())

# 添加y轴的数据标签及列表
bar.add_yaxis("商家A", Faker.values())

# 生成图表到notebook
bar.render_notebook()

# 生成图表成html
# bar.render(f"{outpath}\\bar_{date.today():%y%m%d}.html")

Awesome-pyecharts

链式调用

语法:

1
2
3
4
5
6
7
8
9
a = (Bar()
.add_xaxis(xaxis_data = )
.add_yaxis(serise_name = ,
y_axis = ,
stack = '',
color= '#eee',
category_gap = 1,
)
)

参数:

  1. .add_xaxis()
    • xaxis_data:指定 x 轴的数据
  2. .add_yaxis()
    • series_name: 指定系列名称
    • y_axis :指定 y 轴的数据
    • stack : 指定 y 轴名称
    • color : 指定柱子的颜色
    • category_gap:指定柱子的间距
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bar=(Bar().add_xaxis(xaxis_data=Faker.choose())
.add_yaxis(series_name= "商家A",
y_axis=Faker.values(),
stack ='时间',
color ='#0f0',
# category_gap=0,
)
.add_yaxis('商家B',
Faker.values(),
stack = '数量',
color = '#f0f',
category_gap = 50
)
.set_global_opts(title_opts = opts.TitleOpts(
title = '直方图的基本设置',
subtitle = '柱子颜色和间距',
)

)
)
bar.render_notebook()
Awesome-pyecharts

配置选项

pyecharts中包括图的标题,颜色主题等,都是通过选项Options配置的。

1
2
3
4
5
6
7
8
9
10
bar = (
# 使用了InitOpts来初始化图的主题
Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋","袜子"])
.add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
.add_yaxis("商家B",[10, 21, 30, 15, 80, 92])
.add_yaxis('商家C',[13,47,23,12,56,29])
.set_global_opts(
title_opts=opts.TitleOpts(title="设置主标题", subtitle="设置副标题")))
bar.render_notebook()
Awesome-pyecharts

InitOpts:初始化配置项

  1. 可以配置诸如图像宽度,高度,图表主题,背景颜色等
  2. 图表的宽和高,单位像素
  3. 图表的主题,常用的有:
    • 白色:.LIGHT
    • 黑色:.DARK
    • 暖色:.INFOGRAPHIC
    • 冷色: .SHINE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
c = (Bar(
init_opts=opts.InitOpts(
# 设置图表宽度
width="100%",
# 设置图表高度
height="600px",
# 设置图表主题
theme=ThemeType.LIGHT,
)
)
.add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.set_global_opts(
title_opts=opts.TitleOpts(title="初始化", subtitle="设置图表的宽高: 1000*600 和主题:ThemeType.LIGHT"))
)
c.render_notebook()

Awesome-pyecharts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
c = (Bar(
init_opts=opts.InitOpts(
# 设置图表宽度
width="100%",
# 设置图表高度
height="600px",
# 设置图表主题
theme=ThemeType.DARK,
)
)
.add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.set_global_opts(
title_opts=opts.TitleOpts(title="初始化", subtitle="图表宽高: 1000*600 主题:ThemeType.Dark"))
)

c.render_notebook()
Awesome-pyecharts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
c = (Bar(
init_opts=opts.InitOpts(
# 设置图表宽度
width="100%",
# 设置图表高度
height="600px",
# 设置图表主题
theme=ThemeType.INFOGRAPHIC,
)
)
.add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.set_global_opts(
title_opts=opts.TitleOpts(title="初始化", subtitle="图表宽高: 1000*600 主题:ThemeType.INFOGRAPHIC"))
)
c.render_notebook()




Awesome-pyecharts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
c = (Bar(
init_opts=opts.InitOpts(
# 设置图表宽度
width="100%",
# 设置图表高度
height="600px",
# 设置图表主题
theme=ThemeType.SHINE,
)
)
.add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.set_global_opts(
title_opts=opts.TitleOpts(title="初始化", subtitle="图表宽高: 1000*600 主题:ThemeType.SHINE"))
)
c.render_notebook()
Awesome-pyecharts

全局配置项

使用 options 配置项,在 pyecharts 中,一切皆 Options。

  1. 全局配置项可通过 set_global_opts 方法设置

提示框配置

  1. axis_pointer_type=str ; axis_pointer_type=”cross”
    • cross : 十字准星指示器
    • line : 直线
    • shadow: 阴影
    • nonw :无
  2. is_show:是否显示提示框组件,包括提示框浮层和 axisPointer
  3. trigger:
    • axis: 坐标轴触发
    • item: 项目触发
  4. trigger_on:提示框触发的条件,
    • mousemove: 鼠标移动时触发。
    • click: 鼠标点击时触发。
    • mousemove|click: 鼠标移动或点击时触发。
    • none:不在 ‘mousemove’ 或 ‘click’ 时触发
  5. background_color:提示框浮层的背景颜色。
  6. border_color:提示框浮层的边框颜色。
  7. border_width:提示框浮层的边框宽
  8. 提示框的文字样式设置:
    • color: 字体颜色
    • font_size: 字体尺寸大小
    • font_weight: 字体加粗
    • font_family: 字体
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
c = (Bar().add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.set_global_opts(tooltip_opts=opts.TooltipOpts(
axis_pointer_type="line",
# axis_pointer_type="cross",
# axis_pointer_type="shadow",
trigger= 'item',
# trigger= 'axis',
# trigger_on = 'click',
trigger_on = 'mousemove',
# trigger_on = 'none',
background_color="#000",
border_width=1,
border_color="#ccc",
textstyle_opts=opts.TextStyleOpts(
color="#fff",
font_size=14,
font_weight="normal",
font_family="微软雅黑")
),
title_opts=opts.TitleOpts(
title="图表提示框配置",
subtitle="提示框的触发 框的大小颜色 文字样式")
)
)

c.render_notebook()
Awesome-pyecharts

TitleOpts:标题配置项

语法:.set_global_opts(title_opts=opts.TitleOpts())
参数:

  1. title: 主标题

  2. subtitle: 副标题

  3. pos_left: 离容器左侧的距离

    • left/center/right:表示左对齐、居中、右对齐
    • 20: 表示距离20个像素
    • 20%:表示相对于图标宽度的20%
  4. pos_top:离容器上侧的距离

    • ‘top’, ‘middle’, ‘bottom’:靠上,居中,靠下
  5. pos_right:

  6. pos_bottom:

  7. padding: 内边距

    • 5:表示上下左右的内边距等于5
  8. item_gap: 主副标题之间的间距

  9. title_textstyle_opts=opts.TextStyleOpts()

    • color:
    • font_style:’normal’,’italic’,’oblique’
    • font_weight:’normal’,’bold’,’bolder’,’lighter’
    • font_family:
    • font_size:
  10. subtitle_textstyle_opts = opts.TextStyleOpts(…)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
c = Bar().add_xaxis(Faker.choose()
).add_yaxis("商家A", Faker.values()
).add_yaxis("商家B", Faker.values()
).add_yaxis("商家C", Faker.values()
).add_yaxis("商家D", Faker.values()
).set_global_opts(title_opts=opts.TitleOpts(
title="标题的配置", # 主标题
subtitle="标题、标题的定位、标题文字样式", # 副标题
pos_left="150px", #左定位 150像素 也可以是比例5%
pos_top="10px", #上定位
title_textstyle_opts=opts.TextStyleOpts(
color="#0ff",
font_size = 20,
font_style = 'oblique',
font_weight = 'bolder',
font_family = '楷体')
)
)
c.render_notebook()


Awesome-pyecharts

LegendOpts:图例配置项

语法:.set_global_opts(legend_opts=opts.LegendOpts())
参数:

  1. is_show : 是否显示图例组件 True / False
  2. type_ : 图例类型 plain 缺省,普通图例。scroll:可滚动的图例,当图例较多时使用
  3. selected_mode: 图例选择的模式
    • True:默认,开启图例点选
    • False:关闭
    • single:单选
    • multiple:多选
  4. pos_left 配置方法与标题栏的配置类似
  5. orient 图例列表的布局朝向
    • ‘horizontal’, ‘vertical’
  6. align:文本对齐方式 auto, left, right
  7. padding:文本的内边距
  8. item_gap:图例每项之间的间,隔横向布局时为水平间隔,纵向布局时为纵向间隔
  9. item_width:
  10. item_height:
  11. inactive_color = ‘#E6E61A’
    • 图例关闭时的颜色。默认是 #ccc
  12. textstyle_opts:与提示框的配置相同
  13. legend_icon:
    • ‘circle’, 圆
    • ‘rect’, 矩形
    • ‘roundRect’, 圆角矩形
    • ‘triangle’, 三角形
    • ‘diamond’, 钻石
    • ‘pin’, 饼
    • ‘arrow’, 箭头
    • ‘none’ 无
    • ‘image://url’设置为图片,其中 URL 为图片的链接
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
c = (Bar().add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.add_yaxis("商家C", Faker.values())
.add_yaxis("商家D", Faker.values())
.set_global_opts(
legend_opts=opts.LegendOpts(
type_='plain',
# selected_mode=True,
# selected_mode='single',
selected_mode='multiple',
# orient="vertical",
orient="horizontal",
item_gap=3,
item_width=25,
item_height=5,
pos_right='center',
legend_icon='roundRect' ),

title_opts=opts.TitleOpts(
title ="图例配置",
subtitle ="图例类型、横竖样式、图例列表的大小、间距、ICON")
)
)

c.render_notebook()
Awesome-pyecharts

DataZoomOpts:区域缩放配置项

图的底部的缩放配置项目。比如是否展示缩放,缩放过程中是否需要实时更新图等。
语法:.set_global_opts(datazoom_opts=[opts.DataZoomOpts(
参数:

  1. is_show :是否显示缩放组件
  2. type_ :组件类型,可选 “slider”, “inside
  3. range_start :数据窗口范围的起始百分比
  4. range_end :数据窗口范围的结束百分比
  5. orient :布局方式是横还是竖 ‘horizontal’, ‘vertical’
  6. xaxis_index:
  7. yaxis_index :
  8. is_zoom_lock:设置为 true 则锁定选择区域的大小,也就是说,只能平移,不能缩放9.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
c = (Bar().add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.add_yaxis("商家C", Faker.values())
.add_yaxis("商家D", Faker.values())
.set_global_opts(datazoom_opts=[opts.DataZoomOpts(
type_="inside",
range_start=0,
range_end=50),
opts.DataZoomOpts(
type_="slider",
xaxis_index=0,
is_show=True),
],
title_opts=opts.TitleOpts(
title="区域缩放配置",
subtitle="缩放条位置,初始范围")
)
)

c.render_notebook()
Awesome-pyecharts

ToolBoxFeatureOpts和ToolboxOpts:工具箱配置项

语法:.set_global_opts(title_opts=opts.TitleOpts( )
参数:

  1. is_show :是否显示工具箱
  2. orient :工具箱的布局
  3. pos_left:工具箱的定位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
c = (Bar().add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.add_yaxis("商家C", Faker.values())
.add_yaxis("商家D", Faker.values())
.add_yaxis("商家E", Faker.values())
.add_yaxis("商家F", Faker.values())
.set_global_opts(toolbox_opts=opts.ToolboxOpts(),
title_opts=opts.TitleOpts(title="工具箱的配置",
subtitle="工具箱的布局、定位")
)

)
c.render_notebook()
Awesome-pyecharts

系列配置-LabelOpts 标签配置项

属于系列配置选项
语法:.set_series_opts(label_opts=opts.LabelOpts())
参数:

  1. is_show=True 是否显示标签
  2. position 标签的位置 可选 ‘top’,’left’,’right’,’bottom’,’inside’,’insideLeft’,’insideRight’
  3. font_size 文字的字体大小
  4. color 文字的颜色
  5. font_style
  6. rotate = 90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
c = (Bar().add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.add_yaxis("商家C", Faker.values())
.add_yaxis("商家D", Faker.values())
.set_series_opts(label_opts=opts.LabelOpts(
is_show=True,
position='insideTop',
font_size=9,
color= '#fff',
rotate =0),)
.set_global_opts(title_opts=opts.TitleOpts(
title="系列配置-标签配置",
subtitle="标签显示位置、标签文字样式设定")
)
)


c.render_notebook()
Awesome-pyecharts

系列配置-MarkLineOpts标记配置

语法:

1
2
3
4
5
6
7
8
9
10
.set_series_opts(
MarkPoint_opts=opts.MarkPointOpts(
data=[
opts.MarkPointItem(name="自定义线",y = 44, ),
opts.MarkPointItem(type_="min"),
opts.MarkLineItem(type_="max"),
opts.MarkPointItem(type_="average")
]
)
)

参数:

  1. name:标注名称
  2. type_:标注类型 ‘min’ 最大值、’max’ 最大值 、’average’ 平均值
  3. value_index:指定在哪个维度上指定最大值最小值 ‘0’(xAxis, radiusAxis) 或 ‘1’ (yAxis, angleAxis),只有使用type_时有效
  4. value_dim:在使用 type 时有效,用于指定在哪个维度上指定最大值最小值。
  5. coord:标注的坐标。坐标格式视系列的坐标系而定,可以是直角坐标系上的 x, y
  6. value:标注值,可以不设
  7. symbol:标记的图形 ‘circle’, ‘rect’, ‘roundRect’, ‘triangle’, ‘diamond’, ‘pin’, ‘arrow’, ‘none’
  8. symbol_size:标记的大小
  9. itemstyle:标记点样式配置项,参考 `series_options.ItemStyleOpts
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
30
31
32
c = (Bar().add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.add_yaxis("商家C", Faker.values())
.add_yaxis("商家D", Faker.values())
.set_series_opts(markline_opts=opts.MarkLineOpts(
data=[
opts.MarkLineItem(
name = '最大值',
type_="max",
value_index =1,
value_dim = 1,
symbol='diamond',
coord = [2,5],
)

],
),
markpoint_opts=opts.MarkPointOpts(
data=[
opts.MarkPointItem(type_="max", name="x轴最大",value_index=1),
],
),
)
.set_global_opts(title_opts=opts.TitleOpts(
title="系列配置-标记配置",
subtitle="标签显示位置、标签文字样式设定")
)
)


c.render_notebook()
Awesome-pyecharts

实例配置

  1. 大小、主题
  2. 柱状图
  3. 工具箱
  4. 标题
  5. 图例
  6. 缩放
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
c = (Bar(init_opts=opts.InitOpts(
width="100%",
height="100%",
theme=ThemeType.INFOGRAPHIC))
.add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.add_yaxis("商家C", Faker.values())
.add_yaxis("商家D", Faker.values())
.add_yaxis("商家E", Faker.values())
.add_yaxis("商家F", Faker.values())
.set_global_opts(
toolbox_opts=opts.ToolboxOpts(),
title_opts=opts.TitleOpts(
title="Pychart练习",
subtitle="设置标题、图例、工具箱、区域缩放、标签、提示框",
pos_left="150px",
pos_top="10px"),
legend_opts=opts.LegendOpts(
type_="scroll",
selected_mode=True,
orient="horizontal",
item_gap=3,
item_width=25,
item_height=5,
pos_right="25%"),
datazoom_opts=[
opts.DataZoomOpts(type_="inside",range_start=0,range_end=100),
opts.DataZoomOpts(type_="slider",xaxis_index=0,is_show=True),
],
tooltip_opts=opts.TooltipOpts(
axis_pointer_type="line",
# axis_pointer_type="cross",
# axis_pointer_type="shadow",
trigger= 'item',
# trigger= 'axis',
# trigger_on = 'click',
trigger_on = 'mousemove',
# trigger_on = 'none',
background_color="#000",
border_width=1,
border_color="#ccc",
textstyle_opts=opts.TextStyleOpts(
color="#fff",
font_size=14,
font_weight="normal",
font_family="微软雅黑")
),
)
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
)

c.render_notebook()
Awesome-pyecharts

参数化设计实例

  1. 准备对四边形刀片的建模
    1. 共同点:四条边
  2. 建模步骤:

创建模型

Step1:绘制图形

绘制内接圆 —>绘制平行四边形 —-> 约束四条边相切于内接圆 —-> 标注尺寸

Step2:对称拉伸
Step3:倒圆角
Step4:拔模
Step5:投影文字

程序

完成参数的设置。详细参数如下:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
INPUT
NAME STRING
"输入刀片规格"
END INPUT

RELATIONS
SHAPE = EXTRACT(NAME,1,1)
BACK =EXTRACT(NAME,2,1)
LENGTH = EXTRACT(NAME,5,2)
THINK =EXTRACT(NAME,7,2)
ROUND = EXTRACT(NAME,9,2)
MIRROR = EXTRACT(NAME,2,1)

/*控制镜像特征是否显示
/* D16=内接圆直径,
/* D17 =菱形顶角 ,
/* D21=刀片厚度,
/*D20=刀尖圆角,
/* D21=刀片后角

/* 形状记号转换
IF SHAPE == "C"
D17=80
ENDIF
IF SHAPE == "D"
D17=55
ENDIF
IF SHAPE == "E"
D17=75
ENDIF
IF SHAPE == "F"
D17=50
ENDIF
IF SHAPE == "V"
D17=35
ENDIF
IF SHAPE == "S"
D17=90
ENDIF

/* 厚度记号转换
IF THINK == "02"
D15 = 2.38
ENDIF
IF THINK == "03"
D15 = 3.18
ENDIF
IF THINK == "04"
D15 = 4.76
ENDIF
IF THINK == "05"
D15 = 5.56
ENDIF
IF THINK == "06"
D15 = 6.35
ENDIF
IF THINK == "07"
D15 = 7.94
ENDIF
IF THINK == "09"
D15 = 9.52
ENDIF
IF THINK == "T2"
D15 = 2.78
ENDIF
IF THINK == "T3"
D15 = 3.97
ENDIF

/* 刀尖圆角记号转换
IF ROUND == "02"
D20 = 0.2
ENDIF
IF ROUND == "04"
D20 = 0.4
ENDIF
IF ROUND == "08"
D20 = 0.8
ENDIF
IF ROUND == "12"
D20 = 1.2
ENDIF
IF ROUND == "16"
D20 = 1.6
ENDIF

/* 后角记号转换
IF BACK == "N"
D21=0
ENDIF
IF BACK == "A"
D21=3
ENDIF
IF BACK == "B"
D21=5
ENDIF
IF BACK == "C"
D21=7
ENDIF
IF BACK == "D"
D21=15
ENDIF
IF BACK == "E"
D21=20
ENDIF
IF BACK == "P"
D21=11
ENDIF

/* 刃长记号转换成内接圆直径 D16
IF SHAPE == "C"
IF LENGTH == "06"
D16= 6.35
ENDIF
IF LENGTH == "08"
D16=7.94
ENDIF
IF LENGTH == "09"
D16=9.525
ENDIF
IF LENGTH == "12"
D16=12.7
ENDIF
IF LENGTH == "16"
D16=15.975
ENDIF
IF LENGTH == "19"
D16=19.3
ENDIF
IF LENGTH == "25"
D16=25.4
ENDIF
ENDIF

IF SHAPE == "D"
IF LENGTH == "07"
D16= 6.35
ENDIF
IF LENGTH == "09"
D16=7.94
ENDIF
IF LENGTH == "11"
D16=9.525
ENDIF
IF LENGTH == "15"
D16=12.7
ENDIF
IF LENGTH == "16"
D16=15.975
ENDIF
IF LENGTH == "19"
D16=19.4
ENDIF
ENDIF

IF SHAPE == "V"
IF LENGTH == "08"
D16=4.76
ENDIF
IF LENGTH == "09"
D16=5.56
ENDIF
IF LENGTH == "11"
D16=6.35
ENDIF
IF LENGTH == "16"
D16=9.525
ENDIF
IF LENGTH == "22"
D16=19.3
ENDIF
IF LENGTH == "25"
D16=12.7
ENDIF
ENDIF

IF SHAPE == "S"
IF LENGTH == "06"
D16= 6.35
ENDIF
IF LENGTH == "07"
D16=7.94
ENDIF
IF LENGTH == "09"
D16=9.525
ENDIF
IF LENGTH == "12"
D16=12.7
ENDIF
IF LENGTH == "15"
D16=15.875
ENDIF
IF LENGTH == "19"
D16=19.05
ENDIF
IF LENGTH == "25"
D16=25.4
IF LENGTH == "31"
D16=31.75
ENDIF
ENDIF
IF LENGTH == "25"
D16=25.4
ENDIF
ENDIF
END RELATIONS

随时更新设计

Ctrl+G 更新模型

勾选 NAME

输入刀片规格

得到新的模型

从上往下贴图

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import os,re
from datetime import date, time, timedelta
import qrcode as qr
import yagmail as yag
from PIL import Image, ImageDraw, ImageFont


def remove_old():
"""
删除文件夹下的旧文件。webp格式的旧文件(二维码图片)
"""
fold = r"D:\onedrive\Code\Note\Python_project\WDHAC_QR"
files = [i for i in os.listdir(fold) if re.search(r"webp$", i)]
for file in files:
os.remove(f"{fold}\\{file}")

def creat_icon(text):
"""
生成在二维码图片中间添加的文字图片
"""
icon = Image.new("RGBA", (50, 35), (0, 0, 0, 120))
draw = ImageDraw.Draw(icon)
font = ImageFont.truetype(font="msyh.ttc", size=28)
draw.text((0, 0), text, fill=(255, 255, 255, 255), font=font)
return icon

def creat_ewm(name, num, rq):
"""
批量生成二维码
参数: name(str) 物料名称
num(int) 数量
rq(str) 日期231001 23年10月1日
"""
# 设置二维码内容
for i in range(1, int(num) + 1):
if num > 99:
sq = str(i).rjust(3, "0")
data = name + rq + sq
else:
sq = str(i).rjust(2, "0")
data = name + rq + sq
# 指定二维码的格式:box_size:表示每个方格带像素点个数,border:表示边距占位几个方格
qr = qrcode.QRCode(version=2,
error_correction=qrcode.constants.ERROR_CORRECT_H,
box_size=6,
border=2)
# 添加二维吗的内容资料
qr.add_data(data)
qr.make(fit=True)
# 将二维码生成图片并保存,文件名为日期+序列号
img = qr.make_image()
img = img.convert("RGBA")
# # 获取生成的二维码图片尺寸:
# icon_w, icon_h = img.size
# icon = creat_icon(sq)
# img.paste(icon, (100, 100), icon)
img.save(f"{rq}_{sq}.webp")


def creat_tag(name, rq):
"""
生成可以打印的二维码标签
参数: name(str) 物料名称
rq(str) 日期231001 23年10月1日
"""
# ----------列出生成的二维码图片的明细------------
files = [x for x in os.listdir() if re.search("^\d{6}_\d+", x)]
# -----查看生成的二维码的实际大小
img = Image.open(files[0])
w1, h1 = img.size

# -----创建一张标签纸大小的空白照片,每英寸300像素的分辨率,标签纸尺寸 80 *270 mm
w = int(80 / 25.4 * 300)
h = int(270 / 25.4 * 300)
pg = Image.new("RGBA", (w, h))

# -----设置页边距,每行并排2张二维码-----
a = int((40 / 25.4 * 300 - w1) / 2)
b = int((27 / 25.4 * 300 - h1) / 2)

#-----粘贴二维码图片到标签纸上
x, y= a, b
page = 1
for i in files:
img = Image.open(i)
if w - x - w1 >= 0:
pg.paste(img, (x, y))
x += w1 + a*2
else:
x = a
y += h1 + b *2
if h - y - h1 > 0:
# print(page, i, x, y)
pg.paste(img, (x, y))
x += w1 + a *2
else:
pg.save("{}.webp".format(name + rq + "_" + str(page)))
pg = Image.new("RGBA", (w, h))
x, y= a, b
page += 1
pg.paste(img, (x, y))
x += w1 + a *2
img.close()
pg.save("{}.webp".format(name + rq + "_" + str(page)))
for x in files:
os.remove(x)

def send_email(name, num, rq):
"""
自动发送邮件。
参数: name(str): 物料名称
num(int): 数量
rq(str) 日期231001 23年10月1日
"""
# ----------邮件基本设置---------
mail_host = "smtp.163.com" # SMTP服务器
port = int(25) # 端口号
sender = "yxhsiao@163.com" # 发件人邮箱
pwd = "MGWMGHFEVMYQLFVK" # 授权密码
receivers = ["zgjxjjwyx@126.com"] # 收件人邮箱,可以为多个收件人
ccs = ["1796685160@qq.com"] # 邮件抄送
bccs = ["yxhsiao@hotmail.com"] # 邮件密送
title = f"{date.today()} 发货:{name} 数量:{num} Pcs" # 邮件主题
# 邮件内容
html = "<p style='font: normal 150 13pt 黑体;color:#f104b7;text-align:center'><p><strong><span>二维码制作已完成下载即可!</span></strong></p><ol start='' ><li><p><span>标签打印机页面模板设置:</span></p><ul><li><span>纸张大小:80 x 270 </span></li><li><span>布局:上边距 2mm</span></li></ul></li><li><p><span>二维码图片大小设置:</span></p><ul><li><p><span>伸展到方框范围</span></p><ul><li><span>保持纵横比</span></li><li><span>尺寸:80 x 270</span></li></ul></li></ul></li><li><p><span>并设置图片左右上下居中</span></p></li></ol><p>&nbsp;</p>"
# 邮件附件
attachs = [i for i in os.listdir() if re.match(r"{name}{rq}", i)]
# 发送邮件
try:
yag = yagmail.SMTP(user=sender, password=pwd, host=mail_host)
yag.send(
to=receivers,
# cc=ccs,
# bcc=bccs,
subject=title,
contents=html,
attachments=attachs)
print("Email send success")
except:
print("Email send fail")
if __name__ == '__main__':
name = input("输入编码! ")
num = int(input("输入要打印的多少张二维码! "))
print(type(num))
rq = f"{date.today():%y%m%d}"
remove_old()
creat_ewm(name,num,rq)
creat_tag(name,rq)
# send_email(name,num,rq)

从下往上贴图

  1. 符合打印机的习惯
  2. 不足一页时,可以省纸张
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import os,re
from datetime import date, time, timedelta
import qrcode
import yagmail
from PIL import Image, ImageDraw, ImageFont


def remove_old():
"""
删除文件夹下的旧文件。webp格式的旧文件(二维码图片)
"""
fold = r"D:\onedrive\Code\Note\Python_project\WDHAC_QR"
files = [i for i in os.listdir(fold) if re.search(r"webp$", i)]
for file in files:
os.remove(f"{fold}\\{file}")

def creat_icon(text):
"""
生成在二维码图片中间添加的文字图片
"""
icon = Image.new("RGBA", (50, 35), (0, 0, 0, 120))
draw = ImageDraw.Draw(icon)
font = ImageFont.truetype(font="msyh.ttc", size=28)
draw.text((0, 0), text, fill=(255, 255, 255, 255), font=font)
return icon

def creat_ewm(name, num, rq):
"""
批量生成二维码
参数: name(str) 物料名称
num(int) 数量
rq(str) 日期231001 23年10月1日
"""
# 设置二维码内容
for i in range(1, int(num) + 1):
if num > 99:
sq = str(i).rjust(3, "0")
data = name + rq + sq
else:
sq = str(i).rjust(2, "0")
data = name + rq + sq
# 指定二维码的格式:box_size:表示每个方格带像素点个数,border:表示边距占位几个方格
qr = qrcode.QRCode(version=2,
error_correction=qrcode.constants.ERROR_CORRECT_H,
box_size=6,
border=2)
# 添加二维吗的内容资料
qr.add_data(data)
qr.make(fit=True)
# 将二维码生成图片并保存,文件名为日期+序列号
img = qr.make_image()
img = img.convert("RGBA")
# # 获取生成的二维码图片尺寸:
# icon_w, icon_h = img.size
# icon = creat_icon(sq)
# img.paste(icon, (100, 100), icon)
img.save(f"{rq}_{sq}.webp")


def creat_tag(name, rq):
"""
生成可以打印的二维码标签.倒序打印,省纸
参数: name(str) 物料名称
rq(str) 日期231001 23年10月1日
"""
# ----------列出生成的二维码图片的明细------------
files = [x for x in os.listdir() if re.search("^\d{6}_\d+", x)]
# -----查看生成的二维码的实际大小
img = Image.open(files[0])
w1, h1 = img.size

# -----创建一张标签纸大小的空白照片,每英寸300像素的分辨率,标签纸尺寸 80 *270 mm
w = int(80 / 25.4 * 300)
h = int(270 / 25.4 * 300)
pg = Image.new("RGBA", (w, h))

# -----设置页边距,每行并排2张二维码-----
a = int((40 / 25.4 * 300 - w1) / 2)
b = int((27 / 25.4 * 300 - h1) / 2)

#-----粘贴二维码图片到标签纸上
x, y= a, h-b-h1
page = 1
for i in files:
img = Image.open(i)
if w - x - w1 >= 0:
# print(page, i, x, y)
pg.paste(img, (x, y))
x += w1 + a*2
else:
x = a
y -= h1 + b *2
if h + y - h1 > 0:
# print(page, i, x, y)
pg.paste(img, (x, y))
x += w1 + a *2
else:
pg.save("{}.webp".format(name + rq + "_" + str(page)))
pg = Image.new("RGBA", (w, h))
x, y= a, b
page += 1
# print(page, i, x, y)
pg.paste(img, (x, y))
x += w1 + a *2
img.close()
pg.save("{}.webp".format(name + rq + "_" + str(page)))
for x in files:
os.remove(x)

def send_email(name, num, rq):
"""
自动发送邮件。
参数: name(str): 物料名称
num(int): 数量
rq(str) 日期231001 23年10月1日
"""
# ----------邮件基本设置---------
mail_host = "smtp.163.com" # SMTP服务器
port = int(25) # 端口号
sender = "yxhsiao@163.com" # 发件人邮箱
pwd = "MGWMGHFEVMYQLFVK" # 授权密码
receivers = ["zgjxjjwyx@126.com"] # 收件人邮箱,可以为多个收件人
ccs = ["1796685160@qq.com"] # 邮件抄送
bccs = ["yxhsiao@hotmail.com"] # 邮件密送
title = f"{date.today()} 发货:{name} 数量:{num} Pcs" # 邮件主题
# 邮件内容
html = "<p style='font: normal 150 13pt 黑体;color:#f104b7;text-align:center'><p><strong><span>二维码制作已完成下载即可!</span></strong></p><ol start='' ><li><p><span>标签打印机页面模板设置:</span></p><ul><li><span>纸张大小:80 x 270 </span></li><li><span>布局:上边距 2mm</span></li></ul></li><li><p><span>二维码图片大小设置:</span></p><ul><li><p><span>伸展到方框范围</span></p><ul><li><span>保持纵横比</span></li><li><span>尺寸:80 x 270</span></li></ul></li></ul></li><li><p><span>并设置图片左右上下居中</span></p></li></ol><p>&nbsp;</p>"
# 邮件附件
attachs = [i for i in os.listdir() if re.match(r"{name}{rq}", i)]
# 发送邮件
try:
yag = yagmail.SMTP(user=sender, password=pwd, host=mail_host)
yag.send(
to=receivers,
# cc=ccs,
# bcc=bccs,
subject=title,
contents=html,
attachments=attachs)
print("Email send success")
except:
print("Email send fail")
if __name__ == '__main__':
name = "WDH5NC00701"
num = 6
print(type(num))
rq = f"{date.today():%y%m%d}"
remove_old()
creat_ewm(name,num,rq)
creat_tag(name,rq)
# send_email(name,num,rq)

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# -*- encoding: utf-8 -*-

import pandas as pd
import numpy as np
import os, re
import shutil

def get_file_base_name(name):
"""
去掉文件后缀名
参数:name(str)
原始文件名
"""
while re.search(r"(\.[a-z]+$)|(\.[0-9]+$)",name):
name = os.path.splitext(name)[0]
return os.path.splitext(name)[0]

def purge(fd):
"""
删除Creo软件的旧档文件
删除多重版本的文件(多重后缀名的文件),保留最新版本文件。并去除版本号后缀
参数:fd(str)
文件夹名称
"""
# 列出指定文件夹下的所有文件,包含子文件夹下的文件。得到一个完整文件名的列表
ls1 = [os.path.join(p, i) for p, d, f in os.walk(fd) for i in f]
# 去掉后缀名后的列表
ls2 = [get_file_base_name(i) for i in ls1]
# 列出有多重版本号的文件
ls3 = set([i for i in ls2 if ls2.count(i)>1])
# 删除低版本号的文件保留高版本
for i in ls3:
ls =[x for x in ls1 if i in x ]
if len(ls)>1:
print(i,sorted(ls))
for j in sorted(ls)[:-1]:
os.remove(j)
# 列出多版本的文件
ls4 = [os.path.join(p, i) for p, d, f in os.walk(fd) for i in f if re.search(r'\.[a-z]+\.\d+$', i)]
# 重命名,去除版本号
if len(ls4)>1:
for i in ls4:
name = os.path.splitext(i)[0]
shutil.move(i, name)

if __name__ == "main":
fd = "D:\3D"
purge(fd)

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

import os, re
from PIL import Image


def change_to_webp():
"""
将 source\_posts目录下的所有图片格式(webp/webp)转换成webp。
并将对应的md文件中插入图片的语句相应的更改成webp.如:<img src="./1.webp" /> ==>>> <img src="./1.webp" />
"""
fold = r"D:\BLOG\yxhsiao\source\_posts"
imgs = [os.path.join(p,j) for p,d,f in os.walk(fold) for j in f if re.search('\.webp$|\.webp$',j)]
for img in imgs:
im = Image.open(img).convert('RGB')
im.save(re.sub('webp|webp','webp',img))
os.remove(img)

files = [os.path.join(fold, i) for i in os.listdir(fold) if re.search('\.md$', i)]
for file in files:
with open(file, 'r', encoding='utf-8') as f,open(f'{file}.bak','w',encoding='utf-8') as newfile:
for line in f.readlines():
newfile.write(re.sub('webp|webp','webp',line))
os.remove(file)
os.rename(f'{file}.bak',file)


if __name__ == "__main__":
change_to_webp()

1
2
3
4
5
6
7
import os,re,random

a = random.randint(1,3)
f"随机产生的变量 a = {a}"

"a = 1" if a <2 else ( "a = 3" if a >2 else "a = 2" )

Output:
‘随机产生的变量 a = 1’

'a = 1'

Table of Contents

OS模块

  • 该模块提供了一些方便使用操作系统相关功能的函数。
  • 想读写一个文件,open(),
  • 操作路径, os.path
1
2
import os
import re

os.name

  • 该属性宽泛地指明了当前 Python 运行所在的环境,实际上是导入的操作系统相关模块的名称。这个名称也决定了模块中哪些功能是可用的,哪些是没有相应实现的。
  • 目前有效名称为以下三个:posix,nt,java。
1
os.name

Output:
‘nt’

os.sep

  • 主要用于系统路径的分隔符:
  • Windows系统通过是 \,Linux类系统如Ubuntu的分隔符是 /
1
os.sep

Output:

'\\'

os.path.dirname(ph)

  1. 语法:os.path.dirname(path)
  2. 功能:去掉文件名,返回目录
1
2
os.path.dirname(r'd:\software')

Output:
‘d:\‘

os.path.basename(ph)

  1. 语法:os.path.basename(path)
  2. 功能:返回path最后的文件名
1
2
os.path.basename(r'd:\software')

Output:
‘software’

os.pardir

  1. 语法
  2. 参数:无。
  3. 返回值:返回当前目录的父目录(上一级目录),默认值为 ..
1
2
3
4
os.pardir
os.getcwd()
os.path.abspath(os.path.join(os.getcwd(), os.pardir))

Output:
‘..’

Output:

'd:\\'

Output:
‘d:\‘

os.environ

  • os.environ属性可以返回环境相关的信息,主要是各类环境变量。返回值是一个映射(类似字典类型),具体的值为第一次导入os模块时的快照;其中的各个键值对,键是环境变量名,值则是环境变量对应的值。在第一次导入os模块之后,除非直接修改os.environ的值,否则该属性的值不再发生变化。
1
2
3
os.environ['HOMEPATH']

os.environ

Output:
‘\Users\xiaoyx’

Output:
environ{‘ALLUSERSPROFILE’: ‘C:\ProgramData’,
‘APPDATA’: ‘C:\Users\xiaoyx\AppData\Roaming’,
‘APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL’: ‘1’,
‘CHOCOLATEYINSTALL’: ‘C:\ProgramData\chocolatey’,
‘CHOCOLATEYLASTPATHUPDATE’: ‘133302881561848781’,
‘CHROME_CRASHPAD_PIPE_NAME’: ‘\\.\pipe\crashpad_26876_GMWMILBKGJTUSXKS’,
‘COMMONPROGRAMFILES’: ‘C:\Program Files\Common Files’,
‘COMMONPROGRAMFILES(X86)’: ‘C:\Program Files (x86)\Common Files’,
‘COMMONPROGRAMW6432’: ‘C:\Program Files\Common Files’,

os.getcwd()

  • 返回当前工作目录
1
os.getcwd()

Output:
‘d:\‘

os.chdir()

  • “chdir”其实是“change the directory”的简写,因此 os.chdir()的用处实际上是切换当前工作路径为指定路径。其中“指定路径”需要作为参数传入函数 os.chdir(),该参数既可以是文本或字节型字符串,也可以是一个文件描述符,还可以是一个广义的类路径(path-like)对象。若指定路径不存在,则会抛出FileNotFoundError异常。
1
2
os.chdir('d:\\')
os.getcwd()

Output:
Output:
‘d:\‘

os.getlogin()

  • 返回当前系统的实际登录名
1
os.getlogin()

Output:
‘xiaoyx’

os.walk(ph)

  • 这个函数需要传入一个路径作为top参数,函数的作用是在以top为根节点的目录树中游走,对树中的每个目录生成一个由(dirpath, dirnames, filenames)三项组成的三元组。
  • os.walk(top, topdown=True, onerror=None, followlinks=False)
  • 得到的是一个生成器
    • 第一层:目录路径
    • 第二层:目录名
    • 第三层:目录下的文件名
1
2
# 得到的是一个生成器
os.walk(".\\")

Output:
<generator object _walk at 0x0000017805566FF0>

1
2
3
4
5
6
7
8
9
10
11
12
13
ph = "D:\\BLOG\\yxhsiao\\themes\\next\\docs"

# 用for循环
for path, dirs, files in os.walk(ph):
for name in files:
print(os.path.join(path, name))

# 列表推导式:
[
os.path.join(path, file) for path, dir, files in os.walk(ph)
for file in files if re.search(r'\.\w+$', file)
]

Output:
D:\BLOG\yxhsiao\themes\next\docs\AGPL3.md
D:\BLOG\yxhsiao\themes\next\docs\AUTHORS.md
D:\BLOG\yxhsiao\themes\next\docs\LICENSE.txt
D:\BLOG\yxhsiao\themes\next\docs\ru\README.md
D:\BLOG\yxhsiao\themes\next\docs\zh-CN\CODE_OF_CONDUCT.md
D:\BLOG\yxhsiao\themes\next\docs\zh-CN\CONTRIBUTING.md
D:\BLOG\yxhsiao\themes\next\docs\zh-CN\README.md

Output:

['D:\\BLOG\\yxhsiao\\themes\\next\\docs\\AGPL3.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\AUTHORS.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\LICENSE.txt',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\ru\\README.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\zh-CN\\CODE_OF_CONDUCT.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\zh-CN\\CONTRIBUTING.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\zh-CN\\README.md']
1
2
3
4
5
6
7
8
9
10
ph = "D:\\BLOG\\yxhsiao\\themes\\next\\docs"
# 获取所有目录
[ph for ph, dir, files in os.walk(ph)]

# 获取子目录
[os.path.join(ph,x) for ph, dir, files in os.walk(ph) for x in dir]

# 获取所有文件
[os.path.join(ph, file) for ph, dir, files in os.walk(ph) for file in files]

Output:
[‘D:\BLOG\yxhsiao\themes\next\docs’,
‘D:\BLOG\yxhsiao\themes\next\docs\ru’,
‘D:\BLOG\yxhsiao\themes\next\docs\zh-CN’]

Output:

['D:\\BLOG\\yxhsiao\\themes\\next\\docs\\ru',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\zh-CN']

Output:

['D:\\BLOG\\yxhsiao\\themes\\next\\docs\\AGPL3.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\AUTHORS.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\LICENSE.txt',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\ru\\README.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\zh-CN\\CODE_OF_CONDUCT.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\zh-CN\\CONTRIBUTING.md',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\zh-CN\\README.md']
1
2
3
4
5
6
7
8
9
10
11
# 既然生成器的结果是一个二维列表,那么就可以用list[0],list[1],list[2]分别获取其路径、目录名、文件
# list[0]:路径
# list[1]:目录名列表
# list[2]:文件列表

[i[0] for i in os.walk(ph)]
[i[1] for i in os.walk(ph)]
[i[2] for i in os.walk(ph)]

[os.path.join(i[0],x) for i in os.walk(ph) for x in i[2]]

Output:

['D:\\BLOG\\yxhsiao\\themes\\next\\docs',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\ru',
 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\zh-CN']

Output:

[['ru', 'zh-CN'], [], []]

Output:
[[‘AGPL3.md’, ‘AUTHORS.md’, ‘LICENSE.txt’],
[‘README.md’],
[‘CODE_OF_CONDUCT.md’, ‘CONTRIBUTING.md’, ‘README.md’]]

Output:
[‘D:\BLOG\yxhsiao\themes\next\docs\AGPL3.md’,
‘D:\BLOG\yxhsiao\themes\next\docs\AUTHORS.md’,
‘D:\BLOG\yxhsiao\themes\next\docs\LICENSE.txt’,
‘D:\BLOG\yxhsiao\themes\next\docs\ru\README.md’,
‘D:\BLOG\yxhsiao\themes\next\docs\zh-CN\CODE_OF_CONDUCT.md’,
‘D:\BLOG\yxhsiao\themes\next\docs\zh-CN\CONTRIBUTING.md’,
‘D:\BLOG\yxhsiao\themes\next\docs\zh-CN\README.md’]

os.scandir(ph)

  1. 返回path目录树中对应的os.DirEntry对象的迭代器(文件夹或文件),
  2. 不包含子文件夹里的文件夹和文件,
  3. 运行效率比os.walk高,Python官方推荐使用os.scandir来遍历目录树。
1
2
3
4
5
6
7
8
9
10
def find_dir(ph):
return [i.path for i in os.scandir(ph) if i.is_dir()]


def find_file(ph):
return [i.path for i in os.scandir(ph) if i.is_file()]


find_dir(ph)
find_file(ph)

Output:
[‘D:\BLOG\yxhsiao\themes\next\docs\ru’,
‘D:\BLOG\yxhsiao\themes\next\docs\zh-CN’]
Output:
[‘D:\BLOG\yxhsiao\themes\next\docs\AGPL3.md’,
‘D:\BLOG\yxhsiao\themes\next\docs\AUTHORS.md’,
‘D:\BLOG\yxhsiao\themes\next\docs\LICENSE.txt’]

os.listdir()

  • 列出(当前)目录下的全部路径(及文件)。
  • 该函数存在一个参数,用以指定要列出子目录的路径,默认为“.”,即“当前路径”。
  • 函数返回值是一个列表,其中各元素均为字符串,分别是各路径名和文件名。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 不指定路径的情况下默认当前目录
ph = r"D:\BLOG\yxhsiao\themes\next\docs"


def find_dir(ph):
return [i for i in os.listdir(ph) if re.search(r'\.\w+$', i) == None]


def find_file(ph):
return [i for i in os.listdir(ph) if re.search(r'\.\w+$', i)]


find_dir(ph)
find_file(ph)

Output:

['ru', 'zh-CN']

['AGPL3.md', 'AUTHORS.md', 'LICENSE.txt']

os.mkdir()

  • 新建一个目录。需要传入一个类路径参数用以指定新建路径的位置和名称,
  • 如果指定路径已存在,则会抛出FileExistsError异常。
  • 该函数只能在已有的路径下新建一级路径,新建多级路径会抛出FileNotFoundError异常。
  • 需要新建多级路径的场景下,使用 os.makedirs()来完成任务。函数 os.makedirs()执行的是递归创建,若有必要,会分别新建指定路径经过的中间路径,直到最后创建出末端的“叶子路径”。
1
2
3
4
5
6
7
dir = 'D:\\OneDrive\\Code\\Note\\python_module'
[i for i in os.listdir(dir)]

newdir = os.path.join(dir, 'test_makedir')

os.rmdir(newdir) if os.path.exists(newdir) else os.mkdir(newdir)
[i for i in os.listdir(dir)]

Output:
[‘.ipynb_checkpoints’,
‘Datetime’,
‘Numpy’,
‘Openpyxl_处理Excel’,
‘Os’,
‘Pandas’,
‘Pillow’,
‘pychart’,
‘Random’,
‘Regex’,
‘Sys’,
‘xlwings’,
‘Yagmail’]

Output:
[‘.ipynb_checkpoints’,
‘Datetime’,
‘Numpy’,
‘Openpyxl_处理Excel’,
‘Os’,
‘Pandas’,
‘Pillow’,
‘pychart’,
‘Random’,
‘Regex’,
‘Sys’,
‘test_makedir’,
‘xlwings’,
‘Yagmail’]

os.makedirs()

  • 同时创建多级目录

os.remove()

  • 用于删除文件。
  • 如果指定路径是目录而非文件的话,就会抛出IsADirectoryError异常。删除目录应该使用 os.rmdir()函数。

os.rmdir()

  • 删除单级目录

os.removedirs()

  • 删除多级目录

os.rename()os.renames()

  • 该函数的作用是将文件或路径重命名
  • os.rename(src, dst),即将src指向的文件或路径重命名为dst指定的名称。
  • 注意,如果指定的目标路径在其他目录下,该函数还可实现文件或路径的“剪切并粘贴”功能。但无论直接原地重命名还是“剪切粘贴”,中间路径都必须要存在,否则就会抛出FileNotFoundError异常。如果目标路径已存在,Windows 下会抛出FileExistsError异常;Linux 下,如果目标路径为空且用户权限允许,则会静默覆盖原路径,否则抛出OSError异常,
  • 和上两个函数一样,该函数也有对应的递归版本 os.renames(),能够创建缺失的中间路径。
  • 注意,这两种情况下,如果函数执行成功,都会调用 os.removedir()函数来递归删除源路径的最下级目录。

os.path

  • 其实这个模块是os模块根据系统类型从另一个模块导入的,并非直接由os模块实现,比如 os.name值为nt,则在os模块中执行 import ntpath as path;如果 os.name值为posix,则导入posixpath。
  • 使用该模块要注意一个很重要的特性:os.path中的函数基本上是纯粹的字符串操作。换句话说,传入该模块函数的参数甚至不需要是一个有效路径,该模块也不会试图访问这个路径,而仅仅是按照“路径”的通用格式对字符串进行处理。
  • 更进一步地说,os.path模块的功能我们都可以自己使用字符串操作手动实现,该模块的作用是让我们在实现相同功能的时候不必考虑具体的系统,尤其是不需要过多关注文件系统分隔符的问题。
1
os.path

Output:
<module ‘ntpath’ from ‘c:\Users\xiaoyx\AppData\Local\Programs\Python\Python310\lib\ntpath.py’>

os.path.join()

  • 可以将多个传入路径组合为一个路径。实际上是将传入的几个字符串用系统的分隔符连接起来,组合成一个新的字符串,所以一般的用法是将第一个参数作为父目录,之后每一个参数即使下一级目录,从而组合成一个新的符合逻辑的路径。
  • 但如果传入路径中存在一个“绝对路径”格式的字符串,且这个字符串不是函数的第一个参数,那么其他在这个参数之前的所有参数都会被丢弃,余下的参数再进行组合。更准确地说,只有最后一个“绝对路径”及其之后的参数才会体现在返回结果中。
1
2
3
4
5
6
7
p1 = 'home'
p2 = 'fm'
p3 = 'note'

# 按照传入参数的顺序连接,并且用系统分隔符隔开
os.path.join(p1, p2, p3)
os.path.join(p3, p2, p1)

Output:
‘home\fm\note’
‘note\fm\home’

os.path.abspath()

  • 将传入路径规范化,返回一个相应的绝对路径格式的字符串。
  • 也就是说当传入路径符合“绝对路径”的格式时,该函数仅仅将路径分隔符替换为适应当前系统的字符,不做其他任何操作,并将结果返回。所谓“绝对路径的格式”,其实指的就是一个字母加冒号,之后跟分隔符和字符串序列的格式:
1
2
3
4
5
6
7
8
# 当前目录的绝对路径
os.path.abspath(r".")

# 上级目录的绝对路径
os.path.abspath(r"..")

# 指定目录
os.path.abspath(r"D:\BLOG\yxhsiao\themes\next\docs")

Output:
‘d:\‘
‘d:\‘
‘D:\BLOG\yxhsiao\themes\next\docs’

os.path.basename()

  • 该函数返回传入路径的“基名”,即传入路径的最下级目录。
  • 整这个函数要注意的一点是,返回的“基名”实际上是传入路径最后一个分隔符之后的子字符串,也就是说,如果最下级目录之后还有一个分隔符,得到的就会是一个空字符串:
1
os.path.basename(r'D:\OneDrive\SOFT\FormatFactory')

Output:
‘FormatFactory’

os.path.dirname()

  • os.path.basename()函数正好相反,返回的是最后一个分隔符前的整个字符串:
1
os.path.dirname(r'D:\OneDrive\SOFT\FormatFactory')

Output:
‘D:\OneDrive\SOFT’

os.path.split()

  • 实际上前两个函数都是弟弟,这个函数才是老大。
  • 函数 os.path.split()的功能就是将传入路径以最后一个分隔符为界,分成两个字符串,并打包成元组的形式返回.
  • 前两个函数 os.path.dirname()os.path.basename()的返回值分别是函数 os.path.split()返回值的第一个、第二个元素。就连二者的具体实现都十分真实:
1
os.path.split(r'D:\OneDrive\SOFT\FormatFactory')

Output:
(‘D:\OneDrive\SOFT’, ‘FormatFactory’)

os.path.splitex()

  • 分离文件名与扩展名;默认返回(fname,fextension)元组,可做分片操作
1
2
ph = r"D:\3D\export\test3.pdf"
os.path.splitext(ph)

Output:
(‘D:\3D\export\test3’, ‘.pdf’)

os.path.exists()

  • 这个函数用于判断路径所指向的位置是否存在。若存在则返回True,不存在则返回False
1
os.path.exists(r'D:\OneDrive\SOFT\134')

Output:
False

os.path.isabs()

  • 该函数判断传入路径是否是绝对路径,若是则返回True,否则返回False。当然,仅仅是检测格式,同样不对其有效性进行任何核验:
1
os.path.isabs(r'D:\OneDrive\SOFT\FormatFactory')

Output:
True

os.path.isfile() 和 os.path.isdir()

  • 这两个函数分别判断传入路径是否是文件或路径,注意,此处会核验路径的有效性,如果是无效路径将会持续返回False。
1
2
3
4
a = 'D:\\OneDrive\\Code\\Note\\python_module'

os.path.isfile(a)
os.path.isdir(a)

Output:
False
True

os.path.getsize()

  • 返回指定文件的大小,以字节为单位。
  • 仅仅对文件有效。使用前最好先判断是否是文件
1
2
3
4
5
a = 'D:\\BLOG\\yxhsiao\\themes\\next\\docs\\AGPL3.md'
b = 'D:\\BLOG\\yxhsiao\\themes'

os.path.getsize(a) if os.path.isfile(a) else 'The is not file'
os.path.getsize(b) if os.path.isfile(b) else 'The is not file'

Output:
34490
‘The is not file’

1
2
3
import pandas as pd
import xlwings as xw
import re,os
1
2
3
4
url = "https://www.icauto.com.cn/rank/"

data = pd.read_html(url, index_col=0, header=0)[0]
data.head(10)

Output:

车型 资料信息 月销量 年累计
#
1 Model Y 品牌:特斯拉,指导价:26.39-34.99万 41428 320109
2 秦PLUS 品牌:比亚迪,指导价:9.98-20.99万 39904 317115
3 宋PLUS新能源 品牌:比亚迪,指导价:15.38-21.98万 36773 276140
4 海鸥 品牌:比亚迪,指导价:7.88-9.58万 35011 119828
5 朗逸 品牌:大众,指导价:9.40-15.19万 32105 246656
6 轩逸 品牌:日产,指导价:9.98-17.49万 30028 257065
7 元PLUS 品牌:比亚迪,指导价:13.28-15.98万 28727 217670
8 AION Y 品牌:埃安,指导价:11.96-20.26万 26969 163552
9 速腾 品牌:大众,指导价:12.79-17.29万 26350 194407
10 海豚 品牌:比亚迪,指导价:11.68-13.98万 24282 221579
1
2
3
4
5
6
7
8
9
10
# 整理表格
# 将资料信息列的品牌和指导价格分列出来作为新的数据列

data['指导价格'] = data['资料信息'].map(lambda x :x.split(':')[-1].replace('万', ''))
data['品牌'] = data['资料信息'].map(lambda x :x.split(',')[0].split(':')[-1].replace('万', ''))

df = data.filter(['车型', '品牌', '指导价格','月销量', '年累计',])

df.set_index('车型',inplace=True)
df.to_excel('2309汽车销量统计表.xlsx')

Output:

1
2
3
4
5
6
7
8
9
10
11
# 打开Excel 文件
app = xw.App()
wb = xw.Book('2309汽车销量统计表.xlsx')

# 查看工作薄中的工作表
wb.sheet_names

# 将第一个工作表激活
ws1 = wb.sheets[0]
ws1.activate()

Output:
[‘Sheet1’]

1
2
3
4
5
6
7
8
# 获取数据的行数和列数,返回的是一个元组
rc = ws1.used_range.shape
row = rc[0]
col = rc[1]

row
col

Output:

588
5
1
2
3
4
5
6
7
8
# 设置标题区 背景色、字体样式和字体大小等
bt = ws1[0, :col]
bt.select()
bt.color = (0, 122, 204)
bt.font.name = '楷体'
bt.font.bold = True
bt.font.size = 16

Output:

1
2
3
4
5
# 设置数据区的格式:字体:等线  字号:12
rng1 = ws1[1:row, :col]
rng1.font.name = '等线'
rng1.font.size = 12

Output:

1
2
3
# 设置列宽和行高
ws1[:row, :col].autofit()

Output:

1
2
3
4
# 加载边框
ws1[:row, :col].api.Borders.LineStyle = 1


Output:

1
2
3
4
# 设置隔行着色。条件格式的方法实现
ws1[1:row, :5].api.FormatConditions.Add(
xw.constants.FormatConditionType.xlExpression,
Formula1="=Mod(Row(),2) =1").Interior.ColorIndex = 15

Output:

1
2
3
4
# 设置条件格式
ws1[1:row, 6].api.FormatConditions.Add(
xw.constants.FormatConditionType.xlExpression,
Formula1="=$E2>=180000").Font.ColorIndex = 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 排序,并将最近12月没有出货的区域涂绿色
ws1[:row, :col].api.Sort(Key1=ws1[0:row, :col].api.Columns(5),
Order1=2,
Header=1,
Orientation=1)

'''

Key1=range_to_sort.api.Columns(5) 来指定按照第5列(E列)进行排序。
Order1=1 来指定升序排序 2:表示降序
Header=1 来指定第1行为表头
Orientation=1 来指定排序方向为列排序。

'''
True

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 添加图表
chart = ws1.charts.add(ws1[:row, :col].width, 0, 800, 6000)
chart.set_source_data(ws1.range('A:A,E:E'))
chart.chart_type = 'bar_stacked'

chart.api[1].SetElement(2)
chart.api[1].ChartTitle.Text = '23年累计销量'
chart.api[1].SetElement(302)
chart.api[1].Axes(1).AxisTitle.Text = "车型"
chart.api[1].SetElement(311)
chart.api[1].Axes(2).AxisTitle.Text = "年销量" #纵轴标题名称
chart.api[1].SetElement(100) # 不显示图例

1
2
3
wb.save()
wb.close()
app.quit()

1
2
3
4
5
6
7
8
import pandas as pd
import re, os, random

file = r"D:\Stock\allstocks.csv"

data = pd.read_csv(file, dtype={'code': str})
data.sample(3)

output:

code name sind ind
1379 sz.300987 川网传媒 数字媒体 传媒
2240 sh.603087 甘李药业 其他生物制品 生物制品
3341 sz.000543 皖能电力 火电 电力

.isin()

  1. .isin() 方法可以同时判断数据是否与列表中的多个值相等,只要与列表中的某一个值相等则返回True,否则返回False
  2. 接受的是一个列表、字典、Series、Df
  3. 反函数是在之前加上 ~
1
2
data[data['ind'].isin(['化工合成材料', '化学制药'])]

output:

code name sind ind
390 sz.000420 吉林化纤 粘胶 化工合成材料
391 sh.600889 南京化纤 粘胶 化工合成材料
414 sz.301277 新天地 原料药 化学制药
415 sz.301258 富士莱 原料药 化学制药
416 sz.301211 亨迪药业 原料药 化学制药
... ... ... ... ...
4347 sh.603225 新凤鸣 涤纶 化工合成材料
4348 sh.601233 桐昆股份 涤纶 化工合成材料
4658 sz.002254 泰和新材 氨纶 化工合成材料
4659 sz.002064 华峰化学 氨纶 化工合成材料
4660 sz.000949 新乡化纤 氨纶 化工合成材料

242 rows × 4 columns

1
2
3
4
5
# .isin(Series)
sr1 = data.sind.sample(1)
sr1

data[data['sind'].isin(sr1)]
3745    光伏设备
Name: sind, dtype: object

output:

code name sind ind
3712 sz.301278 快可电子 光伏设备 电力设备
3713 sz.301266 宇邦新材 光伏设备 电力设备
3714 sz.301168 通灵股份 光伏设备 电力设备
3715 sz.300842 帝科股份 光伏设备 电力设备
3716 sz.300827 上能电气 光伏设备 电力设备
3717 sz.300776 帝尔激光 光伏设备 电力设备
3718 sz.300763 锦浪科技 光伏设备 电力设备
3719 sz.300751 迈为股份 光伏设备 电力设备
3720 sz.300724 捷佳伟创 光伏设备 电力设备
3721 sz.300393 中来股份 光伏设备 电力设备
3722 sz.300316 晶盛机电 光伏设备 电力设备
3723 sz.300274 阳光电源 光伏设备 电力设备
3724 sz.300125 聆达股份 光伏设备 电力设备
3725 sz.300118 东方日升 光伏设备 电力设备
3726 sz.300080 易成新能 光伏设备 电力设备
3727 sz.003022 联泓新科 光伏设备 电力设备
3728 sz.002865 钧达股份 光伏设备 电力设备
3729 sz.002623 亚玛顿 光伏设备 电力设备
3730 sz.002610 爱康科技 光伏设备 电力设备
3731 sz.002506 协鑫集成 光伏设备 电力设备
3732 sz.002459 晶澳科技 光伏设备 电力设备
3733 sz.002218 拓日新能 光伏设备 电力设备
3734 sz.002129 TCL中环 光伏设备 电力设备
3735 sz.001269 欧晶科技 光伏设备 电力设备
3736 sz.000821 京山轻机 光伏设备 电力设备
3737 sh.688680 海优新材 光伏设备 电力设备
3738 sh.688599 天合光能 光伏设备 电力设备
3739 sh.688598 金博股份 光伏设备 电力设备
3740 sh.688560 明冠新材 光伏设备 电力设备
3741 sh.688556 高测股份 光伏设备 电力设备
3742 sh.688516 奥特维 光伏设备 电力设备
3743 sh.688503 聚和材料 光伏设备 电力设备
3744 sh.688408 中信博 光伏设备 电力设备
3745 sh.688390 固德威 光伏设备 电力设备
3746 sh.688348 昱能科技 光伏设备 电力设备
3747 sh.688303 大全能源 光伏设备 电力设备
3748 sh.688223 晶科能源 光伏设备 电力设备
3749 sh.688147 微导纳米 光伏设备 电力设备
3750 sh.688032 禾迈股份 光伏设备 电力设备
3751 sh.603806 福斯特 光伏设备 电力设备
3752 sh.603628 清源股份 光伏设备 电力设备
3753 sh.603396 金辰股份 光伏设备 电力设备
3754 sh.603212 赛伍技术 光伏设备 电力设备
3755 sh.603185 上机数控 光伏设备 电力设备
3756 sh.601865 福莱特 光伏设备 电力设备
3757 sh.601012 隆基绿能 光伏设备 电力设备
3758 sh.600876 凯盛新能 光伏设备 电力设备
3759 sh.600732 爱旭股份 光伏设备 电力设备
3760 sh.600537 亿晶光电 光伏设备 电力设备
3761 sh.600438 通威股份 光伏设备 电力设备
3762 sh.600207 安彩高科 光伏设备 电力设备
3763 sh.600151 航天机电 光伏设备 电力设备
1
2
3
4
5
6
7
# .isin(Series)
sr1 = data.sind.sample(3)
# sr1
sr2 = data.ind.sample(3)
# sr2

data[data['sind'].isin(sr1) & data['ind'].isin(sr2)]

output:

code name sind ind
167 sz.002314 南山控股 住宅开发 房地产开发
168 sz.002244 滨江集团 住宅开发 房地产开发
169 sz.002208 合肥城建 住宅开发 房地产开发
170 sz.002146 荣盛发展 住宅开发 房地产开发
171 sz.002133 广宇集团 住宅开发 房地产开发
... ... ... ... ...
245 sh.600094 大名城 住宅开发 房地产开发
246 sh.600077 宋都股份 住宅开发 房地产开发
247 sh.600067 冠城大通 住宅开发 房地产开发
248 sh.600064 南京高科 住宅开发 房地产开发
249 sh.600048 保利发展 住宅开发 房地产开发

83 rows × 4 columns

1
2
3
4
5
# .isin(dict)
# .any(axis=1)

dct = {'sind': ['软件开发', 'IT服务'], 'ind': ['计算机应用']}
data[data.isin(dct).any(axis=1)]

output:

code name sind ind
1545 sz.301270 汉仪股份 软件开发 计算机应用
1546 sz.301269 华大九天 软件开发 计算机应用
1547 sz.301195 北路智控 软件开发 计算机应用
1548 sz.301185 鸥玛软件 软件开发 计算机应用
1549 sz.301162 国能日新 软件开发 计算机应用
... ... ... ... ...
4811 sh.600446 金证股份 IT服务 计算机应用
4812 sh.600410 华胜天成 IT服务 计算机应用
4813 sh.600271 航天信息 IT服务 计算机应用
4814 sh.600225 卓朗科技 IT服务 计算机应用
4815 sh.600131 国网信通 IT服务 计算机应用

240 rows × 4 columns

1
2
3
4
5
6
# 多列同时操作
# .any(axis=1), all(axis=1)

data[data[['code', 'ind']].isin(['sz.002616', 'sh.600163', '电力',
'计算机应用']).any(axis=1)]

output:

code name sind ind
833 sz.300317 珈伟新能 新能源发电 电力
834 sz.003816 中国广核 新能源发电 电力
835 sz.002617 露笑科技 新能源发电 电力
836 sz.002616 长青集团 新能源发电 电力
837 sz.002480 新筑股份 新能源发电 电力
... ... ... ... ...
4811 sh.600446 金证股份 IT服务 计算机应用
4812 sh.600410 华胜天成 IT服务 计算机应用
4813 sh.600271 航天信息 IT服务 计算机应用
4814 sh.600225 卓朗科技 IT服务 计算机应用
4815 sh.600131 国网信通 IT服务 计算机应用

331 rows × 4 columns

1
2
3
4
5
6
# 多列同时操作
# .any(axis=1), all(axis=1)

data[data[['code', 'ind']].isin(['sz.002616', 'sh.600163', '电力',
'计算机应用']).all(axis=1)]

output:

code name sind ind
836 sz.002616 长青集团 新能源发电 电力
857 sh.600163 中闽能源 新能源发电 电力
1
2
3
4
# 反函数用法
data[~data['ind'].
isin(['计算机应用', '环保', '综合', '光学光电子', '化工合成材料', '景点及旅游', '饮料制造', '零售'])]

output:

code name sind ind
62 sz.301098 金埔园林 装饰园林 建筑装饰
63 sz.300949 奥雅股份 装饰园林 建筑装饰
64 sz.300649 杭州园林 装饰园林 建筑装饰
65 sz.300621 维业股份 装饰园林 建筑装饰
66 sz.300536 农尚环境 装饰园林 建筑装饰
... ... ... ... ...
4593 sh.688233 神工股份 半导体材料 半导体及元件
4594 sh.688138 清溢光电 半导体材料 半导体及元件
4595 sh.688126 沪硅产业-U 半导体材料 半导体及元件
4596 sh.605358 立昂微 半导体材料 半导体及元件
4597 sh.600206 有研新材 半导体材料 半导体及元件

4096 rows × 4 columns

修改 VPN_WireGuard连接方式的配置文件

文件格式: .conf

下载下来的源文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
'''
#
# Use this configuration with WireGuard client
#
[Interface]
Address = 10.14.0.2/16
PrivateKey = <insert_your_private_key_here>
DNS = 162.252.172.57, 149.154.159.92
[Peer]
PublicKey = OoFY46j/w4uQFyFu/OQ/h3x+ymJ1DJ4UR1fwGNxOxk0=
AllowedIPs = 0.0.0.0/0
Endpoint = 103.176.152.200:51820
'''
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
import os, re

def modify_wireguard_config():
'''
修改VPN_WireGuard连接方式的配置文件。
读取源文件,同时创建新文件
遍历源文件的行,用re.sub(old_word,new_word,str) ,同时逐行写入新文件。
删除源文件,更名新文件名为源文件名
'''
fd = r"C:\Users\xiaoyx\Downloads"
files = [f"{fd}\{i}" for i in os.listdir(fd) if re.search(r'.conf$', i)]
w1 = '<insert_your_private_key_here>'
w2 = 'mKTo/XWQemHxEDJxfDaNvcFwB4R42WQDtV7ZURUitWg='
for file in files:
with open(file, 'r',
encoding='utf-8') as file1, open(f'{file}.bak',
'w',
encoding='utf-8') as file2:
for line in file1:
file2.write(re.sub(w1, w2, line))
os.remove(file)
os.rename(f'{file}.bak', file)


if __name__ =='__main__':
modify_wireguard_config()