-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
551 lines (285 loc) · 726 KB
/
atom.xml
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>星陨的博客</title>
<subtitle>与提问相比,知道的价值往往更小</subtitle>
<link href="https://xiaolaji.site/atom.xml" rel="self"/>
<link href="https://xiaolaji.site/"/>
<updated>2023-10-25T09:22:13.000Z</updated>
<id>https://xiaolaji.site/</id>
<author>
<name>Xiaolaji</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>树莓派通过PCA9685模块控制舵机</title>
<link href="https://xiaolaji.site/20230801/%E6%A0%91%E8%8E%93%E6%B4%BE%E9%80%9A%E8%BF%87PCA9685%E6%A8%A1%E5%9D%97%E6%8E%A7%E5%88%B6%E8%88%B5%E6%9C%BA/"/>
<id>https://xiaolaji.site/20230801/%E6%A0%91%E8%8E%93%E6%B4%BE%E9%80%9A%E8%BF%87PCA9685%E6%A8%A1%E5%9D%97%E6%8E%A7%E5%88%B6%E8%88%B5%E6%9C%BA/</id>
<published>2023-08-01T22:30:09.000Z</published>
<updated>2023-10-25T09:22:13.000Z</updated>
<content type="html"><![CDATA[<h1>树莓派通过PCA9685模块控制舵机</h1><h2 id="原因">原因</h2><p>我们使用树莓派制作机器人或者小车时,经常遇见需要控制大量舵机的需求,树莓派4B只有GPIO1引脚可以通过硬件方式输出PWM波,其余的引脚只有通过软件的方式才可以实现PWM波输出。</p><p><img src="watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2tzanoxMjM=,size_16,color_FFFFFF,t_70.png" alt="引脚示意图"></p><p>为了实现大量舵机的精准控制,可以使用PCA9685模块进行控制。</p><h2 id="PCA9685介绍">PCA9685介绍</h2><p><img src="70.jpeg" alt="PCA9685:I2C转16路PWM,助力你的系统"></p><p>详细介绍可以参考知乎上别人写的一篇文章<a href="https://zhuanlan.zhihu.com/p/67336644">PCA9685:I2C转16路PWM,助力你的系统 - 知乎 (zhihu.com)</a></p><p>可能有一些PCA9685板在外形上有一些不同,其本质近乎相同。</p><p>这边有一些注意点:</p><ul class="lvl-0"><li class="lvl-2"><p>以上图为例,左右两侧为通讯和供电接口,在使用的时候只需要连接任意一边即可。</p></li><li class="lvl-2"><p>中间上方的绿色端子为舵机单独供电接口,V+为正极,GND为舵机负极,这里的供电端子在左右两边也有接口,根据需求进行使用。</p></li><li class="lvl-2"><p>V+端子建议为6V供电,为了防止误接高电压,板载了一颗10V电容,就是左上角的黑色电容。</p></li><li class="lvl-2"><p>左上角的黑色电容规格为10V 1000uF ,有一些店家不会板载这一颗电容,需要自行购买。</p></li><li class="lvl-2"><p>板载供电与舵机供电是完全分开的,需要注意</p></li></ul><p>下方的3*16的路为舵机输出,舵机使用V+供电,PWM为信号输出接口。</p><h2 id="实操">实操</h2><h3 id="打开树莓派的IIC通信">打开树莓派的IIC通信</h3><p>树莓派在安装操作系统之后默认不开启IIC通信,此时树莓派上的IIC引脚暂时无法直接使用,通过<code>sudo raspi-config</code>命令将IIC通信功能开启。</p><p><img src="image-20231025155513500.png" alt="进入Interface Options选项"></p><p><img src="image-20231025155623022.png" alt="打开I2C接口"></p><p>之后选择<code>Back</code>退出,目前在最新的树莓派系统中似乎不再强制重启进行生效,建议手动进行重启保证接口改变的生效。</p><h3 id="安装Python控制包">安装Python控制包</h3><p>在终端输入<code>pip install Adafruit_PCA9685</code>,我提前将pip源换成了清华源,对于国内的用户要友好很多,过程如下:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs python">❯ sudo pip install Adafruit_PCA9685<br>Looking <span class="hljs-keyword">in</span> indexes: https://pypi.tuna.tsinghua.edu.cn/simple<br>Collecting Adafruit_PCA9685<br> Downloading https://pypi.tuna.tsinghua.edu.cn/packages/f6/<span class="hljs-number">33</span>/ea998d02bab6f51c43ed99e3345ff7642aa0ceac871aff8cb8850f0dde05/Adafruit_PCA9685-<span class="hljs-number">1.0</span><span class="hljs-number">.1</span>.tar.gz (<span class="hljs-number">3.0</span> kB)<br> Preparing metadata (setup.py) ... done<br>Collecting Adafruit-GPIO>=<span class="hljs-number">0.6</span><span class="hljs-number">.5</span> (<span class="hljs-keyword">from</span> Adafruit_PCA9685)<br> Downloading https://pypi.tuna.tsinghua.edu.cn/packages/db/1c/2dc8a674514219f287fa344e44cadfd77b3e2878d6ff602a8c2149b50dd8/Adafruit_GPIO-<span class="hljs-number">1.0</span><span class="hljs-number">.3</span>.tar.gz (<span class="hljs-number">24</span> kB)<br> Preparing metadata (setup.py) ... done<br>Collecting adafruit-pureio (<span class="hljs-keyword">from</span> Adafruit-GPIO>=<span class="hljs-number">0.6</span><span class="hljs-number">.5</span>->Adafruit_PCA9685)<br> Downloading https://pypi.tuna.tsinghua.edu.cn/packages/<span class="hljs-number">19</span>/9d/28e9d12f36e13c5f2acba3098187b0e931290ecd1d8df924391b5ad2db19/Adafruit_PureIO-<span class="hljs-number">1.1</span><span class="hljs-number">.11</span>-py3-none-<span class="hljs-built_in">any</span>.whl (<span class="hljs-number">10</span> kB)<br>Collecting spidev (<span class="hljs-keyword">from</span> Adafruit-GPIO>=<span class="hljs-number">0.6</span><span class="hljs-number">.5</span>->Adafruit_PCA9685)<br> Downloading https://pypi.tuna.tsinghua.edu.cn/packages/c7/d9/401c0a7be089e02826cf2c201f489876b601f15be100fe391ef9c2faed83/spidev-<span class="hljs-number">3.6</span>.tar.gz (<span class="hljs-number">11</span> kB)<br> Installing build dependencies ... done<br> Getting requirements to build wheel ... done<br> Installing backend dependencies ... done<br> Preparing metadata (pyproject.toml) ... done<br>Building wheels <span class="hljs-keyword">for</span> collected packages: Adafruit_PCA9685, Adafruit-GPIO, spidev<br> Building wheel <span class="hljs-keyword">for</span> Adafruit_PCA9685 (setup.py) ... done<br> Created wheel <span class="hljs-keyword">for</span> Adafruit_PCA9685: filename=Adafruit_PCA9685-<span class="hljs-number">1.0</span><span class="hljs-number">.1</span>-py3-none-<span class="hljs-built_in">any</span>.whl size=<span class="hljs-number">3754</span> sha256=b4033dd84fb944ba45506508bfe3f56f41c42e730c97eda304bc0b5afb20be01<br> Stored <span class="hljs-keyword">in</span> directory: /home/xiaolaji/.cache/pip/wheels/f6/<span class="hljs-number">57</span>/b8/918bc2d69ff2048d441d6b0d5bda5dd9ad959b1d2c5b48481f<br> Building wheel <span class="hljs-keyword">for</span> Adafruit-GPIO (setup.py) ... done<br> Created wheel <span class="hljs-keyword">for</span> Adafruit-GPIO: filename=Adafruit_GPIO-<span class="hljs-number">1.0</span><span class="hljs-number">.3</span>-py3-none-<span class="hljs-built_in">any</span>.whl size=<span class="hljs-number">38124</span> sha256=31d1147378f399fbf18d3c6aeae05fd670ef34a273ab747ef71e482b899ed870<br> Stored <span class="hljs-keyword">in</span> directory: /home/xiaolaji/.cache/pip/wheels/<span class="hljs-number">67</span>/6e/ec/cb7ec763a7f3a6daf3cc544d4cf4bef6dd79c38be99ef7de45<br> Building wheel <span class="hljs-keyword">for</span> spidev (pyproject.toml) ... done<br> Created wheel <span class="hljs-keyword">for</span> spidev: filename=spidev-<span class="hljs-number">3.6</span>-cp38-cp38-linux_x86_64.whl size=<span class="hljs-number">41334</span> sha256=75453493592c76e9fc891ad5036fb314eec296d998ea4af989504d3f1e7a8627<br> Stored <span class="hljs-keyword">in</span> directory: /home/xiaolaji/.cache/pip/wheels/7e/2e/8e/2e65bfcd39d1de3b550ac7ba444a5de1c1972b1d2b976f2444<br>Successfully built Adafruit_PCA9685 Adafruit-GPIO spidev<br>Installing collected packages: spidev, adafruit-pureio, Adafruit-GPIO, Adafruit_PCA9685<br>Successfully installed Adafruit-GPIO-<span class="hljs-number">1.0</span><span class="hljs-number">.3</span> Adafruit_PCA9685-<span class="hljs-number">1.0</span><span class="hljs-number">.1</span> adafruit-pureio-<span class="hljs-number">1.1</span><span class="hljs-number">.11</span> spidev-<span class="hljs-number">3.6</span><br></code></pre></td></tr></table></figure><h3 id="在程序中引用">在程序中引用</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> Adafruit_PCA9685 <span class="hljs-comment"># 引入PCA9685的驱动模块</span><br><br>pwm = Adafruit_PCA9685.PCA9685() <span class="hljs-comment"># 创建PCA9685控制对象</span><br>pwm.set_pwm_freq(<span class="hljs-number">50</span>) <span class="hljs-comment"># 设置频率为50HZ</span><br>channel = <span class="hljs-number">0</span> <span class="hljs-comment"># PCA9685模块提供16路的PWM输出 分别为0~15号 这里选择在0号输出</span><br>set_servo_angle(channel,<span class="hljs-number">90</span>) <span class="hljs-comment"># 此时舵机应该转动到90度上,输出PWM波占空比为50%</span><br><br><span class="hljs-comment"># 这里使用180度舵机作举例 控制的占空比为0%~100%</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">set_servo_angle</span>(<span class="hljs-params">channel, angle</span>): <span class="hljs-comment"># 输入角度转换成12^精度的数值</span><br> date = <span class="hljs-built_in">int</span>(<span class="hljs-number">4096</span> * ((angle * <span class="hljs-number">11</span>) + <span class="hljs-number">500</span>) / <span class="hljs-number">20000</span>) <span class="hljs-comment"># 进行四舍五入运算 date=int(4096*((angle*11)+500)/(20000)+0.5)</span><br> <span class="hljs-comment"># PCA9685的控制为持续时间来进行控制的 set_pwm方法的第二个以及第三个参数指占空比从A~B这么久,最大为4096,对应上0~100的占空比</span><br> <span class="hljs-comment"># 也可以直接将角度直接映射到0~4096上</span><br> <span class="hljs-comment"># data = int(angle/180)*4096</span><br> pwm.set_pwm(channel, <span class="hljs-number">0</span>, date)<br></code></pre></td></tr></table></figure><p>以上就是在程序中的使用,如有欠妥之处,请帮忙指出:smile</p>]]></content>
<summary type="html"><h1>树莓派通过PCA9685模块控制舵机</h1>
<h2 id="原因">原因</h2>
<p>我们使用树莓派制作机器人或者小车时,经常遇见需要控制大量舵机的需求,树莓派4B只有GPIO1引脚可以通过硬件方式输出PWM波,其余的引脚只有通过软件的方式才可以实现PWM波输出。</summary>
<category term="嵌入式Linux" scheme="https://xiaolaji.site/categories/%E5%B5%8C%E5%85%A5%E5%BC%8FLinux/"/>
<category term="树莓派" scheme="https://xiaolaji.site/tags/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
</entry>
<entry>
<title>树莓派U盘启动方法</title>
<link href="https://xiaolaji.site/20230731/%E6%A0%91%E8%8E%93%E6%B4%BEU%E7%9B%98%E5%90%AF%E5%8A%A8%E6%96%B9%E6%B3%95/"/>
<id>https://xiaolaji.site/20230731/%E6%A0%91%E8%8E%93%E6%B4%BEU%E7%9B%98%E5%90%AF%E5%8A%A8%E6%96%B9%E6%B3%95/</id>
<published>2023-07-31T18:02:20.000Z</published>
<updated>2023-07-31T11:04:54.000Z</updated>
<content type="html"><![CDATA[<h1>树莓派U盘启动方法</h1><p>树莓派设备是学习嵌入式Linux开发的常见一款开发板,我们一般是将系统进行烧录到TF卡内,使树莓派从TF卡内启动系统,但是市面上常见的TF卡的IO速度大约是10MB/s,TF卡的读写速度大大限制了一些IO交换比较多的任务的执行速度,使我们的程序运行过程中出现卡顿或者运行缓慢等情况,如果我们能够将树莓派默认的启动方式从TF卡更改到U盘启动,使用USB3.0标准的U盘作为我们的系统盘,这将会大幅提高我们系统运行的流畅性以及程序执行的速度。</p><p>下面我会通过树莓派的官方镜像烧录工具来演示如何将树莓派的启动方式切换至U盘启动。</p><h2 id="前期准备工作">前期准备工作</h2><ul class="lvl-0"><li class="lvl-2"><p>一张TF卡</p><p>用于将原本的Bootloader自动烧录进树莓派的板载存储中以改变与原本的Bootloader</p></li><li class="lvl-2"><p>TF卡读卡器</p><p>用于将TF卡连接至电脑,便于Raspberrypi镜像烧录工具对其进行操作</p></li><li class="lvl-2"><p>一块支持USB3.0标准的U盘</p><p>切换后U盘中会烧录进我们的新的系统</p></li><li class="lvl-2"><p>Raspberrypi镜像烧录工具</p><p>树莓派官方出品的一款极为便捷的树莓派烧录工具,可以一键烧录各种与树莓派相兼容的系统,除了官方的Raspberrypi Pi OS还有很多常见的Linux系统如:Ubuntu Apertis RISC;还有很多小众的特殊用途的系统支持一键烧录,使树莓派的生态更为全面。</p><p>我们的Bootloader也在官方镜像下载器的支持范围内。</p><p>此软件可以从官网下载,点击<a href="https://www.raspberrypi.com/software/">此处</a>跳转官方网站选择合适版本下载。</p><p><img src="image-20230731142646000.png" alt="Raspberrypi镜像烧录工具"></p></li></ul><h2 id="正式开始">正式开始</h2><h3 id="将Bootloader烧录进TF卡">将Bootloader烧录进TF卡</h3><p>将TF卡通过读卡器连接电脑,在Raspberrypi镜像烧录工具中点击<code>选择操作系统</code></p><p><img src="image-20230731143034944.png" alt="选择操作系统"></p><p>这里可供我们选择的操作系统非常多,各位可以自行探索,我们这里下拉,选择Misc utility images</p><p><img src="image-20230731143516330.png" alt="Misc utility images"></p><p>再次选择Bootloader</p><p><img src="image-20230731143617999.png" alt="Bootloader"></p><p>Bootloader中提供了三种Boot方式</p><p><img src="image-20230731143733992.png" alt="Boot方式"></p><p>SD Card Boot方式指优先从SD卡启动,如果无法启动则从USB启动</p><p>USB Boot方式则与SD Card Boot 相反</p><p>NetWork Boot方式是优先SD卡和USB方式,如果两者都无法启动则会自动通过网络进行启动,但是这一种方式我没有尝试过,有兴趣的小伙伴可以尝试一下。</p><p><img src="image-20230731144343482.png" alt="烧录Bootloader"></p><p>选择USB Boot,点击选择SD卡,进行烧录等待完成即可。</p><h2 id="将Bootloader烧录进树莓派">将Bootloader烧录进树莓派</h2><p>将烧录好的TF卡插入树莓派,上电启动后绿色的LED会快速闪烁一段时间,之后连接树莓派的屏幕上会显示为绿色,则Bootloader已经烧录进树莓派,大功告成,现在树莓派已经将启动方式切换为优先USB。</p><h2 id="重新安装系统或者迁移原系统">重新安装系统或者迁移原系统</h2><h3 id="重新安装">重新安装</h3><p>通过树莓派镜像烧录器选择需要的系统进行少录,将我们的U盘连接电脑,选择SD卡时选择我们的U盘,正常进行烧录即可,最终将U盘插在树莓派上的USB3.0接口上,上电后即可自动启动系统。</p><h3 id="迁移系统">迁移系统</h3><p>迁移系统要注意将我们要迁移的U盘先格式化为FAT32格式,此操作可以借助树莓派镜像烧录器进行。</p><p>将原本的TF卡内的所有文件进行拷贝,粘贴到U盘内,最终将U盘插在树莓派上的USB3.0接口上,上电后即可自动启动系统。</p>]]></content>
<summary type="html"><h1>树莓派U盘启动方法</h1>
<p>树莓派设备是学习嵌入式Linux开发的常见一款开发板,我们一般是将系统进行烧录到TF卡内,使树莓派从TF卡内启动系统,但是市面上常见的TF卡的IO速度大约是10MB/s,TF卡的读写速度大大限制了一些IO交换比较多的任务的执行速度,使我</summary>
<category term="嵌入式Linux" scheme="https://xiaolaji.site/categories/%E5%B5%8C%E5%85%A5%E5%BC%8FLinux/"/>
<category term="树莓派" scheme="https://xiaolaji.site/tags/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
</entry>
<entry>
<title>Ascll完整码表</title>
<link href="https://xiaolaji.site/20230625/Ascll%E5%AE%8C%E6%95%B4%E7%A0%81%E8%A1%A8/"/>
<id>https://xiaolaji.site/20230625/Ascll%E5%AE%8C%E6%95%B4%E7%A0%81%E8%A1%A8/</id>
<published>2023-06-25T15:16:13.000Z</published>
<updated>2023-06-25T05:10:34.000Z</updated>
<content type="html"><![CDATA[<h1><strong>ASCII码表</strong></h1><table><thead><tr><th style="text-align:center"><strong>ASCII值</strong></th><th style="text-align:center"><strong>控制字符</strong></th><th style="text-align:center"><strong>ASCII值</strong></th><th style="text-align:center"><strong>控制字符</strong></th><th style="text-align:center"><strong>ASCII值</strong></th><th style="text-align:center"><strong>控制字符</strong></th><th style="text-align:center"><strong>ASCII值</strong></th><th style="text-align:center"><strong>控制字符</strong></th></tr></thead><tbody><tr><td style="text-align:center">0</td><td style="text-align:center">NUL</td><td style="text-align:center">32</td><td style="text-align:center">(space)</td><td style="text-align:center">64</td><td style="text-align:center">@</td><td style="text-align:center">96</td><td style="text-align:center">、</td></tr><tr><td style="text-align:center">1</td><td style="text-align:center">SOH</td><td style="text-align:center">33</td><td style="text-align:center">!</td><td style="text-align:center">65</td><td style="text-align:center">A</td><td style="text-align:center">97</td><td style="text-align:center">a</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center">STX</td><td style="text-align:center">34</td><td style="text-align:center">"</td><td style="text-align:center">66</td><td style="text-align:center">B</td><td style="text-align:center">98</td><td style="text-align:center">b</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center">ETX</td><td style="text-align:center">35</td><td style="text-align:center">#</td><td style="text-align:center">67</td><td style="text-align:center">C</td><td style="text-align:center">99</td><td style="text-align:center">c</td></tr><tr><td style="text-align:center">4</td><td style="text-align:center">EOT</td><td style="text-align:center">36</td><td style="text-align:center">$</td><td style="text-align:center">68</td><td style="text-align:center">D</td><td style="text-align:center">100</td><td style="text-align:center">d</td></tr><tr><td style="text-align:center">5</td><td style="text-align:center">ENQ</td><td style="text-align:center">37</td><td style="text-align:center">%</td><td style="text-align:center">69</td><td style="text-align:center">E</td><td style="text-align:center">101</td><td style="text-align:center">e</td></tr><tr><td style="text-align:center">6</td><td style="text-align:center">ACK</td><td style="text-align:center">38</td><td style="text-align:center">&</td><td style="text-align:center">70</td><td style="text-align:center">F</td><td style="text-align:center">102</td><td style="text-align:center">f</td></tr><tr><td style="text-align:center">7</td><td style="text-align:center">BEL</td><td style="text-align:center">39</td><td style="text-align:center">’</td><td style="text-align:center">71</td><td style="text-align:center">G</td><td style="text-align:center">103</td><td style="text-align:center">g</td></tr><tr><td style="text-align:center">8</td><td style="text-align:center">BS</td><td style="text-align:center">40</td><td style="text-align:center">(</td><td style="text-align:center">72</td><td style="text-align:center">H</td><td style="text-align:center">104</td><td style="text-align:center">h</td></tr><tr><td style="text-align:center">9</td><td style="text-align:center">HT</td><td style="text-align:center">41</td><td style="text-align:center">)</td><td style="text-align:center">73</td><td style="text-align:center">I</td><td style="text-align:center">105</td><td style="text-align:center">i</td></tr><tr><td style="text-align:center">10</td><td style="text-align:center">LF</td><td style="text-align:center">42</td><td style="text-align:center">*</td><td style="text-align:center">74</td><td style="text-align:center">J</td><td style="text-align:center">106</td><td style="text-align:center">j</td></tr><tr><td style="text-align:center">11</td><td style="text-align:center">VT</td><td style="text-align:center">43</td><td style="text-align:center">+</td><td style="text-align:center">75</td><td style="text-align:center">K</td><td style="text-align:center">107</td><td style="text-align:center">k</td></tr><tr><td style="text-align:center">12</td><td style="text-align:center">FF</td><td style="text-align:center">44</td><td style="text-align:center">,</td><td style="text-align:center">76</td><td style="text-align:center">L</td><td style="text-align:center">108</td><td style="text-align:center">l</td></tr><tr><td style="text-align:center">13</td><td style="text-align:center">CR</td><td style="text-align:center">45</td><td style="text-align:center">-</td><td style="text-align:center">77</td><td style="text-align:center">M</td><td style="text-align:center">109</td><td style="text-align:center">m</td></tr><tr><td style="text-align:center">14</td><td style="text-align:center">SO</td><td style="text-align:center">46</td><td style="text-align:center">.</td><td style="text-align:center">78</td><td style="text-align:center">N</td><td style="text-align:center">110</td><td style="text-align:center">n</td></tr><tr><td style="text-align:center">15</td><td style="text-align:center">SI</td><td style="text-align:center">47</td><td style="text-align:center">/</td><td style="text-align:center">79</td><td style="text-align:center">O</td><td style="text-align:center">111</td><td style="text-align:center">o</td></tr><tr><td style="text-align:center">16</td><td style="text-align:center">DLE</td><td style="text-align:center">48</td><td style="text-align:center">0</td><td style="text-align:center">80</td><td style="text-align:center">P</td><td style="text-align:center">112</td><td style="text-align:center">p</td></tr><tr><td style="text-align:center">17</td><td style="text-align:center">DCI</td><td style="text-align:center">49</td><td style="text-align:center">1</td><td style="text-align:center">81</td><td style="text-align:center">Q</td><td style="text-align:center">113</td><td style="text-align:center">q</td></tr><tr><td style="text-align:center">18</td><td style="text-align:center">DC2</td><td style="text-align:center">50</td><td style="text-align:center">2</td><td style="text-align:center">82</td><td style="text-align:center">R</td><td style="text-align:center">114</td><td style="text-align:center">r</td></tr><tr><td style="text-align:center">19</td><td style="text-align:center">DC3</td><td style="text-align:center">51</td><td style="text-align:center">3</td><td style="text-align:center">83</td><td style="text-align:center">S</td><td style="text-align:center">115</td><td style="text-align:center">s</td></tr><tr><td style="text-align:center">20</td><td style="text-align:center">DC4</td><td style="text-align:center">52</td><td style="text-align:center">4</td><td style="text-align:center">84</td><td style="text-align:center">T</td><td style="text-align:center">116</td><td style="text-align:center">t</td></tr><tr><td style="text-align:center">21</td><td style="text-align:center">NAK</td><td style="text-align:center">53</td><td style="text-align:center">5</td><td style="text-align:center">85</td><td style="text-align:center">U</td><td style="text-align:center">117</td><td style="text-align:center">u</td></tr><tr><td style="text-align:center">22</td><td style="text-align:center">SYN</td><td style="text-align:center">54</td><td style="text-align:center">6</td><td style="text-align:center">86</td><td style="text-align:center">V</td><td style="text-align:center">118</td><td style="text-align:center">v</td></tr><tr><td style="text-align:center">23</td><td style="text-align:center">TB</td><td style="text-align:center">55</td><td style="text-align:center">7</td><td style="text-align:center">87</td><td style="text-align:center">W</td><td style="text-align:center">119</td><td style="text-align:center">w</td></tr><tr><td style="text-align:center">24</td><td style="text-align:center">CAN</td><td style="text-align:center">56</td><td style="text-align:center">8</td><td style="text-align:center">88</td><td style="text-align:center">X</td><td style="text-align:center">120</td><td style="text-align:center">x</td></tr><tr><td style="text-align:center">25</td><td style="text-align:center">EM</td><td style="text-align:center">57</td><td style="text-align:center">9</td><td style="text-align:center">89</td><td style="text-align:center">Y</td><td style="text-align:center">121</td><td style="text-align:center">y</td></tr><tr><td style="text-align:center">26</td><td style="text-align:center">SUB</td><td style="text-align:center">58</td><td style="text-align:center">:</td><td style="text-align:center">90</td><td style="text-align:center">Z</td><td style="text-align:center">122</td><td style="text-align:center">z</td></tr><tr><td style="text-align:center">27</td><td style="text-align:center">ESC</td><td style="text-align:center">59</td><td style="text-align:center">;</td><td style="text-align:center">91</td><td style="text-align:center">[</td><td style="text-align:center">123</td><td style="text-align:center">{}</td></tr><tr><td style="text-align:center">28</td><td style="text-align:center">FS</td><td style="text-align:center">60</td><td style="text-align:center"><</td><td style="text-align:center">92</td><td style="text-align:center">\</td><td style="text-align:center">124</td><td style="text-align:center">|</td></tr><tr><td style="text-align:center">29</td><td style="text-align:center">GS</td><td style="text-align:center">61</td><td style="text-align:center">=</td><td style="text-align:center">93</td><td style="text-align:center">]</td><td style="text-align:center">125</td><td style="text-align:center">}</td></tr><tr><td style="text-align:center">30</td><td style="text-align:center">RS</td><td style="text-align:center">62</td><td style="text-align:center">></td><td style="text-align:center">94</td><td style="text-align:center">^</td><td style="text-align:center">126</td><td style="text-align:center">~</td></tr><tr><td style="text-align:center">31</td><td style="text-align:center">US</td><td style="text-align:center">63</td><td style="text-align:center">?</td><td style="text-align:center">95</td><td style="text-align:center">—</td><td style="text-align:center">127</td><td style="text-align:center">DEL</td></tr></tbody></table><h2 id="ASCII诠释部分"><strong>ASCII诠释部分</strong></h2><p>ASCII中的0<sub>31为控制字符;32</sub>126为打印字符;127为Delete(删除)命令。</p><h3 id="下表为控制字符释义">下表为控制字符释义</h3><table><thead><tr><th style="text-align:center">十进制</th><th style="text-align:center"><strong>十六进制</strong></th><th style="text-align:center"><strong>字符</strong></th><th style="text-align:center"><strong>十进制</strong></th><th style="text-align:center"><strong>十六进制</strong></th><th style="text-align:center"><strong>字符</strong></th></tr></thead><tbody><tr><td style="text-align:center">0</td><td style="text-align:center">00</td><td style="text-align:center">空</td><td style="text-align:center">15</td><td style="text-align:center">10</td><td style="text-align:center">数据链路转意</td></tr><tr><td style="text-align:center">1</td><td style="text-align:center">01</td><td style="text-align:center">头标开始</td><td style="text-align:center">16</td><td style="text-align:center">11</td><td style="text-align:center">设备控制 1</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center">02</td><td style="text-align:center">正文开始</td><td style="text-align:center">17</td><td style="text-align:center">12</td><td style="text-align:center">设备控制 2</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center">03</td><td style="text-align:center">正文结束</td><td style="text-align:center">18</td><td style="text-align:center">13</td><td style="text-align:center">设备控制 3</td></tr><tr><td style="text-align:center">4</td><td style="text-align:center">04</td><td style="text-align:center">传输结束</td><td style="text-align:center">19</td><td style="text-align:center">14</td><td style="text-align:center">设备控制 4</td></tr><tr><td style="text-align:center">5</td><td style="text-align:center">05</td><td style="text-align:center">查询</td><td style="text-align:center">20</td><td style="text-align:center">15</td><td style="text-align:center">反确认</td></tr><tr><td style="text-align:center">6</td><td style="text-align:center">06</td><td style="text-align:center">确认</td><td style="text-align:center">21</td><td style="text-align:center">16</td><td style="text-align:center">同步空闲</td></tr><tr><td style="text-align:center">7</td><td style="text-align:center">07</td><td style="text-align:center">震铃</td><td style="text-align:center">22</td><td style="text-align:center">17</td><td style="text-align:center">传输块结束</td></tr><tr><td style="text-align:center">8</td><td style="text-align:center">08</td><td style="text-align:center">backspace</td><td style="text-align:center">23</td><td style="text-align:center">18</td><td style="text-align:center">取消</td></tr><tr><td style="text-align:center">9</td><td style="text-align:center">09</td><td style="text-align:center">水平制表符</td><td style="text-align:center">24</td><td style="text-align:center">19</td><td style="text-align:center">媒体结束</td></tr><tr><td style="text-align:center">10</td><td style="text-align:center">0A</td><td style="text-align:center">换行/新行</td><td style="text-align:center">25</td><td style="text-align:center">1A</td><td style="text-align:center">替换</td></tr><tr><td style="text-align:center">11</td><td style="text-align:center">0B</td><td style="text-align:center">竖直制表符</td><td style="text-align:center">26</td><td style="text-align:center">1B</td><td style="text-align:center">转意</td></tr><tr><td style="text-align:center">12</td><td style="text-align:center">0C</td><td style="text-align:center">换页/新页</td><td style="text-align:center">27</td><td style="text-align:center">1C</td><td style="text-align:center">文件分隔符</td></tr><tr><td style="text-align:center">13</td><td style="text-align:center">0D</td><td style="text-align:center">回车</td><td style="text-align:center">28</td><td style="text-align:center">1D</td><td style="text-align:center">组分隔符</td></tr><tr><td style="text-align:center">14</td><td style="text-align:center">0E</td><td style="text-align:center">移出</td><td style="text-align:center">29</td><td style="text-align:center">1E</td><td style="text-align:center">记录分隔符</td></tr><tr><td style="text-align:center">15</td><td style="text-align:center">0F</td><td style="text-align:center">移入</td><td style="text-align:center">30</td><td style="text-align:center">1F</td><td style="text-align:center">单元分隔符</td></tr></tbody></table><h2 id="ASCII扩展字符"><strong>ASCII扩展字符</strong></h2><p>为了适应更多字符,128<sub>255,或者-128</sub>-1,其中,-128对应128,依次递增对应</p><table><thead><tr><th style="text-align:center">十进制</th><th style="text-align:center"><strong>十六进制</strong></th><th style="text-align:center"><strong>字符</strong></th><th style="text-align:center"><strong>十进制</strong></th><th style="text-align:center"><strong>十六进制</strong></th><th style="text-align:center"><strong>字符</strong></th></tr></thead><tbody><tr><td style="text-align:center">128</td><td style="text-align:center">80</td><td style="text-align:center">Ç</td><td style="text-align:center">192</td><td style="text-align:center">C0</td><td style="text-align:center">└</td></tr><tr><td style="text-align:center">129</td><td style="text-align:center">81</td><td style="text-align:center">ü</td><td style="text-align:center">193</td><td style="text-align:center">C1</td><td style="text-align:center">┴</td></tr><tr><td style="text-align:center">130</td><td style="text-align:center">82</td><td style="text-align:center">é</td><td style="text-align:center">194</td><td style="text-align:center">C2</td><td style="text-align:center">┬</td></tr><tr><td style="text-align:center">131</td><td style="text-align:center">83</td><td style="text-align:center">â</td><td style="text-align:center">195</td><td style="text-align:center">C3</td><td style="text-align:center">├</td></tr><tr><td style="text-align:center">132</td><td style="text-align:center">84</td><td style="text-align:center">ä</td><td style="text-align:center">196</td><td style="text-align:center">C4</td><td style="text-align:center">─</td></tr><tr><td style="text-align:center">133</td><td style="text-align:center">85</td><td style="text-align:center">à</td><td style="text-align:center">197</td><td style="text-align:center">C5</td><td style="text-align:center">┼</td></tr><tr><td style="text-align:center">134</td><td style="text-align:center">86</td><td style="text-align:center">å</td><td style="text-align:center">198</td><td style="text-align:center">C6</td><td style="text-align:center">╞</td></tr><tr><td style="text-align:center">135</td><td style="text-align:center">87</td><td style="text-align:center">ç</td><td style="text-align:center">199</td><td style="text-align:center">C7</td><td style="text-align:center">╟</td></tr><tr><td style="text-align:center">136</td><td style="text-align:center">88</td><td style="text-align:center">ê</td><td style="text-align:center">200</td><td style="text-align:center">C8</td><td style="text-align:center">╚</td></tr><tr><td style="text-align:center">137</td><td style="text-align:center">89</td><td style="text-align:center">ë</td><td style="text-align:center">201</td><td style="text-align:center">C9</td><td style="text-align:center">╔</td></tr><tr><td style="text-align:center">138</td><td style="text-align:center">8A</td><td style="text-align:center">è</td><td style="text-align:center">202</td><td style="text-align:center">CA</td><td style="text-align:center">╩</td></tr><tr><td style="text-align:center">139</td><td style="text-align:center">8B</td><td style="text-align:center">ï</td><td style="text-align:center">203</td><td style="text-align:center">CB</td><td style="text-align:center">╦</td></tr><tr><td style="text-align:center">140</td><td style="text-align:center">8C</td><td style="text-align:center">î</td><td style="text-align:center">204</td><td style="text-align:center">CC</td><td style="text-align:center">╠</td></tr><tr><td style="text-align:center">141</td><td style="text-align:center">8D</td><td style="text-align:center">ì</td><td style="text-align:center">205</td><td style="text-align:center">CD</td><td style="text-align:center">═</td></tr><tr><td style="text-align:center">142</td><td style="text-align:center">8E</td><td style="text-align:center">Ä</td><td style="text-align:center">206</td><td style="text-align:center">CE</td><td style="text-align:center">╬</td></tr><tr><td style="text-align:center">143</td><td style="text-align:center">8F</td><td style="text-align:center">Å</td><td style="text-align:center">207</td><td style="text-align:center">CF</td><td style="text-align:center">╧</td></tr><tr><td style="text-align:center">144</td><td style="text-align:center">90</td><td style="text-align:center">É</td><td style="text-align:center">208</td><td style="text-align:center">D0</td><td style="text-align:center">╨</td></tr><tr><td style="text-align:center">145</td><td style="text-align:center">91</td><td style="text-align:center">æ</td><td style="text-align:center">209</td><td style="text-align:center">D1</td><td style="text-align:center">╤</td></tr><tr><td style="text-align:center">146</td><td style="text-align:center">92</td><td style="text-align:center">Æ</td><td style="text-align:center">210</td><td style="text-align:center">D2</td><td style="text-align:center">╥</td></tr><tr><td style="text-align:center">147</td><td style="text-align:center">93</td><td style="text-align:center">ô</td><td style="text-align:center">211</td><td style="text-align:center">D3</td><td style="text-align:center">╙</td></tr><tr><td style="text-align:center">148</td><td style="text-align:center">94</td><td style="text-align:center">ö</td><td style="text-align:center">212</td><td style="text-align:center">D4</td><td style="text-align:center">Ô</td></tr><tr><td style="text-align:center">149</td><td style="text-align:center">95</td><td style="text-align:center">ò</td><td style="text-align:center">213</td><td style="text-align:center">D5</td><td style="text-align:center">╒</td></tr><tr><td style="text-align:center">150</td><td style="text-align:center">96</td><td style="text-align:center">û</td><td style="text-align:center">214</td><td style="text-align:center">D6</td><td style="text-align:center">╓</td></tr><tr><td style="text-align:center">151</td><td style="text-align:center">97</td><td style="text-align:center">ù</td><td style="text-align:center">215</td><td style="text-align:center">D7</td><td style="text-align:center">╫</td></tr><tr><td style="text-align:center">152</td><td style="text-align:center">98</td><td style="text-align:center">ÿ</td><td style="text-align:center">216</td><td style="text-align:center">D8</td><td style="text-align:center">╪</td></tr><tr><td style="text-align:center">153</td><td style="text-align:center">99</td><td style="text-align:center">Ö</td><td style="text-align:center">217</td><td style="text-align:center">D9</td><td style="text-align:center">┘</td></tr><tr><td style="text-align:center">154</td><td style="text-align:center">9A</td><td style="text-align:center">Ü</td><td style="text-align:center">218</td><td style="text-align:center">DA</td><td style="text-align:center">┌</td></tr><tr><td style="text-align:center">155</td><td style="text-align:center">9B</td><td style="text-align:center">¢</td><td style="text-align:center">219</td><td style="text-align:center">DB</td><td style="text-align:center">█</td></tr><tr><td style="text-align:center">156</td><td style="text-align:center">9C</td><td style="text-align:center">£</td><td style="text-align:center">220</td><td style="text-align:center">DC</td><td style="text-align:center">▄</td></tr><tr><td style="text-align:center">157</td><td style="text-align:center">9D</td><td style="text-align:center">¥</td><td style="text-align:center">221</td><td style="text-align:center">DD</td><td style="text-align:center">▌</td></tr><tr><td style="text-align:center">158</td><td style="text-align:center">9E</td><td style="text-align:center">?</td><td style="text-align:center">222</td><td style="text-align:center">DE</td><td style="text-align:center">?</td></tr><tr><td style="text-align:center">159</td><td style="text-align:center">9F</td><td style="text-align:center">ƒ</td><td style="text-align:center">223</td><td style="text-align:center">DF</td><td style="text-align:center">?</td></tr><tr><td style="text-align:center">160</td><td style="text-align:center">A0</td><td style="text-align:center">á</td><td style="text-align:center">224</td><td style="text-align:center">E0</td><td style="text-align:center">α</td></tr><tr><td style="text-align:center">161</td><td style="text-align:center">A1</td><td style="text-align:center">í</td><td style="text-align:center">225</td><td style="text-align:center">E1</td><td style="text-align:center">ß</td></tr><tr><td style="text-align:center">162</td><td style="text-align:center">A2</td><td style="text-align:center">ó</td><td style="text-align:center">226</td><td style="text-align:center">E2</td><td style="text-align:center">Γ</td></tr><tr><td style="text-align:center">163</td><td style="text-align:center">A3</td><td style="text-align:center">ú</td><td style="text-align:center">227</td><td style="text-align:center">E3</td><td style="text-align:center">π</td></tr><tr><td style="text-align:center">164</td><td style="text-align:center">A4</td><td style="text-align:center">ñ</td><td style="text-align:center">228</td><td style="text-align:center">E4</td><td style="text-align:center">Σ</td></tr><tr><td style="text-align:center">165</td><td style="text-align:center">A5</td><td style="text-align:center">Ñ</td><td style="text-align:center">229</td><td style="text-align:center">E5</td><td style="text-align:center">σ</td></tr><tr><td style="text-align:center">166</td><td style="text-align:center">A6</td><td style="text-align:center">ª</td><td style="text-align:center">230</td><td style="text-align:center">E6</td><td style="text-align:center">µ</td></tr><tr><td style="text-align:center">167</td><td style="text-align:center">A7</td><td style="text-align:center">º</td><td style="text-align:center">231</td><td style="text-align:center">E7</td><td style="text-align:center">τ</td></tr><tr><td style="text-align:center">168</td><td style="text-align:center">A8</td><td style="text-align:center">¿</td><td style="text-align:center">232</td><td style="text-align:center">E8</td><td style="text-align:center">Φ</td></tr><tr><td style="text-align:center">169</td><td style="text-align:center">A9</td><td style="text-align:center">?</td><td style="text-align:center">233</td><td style="text-align:center">E9</td><td style="text-align:center">Θ</td></tr><tr><td style="text-align:center">170</td><td style="text-align:center">AA</td><td style="text-align:center">¬</td><td style="text-align:center">234</td><td style="text-align:center">EA</td><td style="text-align:center">Ω</td></tr><tr><td style="text-align:center">171</td><td style="text-align:center">AB</td><td style="text-align:center">½</td><td style="text-align:center">235</td><td style="text-align:center">EB</td><td style="text-align:center">δ</td></tr><tr><td style="text-align:center">172</td><td style="text-align:center">AC</td><td style="text-align:center">¼</td><td style="text-align:center">236</td><td style="text-align:center">EC</td><td style="text-align:center">∞</td></tr><tr><td style="text-align:center">173</td><td style="text-align:center">AD</td><td style="text-align:center">¡</td><td style="text-align:center">237</td><td style="text-align:center">ED</td><td style="text-align:center">φ</td></tr><tr><td style="text-align:center">174</td><td style="text-align:center">AE</td><td style="text-align:center">«</td><td style="text-align:center">238</td><td style="text-align:center">EE</td><td style="text-align:center">ε</td></tr><tr><td style="text-align:center">175</td><td style="text-align:center">AF</td><td style="text-align:center">»</td><td style="text-align:center">239</td><td style="text-align:center">EF</td><td style="text-align:center">∩</td></tr><tr><td style="text-align:center">176</td><td style="text-align:center">B0</td><td style="text-align:center">?</td><td style="text-align:center">240</td><td style="text-align:center">F0</td><td style="text-align:center">≡</td></tr><tr><td style="text-align:center">177</td><td style="text-align:center">B1</td><td style="text-align:center">?</td><td style="text-align:center">241</td><td style="text-align:center">F1</td><td style="text-align:center">±</td></tr><tr><td style="text-align:center">178</td><td style="text-align:center">B2</td><td style="text-align:center">▓</td><td style="text-align:center">242</td><td style="text-align:center">F2</td><td style="text-align:center">≥</td></tr><tr><td style="text-align:center">179</td><td style="text-align:center">B3</td><td style="text-align:center">│</td><td style="text-align:center">243</td><td style="text-align:center">F3</td><td style="text-align:center">≤</td></tr><tr><td style="text-align:center">180</td><td style="text-align:center">B4</td><td style="text-align:center">┤</td><td style="text-align:center">244</td><td style="text-align:center">F4</td><td style="text-align:center">?</td></tr><tr><td style="text-align:center">181</td><td style="text-align:center">B5</td><td style="text-align:center">╡</td><td style="text-align:center">245</td><td style="text-align:center">F5</td><td style="text-align:center">?</td></tr><tr><td style="text-align:center">182</td><td style="text-align:center">B6</td><td style="text-align:center">╢</td><td style="text-align:center">246</td><td style="text-align:center">F6</td><td style="text-align:center">÷</td></tr><tr><td style="text-align:center">183</td><td style="text-align:center">B7</td><td style="text-align:center">╖</td><td style="text-align:center">247</td><td style="text-align:center">F7</td><td style="text-align:center">≈</td></tr><tr><td style="text-align:center">184</td><td style="text-align:center">B8</td><td style="text-align:center">╕</td><td style="text-align:center">248</td><td style="text-align:center">F8</td><td style="text-align:center">≈</td></tr><tr><td style="text-align:center">185</td><td style="text-align:center">B9</td><td style="text-align:center">╣</td><td style="text-align:center">249</td><td style="text-align:center">F9</td><td style="text-align:center">?</td></tr><tr><td style="text-align:center">186</td><td style="text-align:center">BA</td><td style="text-align:center">║</td><td style="text-align:center">250</td><td style="text-align:center">FA</td><td style="text-align:center">·</td></tr><tr><td style="text-align:center">187</td><td style="text-align:center">BB</td><td style="text-align:center">╗</td><td style="text-align:center">251</td><td style="text-align:center">FB</td><td style="text-align:center">√</td></tr><tr><td style="text-align:center">188</td><td style="text-align:center">BC</td><td style="text-align:center">╝</td><td style="text-align:center">252</td><td style="text-align:center">FC</td><td style="text-align:center">?</td></tr><tr><td style="text-align:center">189</td><td style="text-align:center">BD</td><td style="text-align:center">╜</td><td style="text-align:center">253</td><td style="text-align:center">FD</td><td style="text-align:center">²</td></tr><tr><td style="text-align:center">190</td><td style="text-align:center">BE</td><td style="text-align:center">╛</td><td style="text-align:center">254</td><td style="text-align:center">FE</td><td style="text-align:center">■</td></tr><tr><td style="text-align:center">191</td><td style="text-align:center">BF</td><td style="text-align:center">┐</td><td style="text-align:center">255</td><td style="text-align:center">FF</td><td style="text-align:center">ÿ</td></tr></tbody></table>]]></content>
<summary type="html"><h1><strong>ASCII码表</strong></h1>
<table>
<thead>
<tr>
<th style="text-align:center"><strong>ASCII值</strong></th>
<th style="text-align:cent</summary>
<category term="操作系统" scheme="https://xiaolaji.site/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
<category term="Ascll码" scheme="https://xiaolaji.site/tags/Ascll%E7%A0%81/"/>
</entry>
<entry>
<title>操作系统课设——CentOS增加系统调用</title>
<link href="https://xiaolaji.site/20230612/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E8%AF%BE%E8%AE%BE%E2%80%94%E2%80%94CentOS%E5%A2%9E%E5%8A%A0%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8/"/>
<id>https://xiaolaji.site/20230612/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E8%AF%BE%E8%AE%BE%E2%80%94%E2%80%94CentOS%E5%A2%9E%E5%8A%A0%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8/</id>
<published>2023-06-13T02:24:07.000Z</published>
<updated>2023-08-14T19:23:03.000Z</updated>
<content type="html"><![CDATA[<h1>操作系统课设——CentOS增加系统调用</h1><h2 id="一、具体任务">一、具体任务</h2><p>采用编译内核法,在Linux中增加一个系统调用。</p><p>要求:</p><ol><li class="lvl-3"><p>系统调用实现的功能:计算一个数字的三次方, 并打印出来。</p></li><li class="lvl-3"><p>另外写一个程序进行调用</p></li></ol><p>相关思路:</p><p>本次实验实在CentOS 7系统中对于Linux内核源码进行修改,并对源码进行编译,最后完成切换内核操作,并在C语言程序中进行系统调用。</p><p>具体步骤:</p><ul class="lvl-0"><li class="lvl-2"><p>下载Linux 4.20.4版本的源码</p></li><li class="lvl-2"><p>安装所需的工具和相关的编译环境</p></li><li class="lvl-2"><p>对源码进行修改并增加功能</p></li><li class="lvl-2"><p>对原本的系统环境内进行系统调用的添加</p></li><li class="lvl-2"><p>进行Linux内核的编译</p></li><li class="lvl-2"><p>编写C语言程序并在其中对添加的功能进行验证</p></li></ul><h2 id="二、CentOS系统的安装">二、CentOS系统的安装</h2><p>本次系统安装采用了CentOS 7的系统,在VMware WorkStation中安装具体过程不在赘述,注意,尽量将CPU核数给多一些,以免编译的时间过长,建议存储空间大于40GB,防止出现内存不足的情况。</p><p><strong>注意:安装完成以及下面每一步进行记得一定要打上快照,否则出现错误重新操作异常困难,养成打快照的好习惯</strong></p><p><img src="image-20230613081816078.png" alt="CentOS安装完成示例"></p><h2 id="三、安装相关的系统环境">三、安装相关的系统环境</h2><p>使用yum包管理工具将编译需要的相关工具进行安装,为下一步编译进行准备</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo yum -y install ncurses-devel<br>sudo yum -y install bc<br>sudo yum -y install bison<br>sudo yum -y install flex<br>sudo yum -y install gcc g++ gdb make<br>sudo yum -y install centos-release-scl<br>sudo yum -y install devtoolset-7-gcc*<br>sudo yum -y install elfutils-libelf-devel<br>sudo yum -y install openssl-devel<br>sudo yum -y install zlib zlib-devel pcre pcre-devel gcc gcc-c++ openssl openssl-devel libevent libevent-devel perl unzip net-tools wget<br></code></pre></td></tr></table></figure><h2 id="四、对源码进行下载并修改">四、对源码进行下载并修改</h2><h3 id="下载源码">下载源码</h3><p>Linux的源码可以从其官方的网站下载,这里选择了Linux-4.20.4版本的源码</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 下载速度因人而异,我的网络环境比较好大概两三秒就下载完成了,也有人出现需要下载一两个小时的</span><br><span class="hljs-comment"># 建议采取一些措施改善一下网络环境</span><br>sudo wget http://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.20.4.tar.xz<br></code></pre></td></tr></table></figure><p><img src="image-20230613094521121.png" alt="源码下载完成"></p><h3 id="修改源码">修改源码</h3><p>刚才我们将源码下载到了我们当前用户的根目录下,一般的CentOS 7使用的应该是root用户进行登录的,那么此时你的下载的源包就在/root目录下。</p><p>修改/usr/src/kernels/linux-4.20.4/kernel/sys.c文件</p><p><img src="image-20230613094617052.png" alt="文件末尾添加自定义函数"></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">// 文件最后加入我们自己的功能调用</span><br>SYSCALL_DEFINE1(cube,<span class="hljs-type">int</span>,num){<br> <span class="hljs-type">int</span> result = num*num*num;<br> <span class="hljs-keyword">return</span> result;<br>}<br></code></pre></td></tr></table></figure><p>修改/usr/src/kernels/linux-4.20.4/arch/x86/include/asm/syscalls.h文件</p><p><img src="image-20230613094824243.png" alt="添加声明"></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">// 在这个文件内我们可以添加我们自己的声明</span><br><span class="hljs-comment">// 在/*kernel/ioport.c*/下下面进行添加</span><br>asmlinkage <span class="hljs-type">long</span> <span class="hljs-title function_">sys_cube</span><span class="hljs-params">(<span class="hljs-type">long</span> n)</span>;<br></code></pre></td></tr></table></figure><h2 id="五、添加系统调用号">五、添加系统调用号</h2><p>修改/usr/src/kernels/linux-4.20.4/arch/x86/entry/syscalls/syscall_64.tbl文件</p><p><img src="image-20230613094906717.png" alt="添加335号系统调用"></p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-comment"># 第一个是系统调用号</span><br><span class="hljs-attribute">335</span> <span class="hljs-number">64</span> cube __x64_sys_cube<br></code></pre></td></tr></table></figure><h2 id="六、准备并进行编译">六、准备并进行编译</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cp</span> /boot/config-3.10.0-1160.71.1.el7.x86_64 /usr/src/kernels/linux-4.20.4/.config<br>make menuconfig <span class="hljs-comment"># 对Config进行再设置</span><br></code></pre></td></tr></table></figure><p>这里注意,在make设置的时候,移动光标直接选择load,由于Linux会隐藏点开头的文件,.config以及刚刚我们复制过来的文件config文件只有<code>ll</code>命令才能看见,<code>ls</code>命令无法查看。</p><p><img src="image-20230613095404563.png" alt="make menuconfig"></p><p>选择load之后即可选择yes即可配置完成,将当前界面退出,使用<code>ll -a</code>命令我们可以发现原本的<code>.config</code>文件已经变成了<code>.config.old</code>,并且生成了一个新的<code>.config</code>文件,如下图。</p><p><img src="image-20230613215136957.png" alt="文件已经发生了变化"></p><p>下面我们可以进行编译了</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 进行编译 时间可能比较长 16指的是使用多少核心去执行编译 我自己的电脑分配了16核 大概需要20分钟 根据个人电脑动态调整核数</span><br>make -j16<br><span class="hljs-comment"># 安装模块和内核</span><br>make modules_install<br>make install<br><span class="hljs-comment"># 更新引导文件</span><br>grub2-mkconfig -o /boot/grub2/grub.cfg<br></code></pre></td></tr></table></figure><h2 id="七、写程序进行验证">七、写程序进行验证</h2><h3 id="编写验证程序">编写验证程序</h3><p>新建一个C语言程序test.c进行验证</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">// 输入以下代码</span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string"><linux/kernel.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string"><sys/syscall.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string"><unistd.h></span></span><br><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">()</span>{<br> <span class="hljs-type">double</span> n;<br> <span class="hljs-type">long</span> s;<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入一个数字:"</span>);<br> <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%lf"</span>,&n);<br> s=n*<span class="hljs-number">100</span>;<br> <span class="hljs-keyword">if</span>(s<<span class="hljs-number">0</span>){<br> s = -syscall(<span class="hljs-number">335</span>,-s);<br> }<br> <span class="hljs-keyword">else</span>{<br> s = syscall(<span class="hljs-number">335</span>,s);<br> }<br> n = s;<br> n = n / syscall(<span class="hljs-number">335</span>,<span class="hljs-number">100</span>);<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"结果为:"</span>);<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%lf"</span>,n);<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="测试结果">测试结果</h3><p><img src="image-20230613102024617.png" alt="验证结果"></p>]]></content>
<summary type="html"><h1>操作系统课设——CentOS增加系统调用</h1>
<h2 id="一、具体任务">一、具体任务</h2>
<p>采用编译内核法,在Linux中增加一个系统调用。</p>
<p>要求:</p>
<ol>
<li class="lvl-3">
<p>系统调用实现的功能:计算</summary>
<category term="操作系统" scheme="https://xiaolaji.site/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
<category term="课程设计" scheme="https://xiaolaji.site/tags/%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1/"/>
</entry>
<entry>
<title>软件工程知识点整理</title>
<link href="https://xiaolaji.site/20230608/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B%E7%9F%A5%E8%AF%86%E7%82%B9%E6%95%B4%E7%90%86/"/>
<id>https://xiaolaji.site/20230608/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B%E7%9F%A5%E8%AF%86%E7%82%B9%E6%95%B4%E7%90%86/</id>
<published>2023-06-08T22:19:43.000Z</published>
<updated>2023-07-10T05:53:45.000Z</updated>
<content type="html"><![CDATA[<h1>软件工程知识点整理</h1><h2 id="声明">声明</h2><p>此份复习资料适合于江苏大学计算机学院软件工程课程,该资料为作者自己整理,如有整理不好之处请多包涵🫡</p><h2 id="第-1-章-软件工程学概述">第 1 章 软件工程学概述</h2><h3 id="什么是软件危机?它有哪些典型表现?为什么会出现软件危机?(选择题、判断题、简答题)">什么是软件危机?它有哪些典型表现?为什么会出现软件危机?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>软件危机是在计算机软件开发和维护过程中所遇到的一系列严重问题</p></li><li class="lvl-3"><p>典型表现:</p><ul class="lvl-2"><li class="lvl-5">对软件开发成本和进度的估计常常很不准确</li><li class="lvl-5">用户对“已完成的”软件系统不满意的现象常常发生</li><li class="lvl-5">软件产品的质量往往靠不住</li><li class="lvl-5">软件常常是不可维护的</li><li class="lvl-5">软件通常没有适当的文档资料</li><li class="lvl-5">软件成本在计算机系统总成本中所占的比例逐年上升</li><li class="lvl-5">软件开发生产率提高的速度远远跟不上计算机应用迅速普及深入的趋势</li></ul></li><li class="lvl-3"><p>为什么出现软件危机:</p><ul class="lvl-2"><li class="lvl-5">对用户要求没有完整准确的认识就匆忙着手编写程序</li></ul></li></ol><h3 id="什么是软件过程?什么是软件工程?什么是软件工程方法学?(选择题、判断题、简答题)">什么是软件过程?什么是软件工程?什么是软件工程方法学?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>软件过程是为了获得高质量软件所需要完成的一系列任务的框架,他规定了完成各项任务的工作步骤</p></li><li class="lvl-3"><p>软件工程是指导计算机软件开发和维护的一门工程学科</p></li><li class="lvl-3"><p>通常在软件生命周期全过程中使用的一整套技术方法的集合称为方法学,也叫做范型</p><ul class="lvl-2"><li class="lvl-5">软件工程方法学包含三个要素<ol><li class="lvl-8">方法</li><li class="lvl-8">工具</li><li class="lvl-8">过程</li></ol></li></ul></li></ol><h3 id="简述结构化范型和面向对象范型的要点,并分析它们的优缺点。(选择题、判断题、简答题)">简述结构化范型和面向对象范型的要点,并分析它们的优缺点。(选择题、判断题、简答题)</h3><ul class="lvl-0"><li class="lvl-2"><p>结构化范型</p><ul class="lvl-2"><li class="lvl-4">优点:面向过程或者面向数据</li><li class="lvl-4">缺点:增加了软件开发和维护的难度</li></ul></li><li class="lvl-2"><p>面向对象范型</p><ul class="lvl-2"><li class="lvl-4">四个要点<ol><li class="lvl-7">把对象作为了融合数据及在数据上的操作行为为统一的软件构件</li><li class="lvl-7">把所有对象都划分成类</li><li class="lvl-7">按照父类与子类的关系把若干个相关类组成了一个具有层次结构的系统</li><li class="lvl-7">对象彼此之间仅能通过发送消息互相联系</li></ol></li><li class="lvl-4">面向对象方法学的方法?</li><li class="lvl-4">面向对象方法学的特征?</li></ul></li></ul><h3 id="简述软件生命周期每个阶段的基本任务?(选择题、判断题、简答题)">简述软件生命周期每个阶段的基本任务?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>问题定义</p><ul class="lvl-2"><li class="lvl-5">明确需要解决的问题是什么</li></ul></li><li class="lvl-3"><p>可行性研究</p><ul class="lvl-2"><li class="lvl-5">对于上个阶段确定的问题有没有行得通的解决办法</li></ul></li><li class="lvl-3"><p>需求分析</p><ul class="lvl-2"><li class="lvl-5">为了解决这个问题,目标系统需要做什么</li></ul></li><li class="lvl-3"><p>总体设计</p><ul class="lvl-2"><li class="lvl-5">应该怎样实现目标系统</li></ul></li><li class="lvl-3"><p>详细设计</p><ul class="lvl-2"><li class="lvl-5">总体设计节点使用比较抽象的方式表述了解决问题的办法,该阶段将办法具体化</li></ul></li><li class="lvl-3"><p>编码和单元测试</p><ul class="lvl-2"><li class="lvl-5">写出正确的容易理解、容易维护的程序模块</li></ul></li><li class="lvl-3"><p>综合测试</p><ul class="lvl-2"><li class="lvl-5">通过各种类型的测试是软件到达预定的效果</li></ul></li><li class="lvl-3"><p>软件维护</p><ul class="lvl-2"><li class="lvl-5">通过各种必要的维护活动使系统持久的满足用户的需求</li></ul></li></ol><h3 id="什么是软件生命周期模型?试比较瀑布模型、快速原型模型、增量模型、螺旋模型的优缺点,说明每种模型的适用范围。(选择题、判断题、简答题)">什么是软件生命周期模型?试比较瀑布模型、快速原型模型、增量模型、螺旋模型的优缺点,说明每种模型的适用范围。(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>软件周期模型规定了把生命周期划分成哪些阶段及各个阶段的执行顺序,因此也称为过程模型</p></li><li class="lvl-3"><p>各种模型的分析(书15~19页)</p><ul class="lvl-2"><li class="lvl-5">瀑布模型<ul class="lvl-4"><li class="lvl-7">优点<ol><li class="lvl-10">强迫开发人员使用规范的方法</li><li class="lvl-10">严格规划了每个阶段必须提交的文档</li><li class="lvl-10">要求每个阶段交出的所有产品必须经过质量保证小组的仔细验证</li></ol></li><li class="lvl-7">缺点<ol><li class="lvl-10">瀑布模型是由文档驱动的</li></ol></li></ul></li><li class="lvl-5">快速原型模型<ul class="lvl-4"><li class="lvl-7">优点<ol><li class="lvl-10">软件开发基本是线性顺序进行的</li></ol></li><li class="lvl-7">缺点<ol><li class="lvl-10">无法完全预测未来设计的问题</li></ol></li></ul></li><li class="lvl-5">增量模型<ul class="lvl-4"><li class="lvl-7">优点<ol><li class="lvl-10">较短时间内向用户提交可完成部分工作的产品</li><li class="lvl-10">逐步增加产品功能可以使用户具有充裕时间学习和适应新产品,减少全新软件可能带给客户组织带来冲击</li></ol></li><li class="lvl-7">缺点<ol><li class="lvl-10">把每个新的增量构件集成到现有软件体系结构中时,必须不破坏原来已经开发出来的产品</li><li class="lvl-10">对开发人员的技术要求比较高</li></ol></li></ul></li><li class="lvl-5">螺旋模型<ul class="lvl-4"><li class="lvl-7">优点<ol><li class="lvl-10">对可选方案和约束条件的强调有利于已有软件的重用,有助于把软件质量作为软件开发的一个重要目标</li><li class="lvl-10">减少过多测试或者测试不足带来的风险</li><li class="lvl-10">螺旋模型中维护只是模型的另一个周期,维护和开发之间并没有本质区别</li></ol></li><li class="lvl-7">缺点<ol><li class="lvl-10">由于其是风险驱动的,软件开发人员必须具备风险评估的经验和该方面的专门知识</li></ol></li></ul></li></ul></li></ol><h2 id="第-2-章-可行性研究">第 2 章 可行性研究</h2><h3 id="可行性研究的目的和任务是什么?从哪些方面研究目标系统的可行性?(选择题、判断题、简答题)">可行性研究的目的和任务是什么?从哪些方面研究目标系统的可行性?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>目的和任务:用最小的代价在尽可能短的时间内确定问题是否可以被解决</p></li><li class="lvl-3"><p>哪几个方面</p><ol><li class="lvl-6">技术可行性</li><li class="lvl-6">经济可行性</li><li class="lvl-6">操作可行性</li></ol></li></ol><h3 id="系统流程图的常用符号及含义(选择题、判断题)">系统流程图的常用符号及含义(选择题、判断题)</h3><p>这是一个用于描述物理层面上的操作过程的图</p><p><img src="b8b850a86aafeb32f502817acb61c09.jpg" alt=""></p><h3 id="什么是数据流图、数据字典,在可行性分析阶段,它们分别描述系统的哪些方面?它们之间有何联系?(选择题、判断题、简答题)">什么是数据流图、数据字典,在可行性分析阶段,它们分别描述系统的哪些方面?它们之间有何联系?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>数据字典</p><ul class="lvl-2"><li class="lvl-5">关于数据的信息的集合,也就是对数据流图中包含的所有元素定义的集合</li><li class="lvl-5"></li></ul></li><li class="lvl-3"><p>数据流图</p><ul class="lvl-2"><li class="lvl-5">描述信息流和数据从输入移动到输出的过程中所经受的变换的图形化技术</li></ul></li><li class="lvl-3"><p>相互关系</p><ul class="lvl-2"><li class="lvl-5">数据流图和数据字典共同构成系统的逻辑模型,没有数据字典,数据流图就不严格,然而没有数据流图,数据字典也难以发挥作用。只有数据流图和对数据流图中的每一个元素的精确定义放在一起才能共同构成系统的规格说明。</li></ul></li></ol><h3 id="设计数据流图、数据字典,难度不超过书后习题(应用题)">设计数据流图、数据字典,难度不超过书后习题(应用题)</h3><ul class="lvl-0"><li class="lvl-2"><p>数据流图可以参考书44页两张图</p></li><li class="lvl-2"><p>符号规定与41页</p></li><li class="lvl-2"><p>相关习题见平时作业</p></li></ul><h2 id="第-3-章-需求分析">第 3 章 需求分析</h2><h3 id="为什么要进行需求分析-通常对软件系统有哪些需求?(选择题、判断题、简答题)">为什么要进行需求分析?通常对软件系统有哪些需求?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>为了开发出真正满足用户需求的产品软件,首先必须知道用户的需求</p></li><li class="lvl-3"><p>具体需求</p><ul class="lvl-2"><li class="lvl-5">功能需求</li><li class="lvl-5">性能需求</li><li class="lvl-5">可靠性和可用性需求</li><li class="lvl-5">出错处理需求</li><li class="lvl-5">接口需求</li><li class="lvl-5">约束</li><li class="lvl-5">逆向需求</li><li class="lvl-5">将来可能提出的要求</li></ul></li></ol><h3 id="需求分析的任务。(选择题、判断题)">需求分析的任务。(选择题、判断题)</h3><ul class="lvl-0"><li class="lvl-2"><p>确定对系统的总和要求</p></li><li class="lvl-2"><p>分析系统的数据要求</p></li><li class="lvl-2"><p>导出系统的逻辑模型</p></li><li class="lvl-2"><p>修正系统开发计划</p></li></ul><h3 id="需求分析过程应该建立-3-种模型,各有什么作用?(选择题、判断题)">需求分析过程应该建立 3 种模型,各有什么作用?(选择题、判断题)</h3><ol><li class="lvl-3"><p>数据模型</p><ul class="lvl-2"><li class="lvl-5">描绘数据对象及数据对象之间的关系</li></ul></li><li class="lvl-3"><p>功能模型</p><ul class="lvl-2"><li class="lvl-5">描绘当数据在软件系统中移动时被变换的逻辑过程,指明系统具备变换数据功能</li></ul></li><li class="lvl-3"><p>行为模型</p><ul class="lvl-2"><li class="lvl-5">指明了作为外部事件结果的系统行为,描绘了系统的各种行为模式和在不同状态间转换的方式</li></ul></li></ol><h3 id="ER-图(选择题、判断题、应用题)">ER 图(选择题、判断题、应用题)</h3><ul class="lvl-0"><li class="lvl-2"><p>书64页 实体-联系图</p></li></ul><h3 id="状态转换图(课后习题)(应用题)">状态转换图(课后习题)(应用题)</h3><ul class="lvl-0"><li class="lvl-2"><p>书67页 课后习题</p></li></ul><h3 id="层次方框图和-IPO-图的作用(选择题、判断题)">层次方框图和 IPO 图的作用(选择题、判断题)</h3><ul class="lvl-0"><li class="lvl-2"><p>层次方框图(68页)</p><ul class="lvl-2"><li class="lvl-4">用树形结构的一系列多层次的矩形框描绘数据的层次结构</li></ul></li><li class="lvl-2"><p>IPO图(69页)</p><ul class="lvl-2"><li class="lvl-4">描绘输入数据、对数据的处理和输出数据之间的关系</li></ul></li></ul><h2 id="第-5-章-总体设计">第 5 章 总体设计</h2><h3 id="总体设计过程通常由两个主要阶段组成-系统设计阶段-确定系统的-具体实现方案-结构设计阶段-确定软件结构。典型的总体设计过程-包括下述-9-个步骤。(选择题、判断题)">总体设计过程通常由两个主要阶段组成:系统设计阶段,确定系统的 具体实现方案;结构设计阶段,确定软件结构。典型的总体设计过程 包括下述 9 个步骤。(选择题、判断题)</h3><ol><li class="lvl-3"><p>设想供选择的方案、</p></li><li class="lvl-3"><p>选取合适的方案</p></li><li class="lvl-3"><p>推荐最佳方案</p></li><li class="lvl-3"><p>功能分解</p></li><li class="lvl-3"><p>设计软件结构</p></li><li class="lvl-3"><p>设计数据库</p></li><li class="lvl-3"><p>制定测试计划</p></li><li class="lvl-3"><p>书写文档</p></li><li class="lvl-3"><p>审查和复审</p></li></ol><h3 id="在总体设计阶段,模块化、抽象、逐步求精和信息隐藏是通常应该遵循的一些基本原理,简要说明这些原理所表达的思想?-什么是耦合?什么是内聚?衡量模块独立性的标准又是什么?(选择题、判断题、-简答题)">在总体设计阶段,模块化、抽象、逐步求精和信息隐藏是通常应该遵循的一些基本原理,简要说明这些原理所表达的思想? 什么是耦合?什么是内聚?衡量模块独立性的标准又是什么?(选择题、判断题、 简答题)</h3><ul class="lvl-0"><li class="lvl-2"><p>94页~99页</p></li></ul><h3 id="根据数据流图设计软件的结构图(选择题、判断题、-应用题)">根据数据流图设计软件的结构图(选择题、判断题、 应用题)</h3><ul class="lvl-0"><li class="lvl-2"><p>111页</p></li></ul><h2 id="第-6-章-详细设计">第 6 章 详细设计</h2><h3 id="详细设计阶段的任务还不是具体地编写程序-而是要设计出程序的-“蓝图”-以后程序员将根据这个“蓝图”写出实际的程序代码(选择题、判断题)">详细设计阶段的任务还不是具体地编写程序,而是要设计出程序的 “蓝图”,以后程序员将根据这个“蓝图”写出实际的程序代码(选择题、判断题)</h3><ul class="lvl-0"><li class="lvl-2"><p>该题目就是考点</p></li></ul><h3 id="什么叫结构程序设计?(选择题、判断题、简答题)">什么叫结构程序设计?(选择题、判断题、简答题)</h3><ul class="lvl-0"><li class="lvl-2"><p>如果一个程序的代码块仅仅通过顺序、选择和循环着三种基本控制结构进行连接,并且每个代码块只有一个入口和一个出口,则称这个程序是结构化的</p></li></ul><h3 id="程序流程图、盒图和判定表是详细设计过程中常用的图形表达工具,请分别说明它们各自的功用和特点?(选择题、判断题)">程序流程图、盒图和判定表是详细设计过程中常用的图形表达工具,请分别说明它们各自的功用和特点?(选择题、判断题)</h3><ul class="lvl-0"><li class="lvl-2"><p>程序流程图</p><ul class="lvl-2"><li class="lvl-4">功用<ul class="lvl-4"><li class="lvl-6">描述过程设计的方法</li></ul></li><li class="lvl-4">特点<ul class="lvl-4"><li class="lvl-6">优点:<ul class="lvl-6"><li class="lvl-8">对控制流程的描述直观</li></ul></li><li class="lvl-6">缺点:<ul class="lvl-6"><li class="lvl-8">诱使程序员过早的考虑程序的控制流程而不去考虑程序的全局结构</li><li class="lvl-8">使用箭头代表控制流,因此程序员不受任何约束,可以完全不顾结构程序设计的精神,随意转移控制</li><li class="lvl-8">不易表示数据结构</li></ul></li></ul></li></ul></li><li class="lvl-2"><p>盒图</p><ul class="lvl-2"><li class="lvl-4">特点<ul class="lvl-4"><li class="lvl-6">功能域明确</li><li class="lvl-6">不可能随意转移控制</li><li class="lvl-6">很容易确定局部和全局数据的作用域</li><li class="lvl-6">很容易表现出嵌套关系,也可以表示模块的层次结构</li></ul></li></ul></li><li class="lvl-2"><p>判定表</p><ul class="lvl-2"><li class="lvl-4">功用<ul class="lvl-4"><li class="lvl-6">清晰的表示复杂的条件组合与应做的动作之间的对应关系</li></ul></li></ul></li></ul><h3 id="程序流程图、盒图和判定表(难度不超过书后习题)(应用题)">程序流程图、盒图和判定表(难度不超过书后习题)(应用题)</h3><ul class="lvl-0"><li class="lvl-2"><p>平时作业题</p></li></ul><h3 id="Jackson-图的特点(选择题、判断题)">Jackson 图的特点(选择题、判断题)</h3><ul class="lvl-0"><li class="lvl-2"><p>便于表示层次结构,而且对目录进行自定向下分解的有力工具</p></li><li class="lvl-2"><p>形象直观可读性好</p></li><li class="lvl-2"><p>既能表示数据结构也能表示程序结构</p></li></ul><p>详细设计除了应该保证软件的可靠性之外,使将来编写出的程序可读性好﹑容易理解、容易测试、容易修改和维护,是详细设计阶段最 重要的目标。 过程设计应该在数据设计.体系结构设计和接口设计完成之后进行, 它的任务是设计解题的详细步骤(即算法),它是详细设计阶段应完 成的主要工作。过程设计的工具可分为图形、表格和语言 3 类,这 3 类工具各有所长,读者应该能够根据需要选用适当的工具(选择题、判断题)</p><h2 id="第-7-章-实现">第 7 章 实现</h2><h3 id="软件测试在软件生命周期中横跨两个阶段。通常在编写出每个模块-之后就对它做必要的测试-称为单元测试-模块的编写者和测试者是-同一个人-编码和单元测试属于软件生命周期的同一个阶段。(选择题、判断题)">软件测试在软件生命周期中横跨两个阶段。通常在编写出每个模块 之后就对它做必要的测试(称为单元测试),模块的编写者和测试者是 同一个人,编码和单元测试属于软件生命周期的同一个阶段。(选择题、判断题)</h3><h3 id="测试的目的就是在软件投入生产性运行之前-尽可能多地发现软件中的错误。(选择题、判断题)">测试的目的就是在软件投入生产性运行之前,尽可能多地发现软件中的错误。(选择题、判断题)</h3><h3 id="何谓白盒测试、黑盒测试?在两种测试中采用的最重要的技术有哪些?(选择题、判断题、简答题)">何谓白盒测试、黑盒测试?在两种测试中采用的最重要的技术有哪些?(选择题、判断题、简答题)</h3><ul class="lvl-0"><li class="lvl-2"><p>白盒测试</p><ul class="lvl-2"><li class="lvl-4">知道产品内部工作过程,通过测试来检验内部动作是否按照规格说明书上的规定正常进行</li><li class="lvl-4">测试技术:<ul class="lvl-4"><li class="lvl-6">逻辑覆盖</li><li class="lvl-6">控制结构测试</li></ul></li></ul></li><li class="lvl-2"><p>黑盒测试</p><ul class="lvl-2"><li class="lvl-4">已经知道产品应具备的功能,通过测试来检验每个功能都能正常使用</li><li class="lvl-4">测试技术<ul class="lvl-4"><li class="lvl-6">等价划分</li><li class="lvl-6">边界值分析</li><li class="lvl-6">错误推测</li></ul></li></ul></li></ul><h3 id="单元测试期间着重从哪-5-个方面对模块进行测试?(选择题、判断题)">单元测试期间着重从哪 5 个方面对模块进行测试?(选择题、判断题)</h3><ol><li class="lvl-3"><p>模块接口</p></li><li class="lvl-3"><p>局部数据结构</p></li><li class="lvl-3"><p>重要的执行通路</p></li><li class="lvl-3"><p>出错处理通路</p></li><li class="lvl-3"><p>边界条件</p></li></ol><h3 id="自顶向下集成测试和自底向上集成测试有什么区别?-什么是α测试和β测试-(选择题、判断题、简答题)">自顶向下集成测试和自底向上集成测试有什么区别? 什么是α测试和β测试?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>自顶向下:从主控模块开始沿着程序的控制层次向下移动,逐渐把各个模块结合起来。</p></li><li class="lvl-3"><p>自底向上:从“原子模块”开始组装和测试</p></li><li class="lvl-3"><p>α测试:由用户在开发者擦和场所进行,并且在开发者对用户的“指导”下进行测试,开发者负责记录发现的错误和使用中遇到的问题</p></li><li class="lvl-3"><p>β测试:由软件的最终用户们在一个或多个客户场所进行,开发者通常不在测试的现场。</p></li></ol><h3 id="设计逻辑覆盖的测试用例(判断题、应用题)(重点)">设计逻辑覆盖的测试用例(判断题、应用题)(重点)</h3><p>书162页</p><h3 id="能区分等价划分、边界值分析、错误推测(选择题、判断题)">能区分等价划分、边界值分析、错误推测(选择题、判断题)</h3><ul class="lvl-0"><li class="lvl-2"><p>考点</p></li></ul><h3 id="什么是测试用例(选择题、判断题)">什么是测试用例(选择题、判断题)</h3><ul class="lvl-0"><li class="lvl-2"><p>测试用例是针对软件应用程序或系统的特定功能而编写的一系列步骤,旨在评估其是否按照预期进行操作。</p></li></ul><h2 id="第-8-章-维护">第 8 章 维护</h2><h3 id="软件维护需要的工作量很大-平均说来-大型软件的维护成本高达开发成本的-4-倍左右(选择题、判断题)">软件维护需要的工作量很大,平均说来,大型软件的维护成本高达开发成本的 4 倍左右(选择题、判断题)</h3><h3 id="软件维护的定义?四类维护活动是什么?哪种活动比例最大、最小(选择题、判断题)">软件维护的定义?四类维护活动是什么?哪种活动比例最大、最小(选择题、判断题)</h3><ol><li class="lvl-3"><p>软件维护就是在软件已经交付使用之后,为了改正错误或者满足新的需求而要修改软件的过程</p></li><li class="lvl-3"><p>四类维护活动:</p><ul class="lvl-2"><li class="lvl-5">完善性维护(50%~66%)(最大)</li><li class="lvl-5">改正性维护(17%~21%)</li><li class="lvl-5">适应性维护(18%~25%)</li><li class="lvl-5">预防性维护(4%)(最小)</li></ul></li></ol><h3 id="什么是结构化维护?结构化维护的特点是什么?(选择题、判断题、简答题)">什么是结构化维护?结构化维护的特点是什么?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>如果有一个特定的软件配置存在,维护工作从评价设计文档开始,确定软件重要的结构特点、性能特点及接口特点;估量重要的改动将带来的影响,并计划实施途径,然后首次修改设计并且对做出的修改进行仔细复查。接下来编写相应的源程序代码;使用在测试说明书中包含的信息进行回归测试;最后把修改的软件再次交付使用。</p></li><li class="lvl-3"><p>特点:</p><ul class="lvl-2"><li class="lvl-5">减少精力的浪费</li><li class="lvl-5">提高维护的总体质量</li></ul></li></ol><h3 id="根据维护阶段的事件流,第一件事是?最后一件是?(选择题、判断题)">根据维护阶段的事件流,第一件事是?最后一件是?(选择题、判断题)</h3><ol><li class="lvl-3"><p>第一件事:确定要求进行的维护的类型</p></li><li class="lvl-3"><p>最后一件事情:复审</p></li></ol><h3 id="软件的可维护性与哪些因素有关-在软件开发过程中应该采取哪些措施来提高软件产品的可维护性-(选择题、判断题、简答题)">软件的可维护性与哪些因素有关?在软件开发过程中应该采取哪些措施来提高软件产品的可维护性?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>有关因素:</p><ul class="lvl-2"><li class="lvl-5">可理解性</li><li class="lvl-5">可测试性</li><li class="lvl-5">可修改性</li><li class="lvl-5">可移植性</li><li class="lvl-5">可重用性</li></ul></li><li class="lvl-3"><p>在每个阶段结束前的技术审查和管理复查中,应该着重对可维护性进行复审过程中,应该对将来要改进的部分和可能要改进的部分加以注意指明。应在讨论软件的可移植性问题,考虑可能影响软件维护的系统界面。在设计和编码过程中应该尽可能使用可重用的软件构件,每个测试步骤都可以暗示在软件正式交付使用之前,程序中可能需要做预防性维护的部分。在完成每项维护工作之后,都应该对软件维护本身仔细认真地复审。</p></li></ol><h3 id="什么是逆向工程?什么是代码重构?(选择题、判断题)">什么是逆向工程?什么是代码重构?(选择题、判断题)</h3><ol><li class="lvl-3"><p>分析程序以便在比源代码更高的抽象层次上创建出程序的某种表示过程</p></li><li class="lvl-3"><p>不修改整体程序体系结构,仅关注个体模块的设计细节以及在模块中定义的局部数据结构的再生程序活动</p></li></ol><h3 id="预防性维护实质上是软件再工程。典型的软件再工程过程模型定义-了库存目录分析、文档重构、逆向工程、代码重构﹑数据重构和正-向工程-6-类活动(选择题、判断题)">预防性维护实质上是软件再工程。典型的软件再工程过程模型定义 了库存目录分析、文档重构、逆向工程、代码重构﹑数据重构和正 向工程 6 类活动(选择题、判断题)</h3><h2 id="第-9-章-面向对象方法学引论">第 9 章 面向对象方法学引论</h2><h3 id="什么是模型-开发软件为何要建模-(选择题、判断题)">什么是模型?开发软件为何要建模?(选择题、判断题)</h3><ol><li class="lvl-3"><p>为了理解事物而对事物作出的一种抽象,是对事物的一种无歧义的书面描述</p></li><li class="lvl-3"><p>对目标系统进行分析的初始阶段,面对大量模糊的、涉及众多专业领域的、错综复杂的信息,系统信息员往往感到无从下手,模型提供了组织大量信息的一种有效机制。</p></li></ol><h3 id="什么是面向对象方法学-它有哪些优点-(选择题、判断题、简答题)">什么是面向对象方法学?它有哪些优点?(选择题、判断题、简答题)</h3><ol><li class="lvl-3"><p>什么是?</p></li><li class="lvl-3"><p>优点:</p><ul class="lvl-2"><li class="lvl-5">与人类习惯的思维方法一致</li><li class="lvl-5">稳定性好</li><li class="lvl-5">可重用性好</li><li class="lvl-5">较易开发大型软件产品</li><li class="lvl-5">可维护性好</li></ul></li></ol><h3 id="类、对象、实例这三个概念的区别?(选择题、判断题、简答题)">类、对象、实例这三个概念的区别?(选择题、判断题、简答题)</h3><ul class="lvl-0"><li class="lvl-2"><p>类->对象->实例</p></li></ul><h3 id="3-种模型的作用?(选择题、判断题)">3 种模型的作用?(选择题、判断题)</h3><ol><li class="lvl-3"><p>描述系统数据结构的对象模型</p></li><li class="lvl-3"><p>描述系统控制结构的动态模型</p></li><li class="lvl-3"><p>描述系统功能的功能模型</p></li></ol><h3 id="类及类与类之间的-4-种关系,图形符号(选择题、判断题)">类及类与类之间的 4 种关系,图形符号(选择题、判断题)</h3><ol><li class="lvl-3"><p>关联</p><p><img src="image-20230606005611265.png" alt=""></p></li><li class="lvl-3"><p>聚集</p><p><img src="image-20230606005635238.png" alt=""></p></li><li class="lvl-3"><p>泛化</p><p><img src="image-20230606005701686.png" alt=""></p></li><li class="lvl-3"><p>依赖和细化</p><p><img src="image-20230606005723282.png" alt=""></p></li></ol><h3 id="简单的用例图的画法(应用题)">简单的用例图的画法(应用题)</h3><ul class="lvl-0"><li class="lvl-2"><p>见相关习题</p></li></ul><h3 id="数据流图和对象模型之间的关系(选择题、判断题)">数据流图和对象模型之间的关系(选择题、判断题)</h3><ul class="lvl-0"><li class="lvl-2"><p>数据流图用于描述系统的数据流动和处理流程,而对象模型用于描述系统的对象、类别和它们之间的关系。</p></li></ul><h2 id="第-10-章-面向对象分析">第 10 章 面向对象分析</h2><h3 id="不论采用哪种方法开发软件-分析的过程都是提取系统需求的过程。-分析工作主要包括-3-项内容-这就是理解、表达和验证。-面向对象分析-OOA-的关键是识别出问题域内的类与对象-在用面-向对象观点建立起的-3-种模型中-对象模型是最基本、最重要、最核-心的。">不论采用哪种方法开发软件,分析的过程都是提取系统需求的过程。 分析工作主要包括 3 项内容,这就是理解、表达和验证。 面向对象分析(OOA)的关键是识别出问题域内的类与对象,在用面 向对象观点建立起的 3 种模型中,对象模型是最基本、最重要、最核 心的。</h3><h3 id="面向对象建模-3-个子模型与-5-个层次是什么?主题层的作用?">面向对象建模 3 个子模型与 5 个层次是什么?主题层的作用?</h3><ul class="lvl-0"><li class="lvl-2"><p>三个子模型</p><ol><li class="lvl-5">描述系统数据结构的对象模型</li><li class="lvl-5">描述系统控制结构的动态模型</li><li class="lvl-5">描述系统功能的功能模型</li></ol></li><li class="lvl-2"><p>五个层次</p><ol><li class="lvl-5">主题层<ul class="lvl-4"><li class="lvl-7">控制可见性和指导读者注意力</li></ul></li><li class="lvl-5">类与对象层</li><li class="lvl-5">结构层</li><li class="lvl-5">属性层</li><li class="lvl-5">服务层</li></ol></li></ul><h3 id="面向对象分析时,为了确定类与对象,经常采用一种非正式分析法,-其基本思路是什么?采用该方法建立系统的对象模型。-难度与本章习题第-4-题相当">面向对象分析时,为了确定类与对象,经常采用一种非正式分析法, 其基本思路是什么?采用该方法建立系统的对象模型。 难度与本章习题第 4 题相当</h3><ol><li class="lvl-3"><p>非正式分析法:</p><ul class="lvl-2"><li class="lvl-5">以自然语言书写的需求陈述作为依据,把陈述中的名词作为类与对象的候选者,用形容词作为确定属性的线索,把动词作为服务(操作)的候选者。</li></ul></li><li class="lvl-3"><p>习题见作业</p></li></ol><h3 id="动态模型和功能模型在作业中完成,不列入考试范围">动态模型和功能模型在作业中完成,不列入考试范围</h3><ul class="lvl-0"><li class="lvl-2"><p>该考点不考</p></li></ul><h2 id="平时作业答案整理">平时作业答案整理</h2><h3 id="第一次作业">第一次作业</h3><h4 id="作业内容">作业内容</h4><p>P32页 第1题</p><p><img src="image-20230607200338381.png" alt=""></p><p>P32页 第3题</p><p><img src="image-20230607200356988.png" alt=""></p><p>P32页 第4题</p><p><img src="image-20230607200412224.png" alt=""></p><p>P33页 第6题</p><p><img src="image-20230607200430524.png" alt=""></p><p>P33页 第7题</p><p><img src="image-20230607200515933.png" alt=""></p><h3 id="第二次作业">第二次作业</h3><h4 id="作业内容-2">作业内容</h4><p>P54页第5题</p><p><img src="image-20230607200829728.png" alt=""></p><p>P73页第1题</p><p><img src="image-20230607200910030.png" alt=""></p><p>P73页第3题</p><p><img src="image-20230607201050997.png" alt=""></p><p>P73页第4题</p><p><img src="image-20230607201112128.png" alt=""></p><p><img src="image-20230607201125137.png" alt=""></p><p>P73页第5题</p><p><img src="image-20230607201138712.png" alt=""></p><p>P73页第6题</p><p><img src="image-20230607201205468.png" alt=""></p><h3 id="第三次作业">第三次作业</h3><h4 id="作业内容-3">作业内容</h4><p>P114页第3题</p><p>P140页第3题</p><p><img src="image-20230607202233079.png" alt=""></p><p><img src="image-20230607202245280.png" alt=""></p><p>P140页第4题</p><p><img src="image-20230607202304931.png" alt=""></p><p><img src="image-20230607202317941.png" alt=""></p><p>P142页第7题</p><p><img src="image-20230607202338189.png" alt=""></p><p><img src="image-20230607202352031.png" alt=""></p><p><img src="image-20230607202404630.png" alt=""></p><h3 id="第四次作业">第四次作业</h3><h4 id="作业内容-4">作业内容</h4><p>P184页第2题</p><p><img src="image-20230607202621583.png" alt=""></p><p><img src="image-20230607202634550.png" alt=""></p><p><img src="image-20230607202702250.png" alt=""></p><p>P184页第4题(1)(3)</p><p><img src="image-20230607202738993.png" alt=""><img src="image-20230607202748435.png" alt=""><img src="image-20230607202816345.png" alt=""><img src="image-20230607202836185.png" alt=""></p><p>P185页第6题</p><p><img src="image-20230607202855537.png" alt=""></p><p>P201页第1题</p><p><img src="image-20230607202919021.png" alt=""></p><h3 id="第五次作业">第五次作业</h3><h4 id="作业内容-5">作业内容</h4><p>P229页第2题</p><p><img src="image-20230607203101076.png" alt=""></p><p>P229页第3题</p><p><img src="image-20230607203108411.png" alt=""></p><p>P229页第4题</p><p><img src="image-20230607203116504.png" alt=""></p><p>P229页第6题</p><p><img src="image-20230607203124830.png" alt=""></p><p>P229页第9题</p><p><img src="image-20230607203136571.png" alt=""></p><p>P229页第10题</p><p><img src="image-20230607203146492.png" alt=""></p><p>P256页第1题</p><p><img src="image-20230607203212579.png" alt=""></p>]]></content>
<summary type="html"><h1>软件工程知识点整理</h1>
<h2 id="声明">声明</h2>
<p>此份复习资料适合于江苏大学计算机学院软件工程课程,该资料为作者自己整理,如有整理不好之处请多包涵🫡</p>
<h2 id="第-1-章-软件工程学概述">第 1 章 软件工程学概述</h2>
<</summary>
<category term="软件工程" scheme="https://xiaolaji.site/categories/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B/"/>
<category term="大学学习" scheme="https://xiaolaji.site/tags/%E5%A4%A7%E5%AD%A6%E5%AD%A6%E4%B9%A0/"/>
</entry>
<entry>
<title>此博客网站的诞生</title>
<link href="https://xiaolaji.site/20230423/%E6%AD%A4%E5%8D%9A%E5%AE%A2%E7%BD%91%E7%AB%99%E7%9A%84%E8%AF%9E%E7%94%9F/"/>
<id>https://xiaolaji.site/20230423/%E6%AD%A4%E5%8D%9A%E5%AE%A2%E7%BD%91%E7%AB%99%E7%9A%84%E8%AF%9E%E7%94%9F/</id>
<published>2023-04-23T17:23:16.000Z</published>
<updated>2023-06-13T08:02:34.000Z</updated>
<content type="html"><![CDATA[<h1>从今天开始小垃圾的博客正式升级为星陨的博客</h1>]]></content>
<summary type="html"><h1>从今天开始小垃圾的博客正式升级为星陨的博客</h1>
</summary>
<category term="Fluid" scheme="https://xiaolaji.site/categories/Fluid/"/>
<category term="介绍该博客" scheme="https://xiaolaji.site/tags/%E4%BB%8B%E7%BB%8D%E8%AF%A5%E5%8D%9A%E5%AE%A2/"/>
</entry>
<entry>
<title>Java中的Static关键字</title>
<link href="https://xiaolaji.site/20230114/Java%E4%B8%AD%E7%9A%84Static%E5%85%B3%E9%94%AE%E5%AD%97/"/>
<id>https://xiaolaji.site/20230114/Java%E4%B8%AD%E7%9A%84Static%E5%85%B3%E9%94%AE%E5%AD%97/</id>
<published>2023-01-14T05:09:00.000Z</published>
<updated>2023-05-27T03:19:36.000Z</updated>
<content type="html"><![CDATA[<h2 id="Static关键字的解释">Static关键字的解释</h2><p>Static关键字,即静态关键字,他在Java中是一个修饰性的关键字,不仅仅可以用于修饰方法,也可以的修饰属性,也可以直接修饰代码块。通过他的修饰,原本的方法、属性或者是代码块就会变成静态的。</p><p>通过这样的解释,似乎真的是听君一席话,如听一席话。</p><p>下面我会进行详细的解释。</p><h2 id="Static关键字带来的影响">Static关键字带来的影响</h2><p>众所周知,Java程序是运行在Java虚拟机中的,而虚拟机中有三个部分,栈、堆、和方法区。</p><p>在程序开始运行的时候,Java虚拟机首先会将main程序入栈,所使用的的基本数据类型被用于创建某个变量的时候,这个变量会被加载到栈中;当对定义的基本数据类型进行赋值的时候,Java虚拟机会在堆中开辟一个空间用于存放这个变量的值。而方法区则用于存放字节码文件。</p><p><img src="Java%E8%99%9A%E6%8B%9F%E6%9C%BA.png" alt="Java虚拟机"></p><p>由此可见,一般情况下程序在加载的时候,一个变量的生成,需要先去堆中去开辟空间再进行存值,当变量发生变化的时候,可能就需要重新进行加载,并指向新的位置。在使用的时候也需要在栈中先找到这个变量,再去读取堆中这个变量的值。</p><p>当添加了Static关键字后,所有被Static关键字修饰的都会在程序初始化的时候在方法区内进行加载,并且只加载一次。变量需要改变或者使用的时候,可以直接去方法区内进行修改或者调用。相比于普通的调用方法,效率会更高。</p><h2 id="Static关键字的具体使用">Static关键字的具体使用</h2><h3 id="修饰方法">修饰方法</h3><p>当Static用于修饰某个方法时,这个方法可以直接进行调用</p><p>如果这个方法没有static修饰,必须在这个方法所在的类中进行实例化之后才能进行调用</p><p>例如:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java">Thread.sleep(<span class="hljs-number">5000</span>);<span class="hljs-comment">//这里暂停5秒</span><br><br><span class="hljs-comment">//这里直接调用了sleep这个方法,之所以可以直接调用是因为他是被static修饰的</span><br><span class="hljs-comment">//这里展示了sleep的源码</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">native</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">sleep</span><span class="hljs-params">(<span class="hljs-type">long</span> millis)</span> <span class="hljs-keyword">throws</span> InterruptedException;<br></code></pre></td></tr></table></figure><h3 id="属性修饰">属性修饰</h3><p>当Static用于修饰一个属性的时候,这个属性随着类的加载而加载,存放在方法区内,且仅被加载一次</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String name;<br><span class="hljs-comment">//这样使用static修饰的变量,叫做静态变量,会随着类的加载而加载,存放的地址是方法区,并且只加载一次</span><br></code></pre></td></tr></table></figure><h3 id="静态代码块">静态代码块</h3><p>使用Static加载一块代码,这块代码也会类似于被Static修饰的变量,随着类的加载而加载,在程序最开始的时候就会被执行,且只被加载一次。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">static</span> {<br> System.out.println(<span class="hljs-string">"我是静态代码块中的内容"</span>);<br>}<br><span class="hljs-comment">//这个会随着类的加载而加载,即在整个程序的最开始的时候进行执行。而且只加载一次就可以,不管其出现在什么地方</span><br></code></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="Static关键字的解释">Static关键字的解释</h2>
<p>Static关键字,即静态关键字,他在Java中是一个修饰性的关键字,不仅仅可以用于修饰方法,也可以的修饰属性,也可以直接修饰代码块。通过他的修饰,原本的方法、属性或者是代码块就会变成静态的。<</summary>
<category term="Java" scheme="https://xiaolaji.site/categories/Java/"/>
<category term="Java" scheme="https://xiaolaji.site/tags/Java/"/>
</entry>
<entry>
<title>我与单片机的邂逅</title>
<link href="https://xiaolaji.site/20221227/%E6%88%91%E4%B8%8E%E5%8D%95%E7%89%87%E6%9C%BA%E7%9A%84%E9%82%82%E9%80%85/"/>
<id>https://xiaolaji.site/20221227/%E6%88%91%E4%B8%8E%E5%8D%95%E7%89%87%E6%9C%BA%E7%9A%84%E9%82%82%E9%80%85/</id>
<published>2022-12-27T17:06:00.000Z</published>
<updated>2023-05-27T03:19:26.000Z</updated>
<content type="html"><![CDATA[<h1>我与单片机的邂逅</h1><p>有时候,我自己会想,CPU的成本那么高,为什么那么多的智能设备的价格却是那么的便宜,到底是怎么去压缩这些产品的价格的;但是自己始终没有去深究过其中的技术,直到学校开始开设劳动教育课程,我选择了“避障小车的制作”这门课程,学校提供了Arduino单片机平台给我,借此我才开始正式接触单片机。</p><h2 id="从Arduino开始入坑">从Arduino开始入坑</h2><p>Arduino到底是个啥?</p><p>喏,就长这样:</p><p><img src="image-20221227131928612.png" alt="Arduino UNO开发板"></p><p>这是一个最为基础的Arduino UNO开发板,由于我们学校还是 <s>比较穷的</s> 经费紧张,再加上Arduino的作者将其在网上全部开源了,任何一家有设备条件的厂商甚至不需要任何授权就可以进行生产,于是我们学校采购了大量的三方生产的UNO板给学生使用</p><p>真的很想吐槽!!!!!</p><p>那个焊接的歪七八zhou的电子元件,真的让我一个强迫症患者十分的 <s>着迷</s>,我真的哭死。</p><p>回来,说正事,单纯一个UNO板其可使用的引脚接口十分少,少得可怜,为了适应更好的开发需求,Arduino对于UNO板开发了其配套的拓展板<code>Sensor Shield v5.0</code>:</p><p><img src="image-20221227145344351.png" alt="UNO开发板适配的拓展板"></p><p>通过拓展板我们可以实现更多的功能,其丰富接口让开发者的开发作品可适用于更多的场景。</p><p><img src="image-20221227150659541.png" alt="拓展板的IO引脚描述"></p><p>其提供的接口包括于数字IO口,模拟IO口,LCD系列接口,无线通信接口,甚至蓝牙接口,同时他也为超声传感器单独给了超声传感接口,为了扩展存储的能力,他也具备一个SD卡接口。</p><p>当然,Arduino是一个很庞大的家族,UNO板只是一个非常基础的初学者开发板,在Arduino IDE中可以看见Arduino还有非常多的各种各样的型号,这里不再一一介绍啦。感兴趣的可以去<a href="https://www.arduino.cc/">Arduino官网</a>或者<a href="https://arduino.nxez.com/">Arduino的中文社区</a>看看。</p><p>由于是第一次接触单片机,但是我还是有部分的C语言的功底的,勉强做出了四个轱辘能跑也可以避障的小车,但是学校给的传感器过于垃圾(开始推卸责任,但是说实话确实是传感器的问题),循迹功能一直表现的不太好(捂脸),具体制作的记录可见我的另一篇文章,<a href="https://xiaolaji.site/archives/113.html">自动避障小车的制作 - 小垃圾的后花园</a></p><h2 id="从STM32开始投入大成本">从STM32开始投入大成本</h2><p>自从开始从Arduino接触单片机后,发现,我作为一个物联网的学生,在未来岂不是需要大量的嵌入式开发咩?同时,借助制作避障小车的机会,结识了学校未来工程师协会的老师,老师建议我学习STM32,大量的嵌入式开发都会采用这一系列的芯片,这一方向刚好符合我的专业,决定开始学习STM32。</p><p>通过协会内的学长推荐,似乎正点原子的开发套件相关的学习资料比较多,所以我最终选择了正点原子的战舰V4开发套件进行入手学习。</p><p><strong>讲真的,STM开发套件是真滴贵啊,花了我四百多大洋,你啊知道四百多大洋对一个穷学生意味着什么吗呜呜呜呜呜。。。。</strong></p><p>但是不得不说,这个板子到货了之后是真的高级啊,黑色的外壳透着神秘气息…咳咳,上图:</p><p><img src="image-20221227161153492.png" alt="战舰开发板外包装"></p><p>里面的板子上下两层拿着光洁的亚克力板子保护,在接口处留有缝隙提供与外设进行连接,真的漂亮,STM32F1系列的芯片比Arduino不知大了多少,这个性能也不是一般的顶。</p><p><img src="image-20221227161607842.png" alt="战舰开发板"></p><p>这张板子四周都是各种外设的接口,STM32F103ZET6这块芯片具备着144个引脚,其可连接外设的数量,已经到达让Arduino UNO板望而却步的地方了,性能也比Arduino UNO要强的太多了。</p><p>从官方给的开放文档可以看见,这些串口分贝代表着哪些</p><p><img src="image-20221227163441919.png" alt="战舰开发板引脚示意图"></p><p>这块板子我觉得最近的一段时间完全足够我去折腾了,希望我很快做出一些实物,毕竟实践才是验证理论的唯一途径。</p>]]></content>
<summary type="html"><h1>我与单片机的邂逅</h1>
<p>有时候,我自己会想,CPU的成本那么高,为什么那么多的智能设备的价格却是那么的便宜,到底是怎么去压缩这些产品的价格的;但是自己始终没有去深究过其中的技术,直到学校开始开设劳动教育课程,我选择了“避障小车的制作”这门课程,学校提供了Ardu</summary>
<category term="单片机" scheme="https://xiaolaji.site/categories/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
<category term="单片机" scheme="https://xiaolaji.site/tags/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
</entry>
<entry>
<title>基于UDP协议的虚拟路灯</title>
<link href="https://xiaolaji.site/20221125/%E5%9F%BA%E4%BA%8EUDP%E5%8D%8F%E8%AE%AE%E7%9A%84%E8%99%9A%E6%8B%9F%E8%B7%AF%E7%81%AF/"/>
<id>https://xiaolaji.site/20221125/%E5%9F%BA%E4%BA%8EUDP%E5%8D%8F%E8%AE%AE%E7%9A%84%E8%99%9A%E6%8B%9F%E8%B7%AF%E7%81%AF/</id>
<published>2022-11-25T18:16:00.000Z</published>
<updated>2023-05-27T03:19:12.000Z</updated>
<content type="html"><![CDATA[<h2 id="项目目标">项目目标</h2><pre><code class="hljs">使用UDP通信协议,创建虚拟路灯。具备多个虚拟路灯的终端,一个UDP Server服务器,通过UDP通信协议将设备相连,并实现虚拟路灯上的数据向服务端的传输、以及服务端可对虚拟路灯终端设备进行远程控制灯的开关。</code></pre><h2 id="设计与实现">设计与实现</h2><h3 id="使用语言:Python">使用语言:Python</h3><h3 id="界面设计:Pyqt5、Pyqt5-Designer、Pyuic">界面设计:Pyqt5、Pyqt5 Designer、Pyuic</h3><h3 id="客户端设计思路:">客户端设计思路:</h3><ul class="lvl-0"><li class="lvl-2"><p>使用Pyqt5 Designer工具先进行界面设计,这是一款图形化的工具,可以方便的得到我们想要的界面效果,并支持通过<code>Ctrl+R</code>进行实时预览,完成后有会生成一个UI文件,使用Pyuic工具即可以将UI文件转换成py文件</p></li><li class="lvl-2"><p>定义函数生成随机数据,可以再客户端的界面进行展示</p></li><li class="lvl-2"><p>在Pyqt5的界面代码中给按钮添加信号,点击则开始相关的功能函数</p></li><li class="lvl-2"><p>定义工作函数,将生成的数据通过UDP的方式发送到Server</p></li><li class="lvl-2"><p>由于在Pyqt5所运行的线程中无法使用,否则界面会卡死,需要引入多线程编程,将UDP接收函数在一个单独的线程上运行</p></li></ul><h3 id="服务端设计思路:">服务端设计思路:</h3><ul class="lvl-0"><li class="lvl-2"><p>使用Pyqt5 Designer工具先进行界面设计,这是一款图形化的工具,可以方便的得到我们想要的界面效果,并支持通过<code>Ctrl+R</code>进行实时预览,完成后有会生成一个UI文件,使用Pyuic工具即可以将UI文件转换成py文件</p></li><li class="lvl-2"><p>定义Pyqt5对界面的展示信号,以及对按钮的信号设置</p></li><li class="lvl-2"><p>发包函数,以用于对客户端的开关灯信号的发送</p></li><li class="lvl-2"><p>由于在Pyqt5所运行的线程中无法使用,否则界面会卡死,需要引入多线程编程,将UDP接收函数在一个单独的线程上运行</p></li></ul><h2 id="测试与结果">测试与结果</h2><p>客户端与三个服务端展示</p><p><img src="image-20221125124719830.png" alt="客户端与三个服务端展示"></p><p>点击服务端开始接收,客户端开始工作;再点击客户端工作按钮,客户端开始工作</p><p><img src="image-20221125125031667.png" alt="开始工作"></p><p>分别点击服务端的停止按钮,服务端会停止工作</p><p><img src="image-20221125125136798.png" alt="停止工作"></p><p>此时点击服务端的开机按钮,服务端会向所有的终端发出开灯指令</p><p><img src="image-20221125125450561.png" alt="发出指令"></p><p>开灯指令在服务端接收后会返回一个数据包给服务端,只有在服务端收到这个客户端返回的数据包,证明传输成功,这样来实现可靠传输。</p><p>点击关灯按钮,所有设备关闭,但保留了接收远程信号的功能</p><p><img src="image-20221125125702500.png" alt="关闭所有设备"></p><h2 id="总结与展望">总结与展望</h2><pre><code class="hljs">这是第一次对程序制作操作界面,从刚开始的磕磕绊绊,到逐渐理解,到完成程序,中途遇见了很多的坑,也学到了很多。开始明白了界面实际是将某种固件在特定的位置点上进行展示,以及按钮的一些使用方法;也明白了界面也是一个程序,但是不能与循环同时运行的原因。这次大作业锻炼了我的编程能力,让我自己在自我解决问题的方面迈出了一大步,网络上的资源很多,我们要学会充分利用。</code></pre><h2 id="相关源代码">相关源代码</h2><h3 id="客户端UI">客户端UI</h3><p><img src="image-20221125124505826.png" alt="客户端UI"></p><h3 id="服务端UI">服务端UI</h3><p><img src="image-20221125124557711.png" alt="服务端UI"></p><h3 id="客户端源代码">客户端源代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span><br><br><span class="hljs-comment"># Form implementation generated from reading ui file 'Light_Client.ui'</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># Created by: PyQt5 UI code generator 5.15.4</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># WARNING: Any manual changes made to this file will be lost when pyuic5 is</span><br><span class="hljs-comment"># run again. Do not edit this file unless you know what you are doing.</span><br><span class="hljs-keyword">import</span> random<br><span class="hljs-keyword">import</span> sys<br><span class="hljs-keyword">import</span> threading<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">from</span> multiprocessing.connection <span class="hljs-keyword">import</span> Client<br><br><span class="hljs-keyword">from</span> PyQt5 <span class="hljs-keyword">import</span> QtCore, QtGui, QtWidgets<br><span class="hljs-keyword">from</span> PyQt5.QtCore <span class="hljs-keyword">import</span> QThread<br><br><span class="hljs-comment">#Port是本设备的监听地址,服务端默认三个设备是 设备三8887 设备二8888 设备一8889 三个端口,如有需要可以自行修改</span><br><span class="hljs-comment">#使用不同的Port端口值即可新建一个设备</span><br>IP = <span class="hljs-string">'127.0.0.1'</span><br>Port = <span class="hljs-string">'8889'</span><br><br><br><span class="hljs-comment"># 创建套接字类,便于后期的套接字的使用</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Client</span>:<br> client_socket = <span class="hljs-literal">None</span><br><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br> self.initialize_socket()<br><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">initialize_socket</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-comment"># 创建套接字</span><br> self.clientsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<br><br><br><span class="hljs-comment"># PYQT界面的设计代码</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Ui_MainWindow</span>(<span class="hljs-title class_ inherited__">object</span>):<br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">setupUi</span>(<span class="hljs-params">self, MainWindow</span>):<br> MainWindow.setObjectName(<span class="hljs-string">"MainWindow"</span>)<br> MainWindow.resize(<span class="hljs-number">597</span>, <span class="hljs-number">489</span>)<br> self.centralwidget = QtWidgets.QWidget(MainWindow)<br> self.centralwidget.setObjectName(<span class="hljs-string">"centralwidget"</span>)<br><br> <span class="hljs-comment"># 第一个标签 写了 温度显示</span><br> self.label = QtWidgets.QLabel(self.centralwidget)<br> self.label.setGeometry(QtCore.QRect(<span class="hljs-number">130</span>, <span class="hljs-number">70</span>, <span class="hljs-number">71</span>, <span class="hljs-number">31</span>))<br> self.label.setObjectName(<span class="hljs-string">"label"</span>)<br><br> <span class="hljs-comment"># 第二个标签 写了湿度显示</span><br> self.label_2 = QtWidgets.QLabel(self.centralwidget)<br> self.label_2.setGeometry(QtCore.QRect(<span class="hljs-number">290</span>, <span class="hljs-number">70</span>, <span class="hljs-number">81</span>, <span class="hljs-number">31</span>))<br> self.label_2.setObjectName(<span class="hljs-string">"label_2"</span>)<br><br> <span class="hljs-comment"># 第三个标签 写了照度显示</span><br> self.label_3 = QtWidgets.QLabel(self.centralwidget)<br> self.label_3.setGeometry(QtCore.QRect(<span class="hljs-number">450</span>, <span class="hljs-number">70</span>, <span class="hljs-number">71</span>, <span class="hljs-number">31</span>))<br> self.label_3.setObjectName(<span class="hljs-string">"label_3"</span>)<br><br> <span class="hljs-comment"># LCD显示器 显示温度数据</span><br> self.lcdNumber_WenDu = QtWidgets.QLCDNumber(self.centralwidget)<br> self.lcdNumber_WenDu.setGeometry(QtCore.QRect(<span class="hljs-number">110</span>, <span class="hljs-number">110</span>, <span class="hljs-number">91</span>, <span class="hljs-number">31</span>))<br> self.lcdNumber_WenDu.setObjectName(<span class="hljs-string">"lcdNumber_WenDu"</span>)<br><br> <span class="hljs-comment"># LCD显示器 显示照度数据</span><br> self.lcdNumber_ZhaoDu = QtWidgets.QLCDNumber(self.centralwidget)<br> self.lcdNumber_ZhaoDu.setGeometry(QtCore.QRect(<span class="hljs-number">430</span>, <span class="hljs-number">110</span>, <span class="hljs-number">91</span>, <span class="hljs-number">31</span>))<br> self.lcdNumber_ZhaoDu.setObjectName(<span class="hljs-string">"lcdNumber_ZhaoDu"</span>)<br><br> <span class="hljs-comment"># LCD显示器 显示湿度数据</span><br> self.lcdNumber_ShiDu = QtWidgets.QLCDNumber(self.centralwidget)<br> self.lcdNumber_ShiDu.setGeometry(QtCore.QRect(<span class="hljs-number">270</span>, <span class="hljs-number">110</span>, <span class="hljs-number">91</span>, <span class="hljs-number">31</span>))<br> self.lcdNumber_ShiDu.setObjectName(<span class="hljs-string">"lcdNumber_ShiDu"</span>)<br><br> <span class="hljs-comment"># 第四个标签 显示了灯工作状态的解释</span><br> self.label_4 = QtWidgets.QLabel(self.centralwidget)<br> self.label_4.setGeometry(QtCore.QRect(<span class="hljs-number">180</span>, <span class="hljs-number">270</span>, <span class="hljs-number">301</span>, <span class="hljs-number">41</span>))<br> self.label_4.setObjectName(<span class="hljs-string">"label_4"</span>)<br><br> <span class="hljs-comment"># 文本框 用于展示当前设备的IP地址</span><br> self.IP_Display = QtWidgets.QTextBrowser(self.centralwidget)<br> self.IP_Display.setGeometry(QtCore.QRect(<span class="hljs-number">110</span>, <span class="hljs-number">320</span>, <span class="hljs-number">161</span>, <span class="hljs-number">31</span>))<br> self.IP_Display.setObjectName(<span class="hljs-string">"IP_Display"</span>)<br> self.IP_Display.setText(IP + <span class="hljs-string">":"</span> + Port)<br><br> <span class="hljs-comment"># 第五个标签 展示了IP字样</span><br> self.label_5 = QtWidgets.QLabel(self.centralwidget)<br> self.label_5.setGeometry(QtCore.QRect(<span class="hljs-number">150</span>, <span class="hljs-number">360</span>, <span class="hljs-number">101</span>, <span class="hljs-number">31</span>))<br> self.label_5.setObjectName(<span class="hljs-string">"label_5"</span>)<br><br> <span class="hljs-comment"># 开始工作的按钮 触发则进入到工作状态</span><br> self.Start = QtWidgets.QPushButton(self.centralwidget)<br> self.Start.setGeometry(QtCore.QRect(<span class="hljs-number">310</span>, <span class="hljs-number">330</span>, <span class="hljs-number">75</span>, <span class="hljs-number">23</span>))<br> self.Start.setObjectName(<span class="hljs-string">"Start"</span>)<br><br> <span class="hljs-comment"># 停止工作按钮 触发则停止工作</span><br> self.Stop = QtWidgets.QPushButton(self.centralwidget)<br> self.Stop.setGeometry(QtCore.QRect(<span class="hljs-number">410</span>, <span class="hljs-number">330</span>, <span class="hljs-number">75</span>, <span class="hljs-number">23</span>))<br> self.Stop.setObjectName(<span class="hljs-string">"Stop"</span>)<br><br> <span class="hljs-comment"># 中央灯状态表示区</span><br> self.frame = QtWidgets.QFrame(self.centralwidget)<br> self.frame.setGeometry(QtCore.QRect(<span class="hljs-number">220</span>, <span class="hljs-number">190</span>, <span class="hljs-number">120</span>, <span class="hljs-number">80</span>))<br> self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)<br> self.frame.setFrameShadow(QtWidgets.QFrame.Raised)<br> self.frame.setStyleSheet(<span class="hljs-string">"background-color:black"</span>)<br> self.frame.setObjectName(<span class="hljs-string">"frame"</span>)<br><br> <span class="hljs-comment"># MainWindow.setCentralWidget(self.centralwidget)</span><br> self.menubar = QtWidgets.QMenuBar(MainWindow)<br> self.menubar.setGeometry(QtCore.QRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">597</span>, <span class="hljs-number">22</span>))<br> self.menubar.setObjectName(<span class="hljs-string">"menubar"</span>)<br> <span class="hljs-comment"># MainWindow.setMenuBar(self.menubar)</span><br><br> self.statusbar = QtWidgets.QStatusBar(MainWindow)<br><br> <span class="hljs-comment"># ----------------------按钮触发方法的设置-----------------------------------------</span><br> <span class="hljs-comment"># 开始按钮点击则启动start_work</span><br> self.Start.clicked.connect(self.start_work)<br> self.Stop.clicked.connect(self.stop_work)<br> <span class="hljs-comment"># 关闭按钮则启动stop_work</span><br> <span class="hljs-comment"># ----------------------按钮触发方法的设置-----------------------------------------</span><br><br> self.statusbar.setObjectName(<span class="hljs-string">"statusbar"</span>)<br> <span class="hljs-comment"># MainWindow.setStatusBar(self.statusbar)</span><br> self.retranslateUi(MainWindow)<br> QtCore.QMetaObject.connectSlotsByName(MainWindow)<br><br> <span class="hljs-comment"># 设置所有的组件上的文字</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">retranslateUi</span>(<span class="hljs-params">self, MainWindow</span>):<br> _translate = QtCore.QCoreApplication.translate<br> MainWindow.setWindowTitle(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"MainWindow"</span>))<br> self.label.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"温度显示"</span>))<br> self.label_2.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"湿度显示"</span>))<br> self.label_3.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"照度显示"</span>))<br> self.label_4.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"红色状态为正常工作 蓝色状态为关闭"</span>))<br> self.label_5.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"设备IP地址"</span>))<br> self.Start.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"工作"</span>))<br> self.Stop.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"停止"</span>))<br><br> <span class="hljs-comment"># 开灯函数,在随机生成数据并显示的同时做到了向Server发包并启动了UDP的接收代码</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">start_work</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-comment"># 数据处理,随机生成温度湿度照度数据并显示</span><br> self.frame.setStyleSheet(<span class="hljs-string">"background-color:red"</span>)<br> WenDu = random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>)<br> ShiDu = random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>)<br> ZhaoDu = random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>)<br> self.lcdNumber_WenDu.display(WenDu)<br> self.lcdNumber_ShiDu.display(ShiDu)<br> self.lcdNumber_ZhaoDu.display(ZhaoDu)<br> <span class="hljs-comment"># 创建套接字 向8080服务器所在的端口进行UDP数据包的发送</span><br> self.client = Client()<br> self.client.initialize_socket()<br> <span class="hljs-comment"># 发送的数据除了三个传感器数据外并带上了自己监控的接收端口</span><br> message = <span class="hljs-built_in">str</span>(WenDu) + <span class="hljs-string">' '</span> + <span class="hljs-built_in">str</span>(ShiDu) + <span class="hljs-string">" "</span> + <span class="hljs-built_in">str</span>(ZhaoDu) + <span class="hljs-string">" "</span> + Port<br> self.client.clientsocket.sendto(message.encode(<span class="hljs-string">"utf8"</span>), (<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br> <span class="hljs-comment"># flag用于保证循环接收不会启动第二次,导致端口占用的报错</span><br> <span class="hljs-comment"># 开启一次则不再进行开启</span><br> <span class="hljs-keyword">global</span> flag<br> <span class="hljs-keyword">if</span> flag == <span class="hljs-number">0</span>:<br> <span class="hljs-comment"># 使用一个新的线程进行接收的操作</span><br> get_Thred = threading.Thread(target=getter)<br> get_Thred.start()<br> flag = <span class="hljs-number">1</span><br><br> <span class="hljs-comment"># stop实质停止所有的数据,则将显示的数据置零</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">stop_work</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-comment"># while (1):</span><br> self.frame.setStyleSheet(<span class="hljs-string">"background-color:blue"</span>)<br> self.lcdNumber_WenDu.display(<span class="hljs-number">0</span>)<br> self.lcdNumber_ShiDu.display(<span class="hljs-number">0</span>)<br> self.lcdNumber_ZhaoDu.display(<span class="hljs-number">0</span>)<br><br><br><span class="hljs-comment"># 接收端函数 占用一个端口进行循环接收UDP数据包</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">getter</span>():<br> udp_getter = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<br> udp_getter.bind((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-built_in">int</span>(Port)))<br> <span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> message, addr = udp_getter.recvfrom(<span class="hljs-number">1024</span>)<br> sig = message.decode(<span class="hljs-string">'utf-8'</span>)<br> <span class="hljs-comment"># print(sig)</span><br> <span class="hljs-comment"># 对数据包内部的内容进行判断,判断完成后执行相应的操作</span><br> <span class="hljs-keyword">if</span> sig == <span class="hljs-string">'1'</span>:<br> ui.start_work()<br> <span class="hljs-keyword">elif</span> sig == <span class="hljs-string">'0'</span>:<br> ui.stop_work()<br><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:<br> sig = <span class="hljs-string">""</span><br> flag = <span class="hljs-number">0</span><br> app = QtWidgets.QApplication(sys.argv)<br> widget = QtWidgets.QWidget()<br> ui = Ui_MainWindow()<br> ui.setupUi(widget)<br> widget.show()<br> sys.exit(app.exec_())<br></code></pre></td></tr></table></figure><h3 id="服务端源代码">服务端源代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span><br><br><span class="hljs-comment"># Form implementation generated from reading ui file 'Light_Server.ui'</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># Created by: PyQt5 UI code generator 5.15.4</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># WARNING: Any manual changes made to this file will be lost when pyuic5 is</span><br><span class="hljs-comment"># run again. Do not edit this file unless you know what you are doing.</span><br><br><span class="hljs-comment">#服务端默认三个设备是 设备三8887 设备二8888 设备一8889 三个端口,如有需要可以自行修改</span><br><br><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> sys<br><span class="hljs-keyword">import</span> threading<br><span class="hljs-keyword">import</span> time<br><br><span class="hljs-keyword">from</span> PyQt5 <span class="hljs-keyword">import</span> QtCore, QtGui, QtWidgets<br><span class="hljs-keyword">from</span> PyQt5.QtCore <span class="hljs-keyword">import</span> QThread<br><br><br><span class="hljs-comment"># PYQT界面代码部分</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Ui_MainWindow</span>(<span class="hljs-title class_ inherited__">object</span>):<br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">setupUi</span>(<span class="hljs-params">self, MainWindow</span>):<br> MainWindow.setObjectName(<span class="hljs-string">"MainWindow"</span>)<br> MainWindow.resize(<span class="hljs-number">800</span>, <span class="hljs-number">600</span>)<br> self.centralwidget = QtWidgets.QWidget(MainWindow)<br> self.centralwidget.setObjectName(<span class="hljs-string">"centralwidget"</span>)<br> self.show_shebei1 = QtWidgets.QTextBrowser(self.centralwidget)<br> self.show_shebei1.setGeometry(QtCore.QRect(<span class="hljs-number">30</span>, <span class="hljs-number">70</span>, <span class="hljs-number">501</span>, <span class="hljs-number">41</span>))<br> self.show_shebei1.setObjectName(<span class="hljs-string">"show_shebei1"</span>)<br> self.show_shebei3 = QtWidgets.QTextBrowser(self.centralwidget)<br> self.show_shebei3.setGeometry(QtCore.QRect(<span class="hljs-number">30</span>, <span class="hljs-number">210</span>, <span class="hljs-number">501</span>, <span class="hljs-number">41</span>))<br> self.show_shebei3.setObjectName(<span class="hljs-string">"show_shebei3"</span>)<br> self.show_shebei2 = QtWidgets.QTextBrowser(self.centralwidget)<br> self.show_shebei2.setGeometry(QtCore.QRect(<span class="hljs-number">30</span>, <span class="hljs-number">140</span>, <span class="hljs-number">501</span>, <span class="hljs-number">41</span>))<br> self.show_shebei2.setObjectName(<span class="hljs-string">"show_shebei2"</span>)<br> self.labal_shebei1 = QtWidgets.QLabel(self.centralwidget)<br> self.labal_shebei1.setGeometry(QtCore.QRect(<span class="hljs-number">250</span>, <span class="hljs-number">41</span>, <span class="hljs-number">54</span>, <span class="hljs-number">21</span>))<br> self.labal_shebei1.setObjectName(<span class="hljs-string">"labal_shebei1"</span>)<br> self.label_shebei2 = QtWidgets.QLabel(self.centralwidget)<br> self.label_shebei2.setGeometry(QtCore.QRect(<span class="hljs-number">250</span>, <span class="hljs-number">112</span>, <span class="hljs-number">54</span>, <span class="hljs-number">31</span>))<br> self.label_shebei2.setObjectName(<span class="hljs-string">"label_shebei2"</span>)<br> self.label_shebei3 = QtWidgets.QLabel(self.centralwidget)<br> self.label_shebei3.setGeometry(QtCore.QRect(<span class="hljs-number">250</span>, <span class="hljs-number">180</span>, <span class="hljs-number">54</span>, <span class="hljs-number">31</span>))<br> self.label_shebei3.setObjectName(<span class="hljs-string">"label_shebei3"</span>)<br> self.textBrowser_shujubao = QtWidgets.QTextBrowser(self.centralwidget)<br> self.textBrowser_shujubao.setGeometry(QtCore.QRect(<span class="hljs-number">70</span>, <span class="hljs-number">280</span>, <span class="hljs-number">256</span>, <span class="hljs-number">192</span>))<br> self.textBrowser_shujubao.setObjectName(<span class="hljs-string">"textBrowser_shujubao"</span>)<br> self.start_light = QtWidgets.QPushButton(self.centralwidget)<br> self.start_light.setGeometry(QtCore.QRect(<span class="hljs-number">600</span>, <span class="hljs-number">110</span>, <span class="hljs-number">75</span>, <span class="hljs-number">23</span>))<br> self.start_light.setStyleSheet(<span class="hljs-string">"background-color:red"</span>)<br> self.start_light.setObjectName(<span class="hljs-string">"start_light"</span>)<br> self.stop_light = QtWidgets.QPushButton(self.centralwidget)<br> self.stop_light.setGeometry(QtCore.QRect(<span class="hljs-number">600</span>, <span class="hljs-number">160</span>, <span class="hljs-number">75</span>, <span class="hljs-number">23</span>))<br> self.stop_light.setStyleSheet(<span class="hljs-string">"background-color:yellow"</span>)<br> self.stop_light.setObjectName(<span class="hljs-string">"stop_light"</span>)<br> self.label = QtWidgets.QLabel(self.centralwidget)<br> self.label.setGeometry(QtCore.QRect(<span class="hljs-number">150</span>, <span class="hljs-number">490</span>, <span class="hljs-number">181</span>, <span class="hljs-number">20</span>))<br> self.label.setObjectName(<span class="hljs-string">"label"</span>)<br> self.Stop_All = QtWidgets.QPushButton(self.centralwidget)<br> self.Stop_All.setGeometry(QtCore.QRect(<span class="hljs-number">420</span>, <span class="hljs-number">360</span>, <span class="hljs-number">201</span>, <span class="hljs-number">51</span>))<br> self.Stop_All.setStyleSheet(<span class="hljs-string">"background-color:White"</span>)<br> self.Stop_All.setObjectName(<span class="hljs-string">"Stop_All"</span>)<br> <span class="hljs-comment"># MainWindow.setCentralWidget(self.centralwidget)</span><br> self.menubar = QtWidgets.QMenuBar(MainWindow)<br> self.menubar.setGeometry(QtCore.QRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">800</span>, <span class="hljs-number">22</span>))<br> self.menubar.setObjectName(<span class="hljs-string">"menubar"</span>)<br> <span class="hljs-comment"># MainWindow.setMenuBar(self.menubar)</span><br> self.statusbar = QtWidgets.QStatusBar(MainWindow)<br> self.statusbar.setObjectName(<span class="hljs-string">"statusbar"</span>)<br> <span class="hljs-comment"># MainWindow.setStatusBar(self.statusbar)</span><br> <span class="hljs-comment"># -----------------------------------------------------------------</span><br> <span class="hljs-comment"># 按钮触发部分</span><br> <span class="hljs-comment"># Stop_all按钮连接的是开始接收按钮</span><br> self.Stop_All.clicked.connect(self.start)<br> <span class="hljs-comment"># start_light连接的是开灯按钮 启动light_up函数</span><br> self.start_light.clicked.connect(self.light_up)<br> <span class="hljs-comment"># stop_light连接的是关灯按钮 启动lightdown函数</span><br> self.stop_light.clicked.connect(self.light_down)<br> <span class="hljs-comment"># self.Stop_All.clicked.connect(self.stop_all)</span><br> <span class="hljs-comment"># 按钮触发部分</span><br> <span class="hljs-comment"># -----------------------------------------------------------------</span><br> self.retranslateUi(MainWindow)<br> QtCore.QMetaObject.connectSlotsByName(MainWindow)<br><br> <span class="hljs-comment"># 对每一个部件上面设置显示的文字</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">retranslateUi</span>(<span class="hljs-params">self, MainWindow</span>):<br> _translate = QtCore.QCoreApplication.translate<br> MainWindow.setWindowTitle(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"MainWindow"</span>))<br> self.labal_shebei1.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"设备一"</span>))<br> self.label_shebei2.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"设备二"</span>))<br> self.label_shebei3.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"设备三"</span>))<br> self.start_light.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"开灯"</span>))<br> self.stop_light.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"关灯"</span>))<br> self.label.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"数据包列表"</span>))<br> self.Stop_All.setText(_translate(<span class="hljs-string">"MainWindow"</span>, <span class="hljs-string">"开始接收"</span>))<br><br> <span class="hljs-comment"># 开始一个新的线程作为对8080端口的监听</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">start</span>(<span class="hljs-params">self</span>):<br> get_Thred = threading.Thread(target=getter)<br> get_Thred.start()<br><br> <span class="hljs-comment"># 对设备一的设备相关信息进行显示</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">dayin1</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-comment"># print(str(get))</span><br> self.show_shebei1.append(get)<br> <span class="hljs-comment"># print(str(get))</span><br><br> <span class="hljs-comment"># 对设备二的设备相关信息进行显示</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">dayin2</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-comment"># print(str(get))</span><br> self.show_shebei2.append(get)<br> <span class="hljs-comment"># print(str(get))</span><br><br> <span class="hljs-comment"># 对设备三的设备相关信息进行显示</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">dayin3</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-comment"># print(str(get))</span><br> self.show_shebei3.append(get)<br> <span class="hljs-comment"># print(str(get))</span><br><br> <span class="hljs-comment"># 对数据包的发送与接收进行显示,显示的量是一个全局变量bag,如果需要显示则先修改bag再进行函数的调用</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">dayin4</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-comment"># 有一个问题:不知道为什么在跨线程的调用中,似乎只有append方法起作用,原本的setText并没有起作用</span><br> self.textBrowser_shujubao.append(bag)<br><br> <span class="hljs-comment"># 通过UDP发包向所有设备的地址分别发送开灯的数据包,设备接收到会调用开灯的函数,相当于执行一次开灯</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">light_up</span>(<span class="hljs-params">self</span>):<br> udp_up = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<br> mes = <span class="hljs-built_in">str</span>(<span class="hljs-number">1</span>)<br> udp_up.sendto(mes.encode(<span class="hljs-string">"utf8"</span>), (<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8889</span>))<br> udp_up.sendto(mes.encode(<span class="hljs-string">"utf8"</span>), (<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8888</span>))<br> udp_up.sendto(mes.encode(<span class="hljs-string">"utf8"</span>), (<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8887</span>))<br> <span class="hljs-keyword">global</span> bag<br> time.sleep(<span class="hljs-number">0.2</span>)<br> bag = <span class="hljs-string">"向所有设备发出开灯数据包"</span><br> self.dayin4()<br><br> <span class="hljs-comment"># 通过UDP发包向所有设备的地址分别发送关灯的数据包,设备接收到会调用关灯的函数,相当于执行一次关灯</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">light_down</span>(<span class="hljs-params">self</span>):<br> udp_down = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<br> mes = <span class="hljs-built_in">str</span>(<span class="hljs-number">0</span>)<br> udp_down.sendto(mes.encode(<span class="hljs-string">"utf8"</span>), (<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8889</span>))<br> udp_down.sendto(mes.encode(<span class="hljs-string">"utf8"</span>), (<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8888</span>))<br> udp_down.sendto(mes.encode(<span class="hljs-string">"utf8"</span>), (<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8887</span>))<br> <span class="hljs-keyword">global</span> bag<br> time.sleep(<span class="hljs-number">0.2</span>)<br> bag = <span class="hljs-string">"向所有设备发出关灯数据包"</span><br> self.dayin4()<br><br> <span class="hljs-comment"># 启动新的线程进行 While 循环来确保能够接收到设备发来的UDP包</span><br><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">getter</span>():<br> udp_getter = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<br> udp_getter.bind((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br> <span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> message, addr = udp_getter.recvfrom(<span class="hljs-number">1024</span>)<br> <span class="hljs-keyword">global</span> get<br> <span class="hljs-keyword">global</span> bag<br> temp = message.decode(<span class="hljs-string">'utf-8'</span>)<br> temp = <span class="hljs-built_in">str</span>(temp)<br> new = temp.split()<br> <span class="hljs-comment"># 对发送来的包进行鉴别,判断出数据包来自哪里并读取处理其中的内容,调用相关的方法显示在数据包列表和相关的设备列表</span><br> <span class="hljs-keyword">if</span> new[<span class="hljs-number">3</span>] == <span class="hljs-string">'8889'</span>:<br> <span class="hljs-comment"># 来自8889设备</span><br> <span class="hljs-comment"># 处理数据显示区域的显示</span><br> get = <span class="hljs-string">"设备一:"</span> + <span class="hljs-string">"温度为"</span> + new[<span class="hljs-number">0</span>] + <span class="hljs-string">" 湿度为"</span> + new[<span class="hljs-number">1</span>] + <span class="hljs-string">" 照度为"</span> + new[<span class="hljs-number">2</span>]<br> ui.dayin1()<br> <span class="hljs-comment"># 处理数据包显示区的信息</span><br> bag = <span class="hljs-string">"来自"</span> + new[<span class="hljs-number">3</span>] + <span class="hljs-string">"的数据包"</span><br> ui.dayin4()<br> <span class="hljs-keyword">elif</span> new[<span class="hljs-number">3</span>] == <span class="hljs-string">'8888'</span>:<br> <span class="hljs-comment"># 来自8888设备</span><br> <span class="hljs-comment"># 处理数据显示区的数据</span><br> get = <span class="hljs-string">"设备二:"</span> + <span class="hljs-string">"温度为"</span> + new[<span class="hljs-number">0</span>] + <span class="hljs-string">" 湿度为"</span> + new[<span class="hljs-number">1</span>] + <span class="hljs-string">" 照度为"</span> + new[<span class="hljs-number">2</span>]<br> ui.dayin2()<br> <span class="hljs-comment"># 处理数据包显示区域的数据</span><br> bag = <span class="hljs-string">"来自"</span> + new[<span class="hljs-number">3</span>] + <span class="hljs-string">"的数据包"</span><br> ui.dayin4()<br> <span class="hljs-keyword">elif</span> new[<span class="hljs-number">3</span>] == <span class="hljs-string">'8887'</span>:<br> <span class="hljs-comment"># 来自8887设备</span><br> <span class="hljs-comment"># 处理数据显示区的设备</span><br> get = <span class="hljs-string">"设备三:"</span> + <span class="hljs-string">"温度为"</span> + new[<span class="hljs-number">0</span>] + <span class="hljs-string">" 湿度为"</span> + new[<span class="hljs-number">1</span>] + <span class="hljs-string">" 照度为"</span> + new[<span class="hljs-number">2</span>]<br> ui.dayin3()<br> <span class="hljs-comment"># 处理数据包显示区的显示数据</span><br> bag = <span class="hljs-string">"来自"</span> + new[<span class="hljs-number">3</span>] + <span class="hljs-string">"的数据包"</span><br> ui.dayin4()<br> <span class="hljs-keyword">else</span>:<br> bag = <span class="hljs-string">"来自"</span> + new[<span class="hljs-number">3</span>] + <span class="hljs-string">"的未知设备"</span> + new[<span class="hljs-number">3</span>]<br> ui.dayin4()<br><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:<br> get = <span class="hljs-string">""</span><br> bag = <span class="hljs-string">""</span><br> app = QtWidgets.QApplication(sys.argv)<br> widget = QtWidgets.QWidget()<br> ui = Ui_MainWindow()<br> ui.setupUi(widget)<br> widget.show()<br> sys.exit(app.exec_())<br></code></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="项目目标">项目目标</h2>
<pre><code class="hljs">使用UDP通信协议,创建虚拟路灯。具备多个虚拟路灯的终端,一个UDP Server服务器,通过UDP通信协议将设备相连,并实现虚拟路灯上的数据向服务端的传输、以及服务端可对虚拟路灯终端</summary>
<category term="大学学习" scheme="https://xiaolaji.site/categories/%E5%A4%A7%E5%AD%A6%E5%AD%A6%E4%B9%A0/"/>
<category term="大作业" scheme="https://xiaolaji.site/tags/%E5%A4%A7%E4%BD%9C%E4%B8%9A/"/>
</entry>
<entry>
<title>计算机网络大作业——抓包与分析</title>
<link href="https://xiaolaji.site/20221102/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%A4%A7%E4%BD%9C%E4%B8%9A%E2%80%94%E2%80%94%E6%8A%93%E5%8C%85%E4%B8%8E%E5%88%86%E6%9E%90/"/>
<id>https://xiaolaji.site/20221102/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%A4%A7%E4%BD%9C%E4%B8%9A%E2%80%94%E2%80%94%E6%8A%93%E5%8C%85%E4%B8%8E%E5%88%86%E6%9E%90/</id>
<published>2022-11-03T00:14:00.000Z</published>
<updated>2023-05-27T03:19:20.000Z</updated>
<content type="html"><![CDATA[<h2 id="一、作业目的">一、作业目的</h2><ol><li class="lvl-3">了解网络通信的分层实现过程,了解不同层次PDU的逐层封装与解封过程;</li><li class="lvl-3">了解数据通信的过程,进一步认知协议的构成与通信过程,进而对TCP/IP分层体系结构有更深刻的了解。</li></ol><h2 id="二、作业内容">二、作业内容</h2><ol><li class="lvl-3"><p>在局域网范围内从协议层面分析ping命令的执行过程,包括所使用协议,以及不同层级的数据包封装与解封的过程。</p></li><li class="lvl-3"><p>访问<code>www.ujs.edu.cn</code>网站,分析其中所使用的协议,以及数据包的逐层封装与解封过程。</p></li><li class="lvl-3"><p>思考在数据链路层的数据包与网络层数据包的异同,包括包长度和数据构成等,并进一步思考为何存在这些区别。</p></li></ol><h2 id="四、抓包软件说明">四、抓包软件说明</h2><pre><code class="hljs">本次作业需要使用到一些特定的抓包软件,如Wireshark、Sniffer等。这些软件可以通过对设备上产生的数据包进行截取,通过分析这些数据包可以详细获取一些我们所做的操作的行为,了解计算机底层通讯的具体过程,甚至通过数据包可以进行分析异常的流量,这些对网络的稳定性与安全性都有着十分重要的意义。由于个人习惯,我使用的是Wireshark抓包工具。</code></pre><h3 id="Wireshark的抓包原理">Wireshark的抓包原理</h3><pre><code class="hljs">Wireshark使用的环境大致分为两种,一种是电脑直连互联网的单机环境,另外一种就是应用比较多的互联网环境,也就是连接交换机的情况。</code></pre><p>「<strong>单机情况</strong>」下,Wireshark直接抓取本机网卡的网络流量;「<strong>交换机情况</strong>」下,Wireshark通过端口镜像、ARP欺骗等方式获取局域网中的网络流量。</p><ul class="lvl-0"><li class="lvl-2"><p><strong>端口镜像</strong>:利用交换机的接口,将局域网的网络流量转发到指定电脑的网卡上。</p></li><li class="lvl-2"><p><strong>ARP欺骗</strong>:交换机根据MAC地址转发数据,伪装其他终端的MAC地址,从而获取局域网的网络流量。</p></li></ul><h4 id="Wireshark的快速使用">Wireshark的快速使用</h4><pre><code class="hljs">Wireshark是一款开源软件,可以从其官网上免费下载。其官网地址为:https://www.wireshark.org</code></pre><h4 id="安装注意事项">安装注意事项</h4><pre><code class="hljs">在官网下载安装包后运行安装程序,在安装过程中有几个注意点:</code></pre><ol><li class="lvl-3"><p>在安装过程中注意安装Npcap这个组件,这个组件是Wireshark在进行网络检测时的重要组件,没有这个组件抓包可能无法进行。</p></li></ol><p><img src="image-20221101234742798.png" alt="WireShark安装"></p><p><img src="Npcap%E5%AE%89%E8%A3%85.jpg" alt="Npcap安装"></p><ol start="2"><li class="lvl-3"><p>在安装Wireshark时需要选择安装哪些工具,建议全部勾选,大部分较为常用。</p><p><img src="image-20221101234817779.png" alt="WireShark安装"></p></li><li class="lvl-3"><p>安装过程中需要勾选USB驱动,便于日后无法检测其他USB端口以及串口。</p><p><img src="image-20221101235022852.png" alt="USBPcap"></p><p><img src="/%E9%99%84%E5%B8%A6%E7%9A%84USB%E6%80%BB%E7%BA%BF.jpg" alt="附带的USB总线"></p><p>在安装完成后,打开软件将看见如下界面:</p></li></ol><p><img src="image-20221101005326034.png" alt="WireShark界面"></p><pre><code class="hljs">这里显示了目前我们的机器上面的所有的网卡设备,这里的网卡设备不仅仅只有真正的硬件设备,同时也有电脑中的虚拟网卡。。本地连接是我曾经连接的一下网线连接,由于此时我使用的是WLAN,所有的本地连接目前都是没有网络波动的。我的电脑中安装了VMware,此时有虚拟机在后台运行,所以VMnet8与VMnet1网卡中也存在着网络波动。Adapter for lookback traffic capture是我的机器的环回接口,即127.0.0.1。只有确定了我们抓包需求之后,选择正确的网卡,我们才能得到我们真正想要的数据。双击需要进行抓包的网卡,屏幕上开始实时显示软件所有的通过网卡的数据流,此时已经开始自动捕获数据流并记录。</code></pre><p><img src="image-20221101152526811.png" alt="抓包界面"></p><pre><code class="hljs">在这个界面的左上角可以进行录制进度的控制,随时可以进行暂停、停止、继续等操作,也可以进行一些分组操作等。</code></pre><p><img src="image-20221101180241263.png" alt="抓包界面"></p><pre><code class="hljs">基本学会如何去使用Wireshark抓包软件就可以进一步去探索某些具体协议的底层数据链路过程了。</code></pre><h2 id="三、具体作业">三、具体作业</h2><h3 id="详细了解ping命令">详细了解ping命令</h3><h4 id="ping命令的原理">ping命令的原理</h4><pre><code class="hljs">ping命令是一个检测网络间两个IP之间的连通性的工具。他实质是一段程序,存储在计算机的`C:\Windows\System32\PING.EXE`位置。</code></pre><p><img src="image-20221102063823268.png" alt="Ping程序"></p><pre><code class="hljs">他可以调用ICMP协议,给指定的一个IP地址发送一个封装好的数据包,如果那个IP存在,再次经过IMCP协议的处理,会返货一个同样大小的数据包会来。如果在一定时间内,本机好没有收到对方IP返回的数据包,则会默认为超时,即为连接不通。ping命令是一个很好的连通性检测工具,但是也并不是ping命令结果为超时就代表这个指定IP不存在,由IP的底层原理就可以看出,想要ping命令生效,检测的双方必须都支持ICMP协议,如果指定IP的那个一方的防火墙被设定为不支持ICMP协议的,则会拒绝掉所有采用ICMP协议的数据包,我方自然不会收到对方应答的数据包。这种不支持ICMP协议的设备在网络中很多,在我们连接某一个公网IP的时候,我们的请求在网络中走的每一跳,通过`tracert`命令,追踪到每一跳经过的机器的IP地址,`tracert`命令会再次对每一跳到达的IP地址进行ping,由于我们访问的目的IP是存在的,那我们的数据包是经过追踪出的每一个IP转发出去的,这些IP在公网中一定是存在的,但是由于其不支持ICMP协议,显然ping命令不能检测到他们,证明ping命令也具有局限性。</code></pre><p><img src="image-20221102065331549.png" alt="本站监测结果"></p><h4 id="ping命令的执行过程">ping命令的执行过程</h4><h5 id="同一网段">同一网段</h5><ul class="lvl-0"><li class="lvl-2"><p><code>ping</code>通知系统建立一个固定格式的<code>ICMP</code>请求数据包</p></li><li class="lvl-2"><p><code>ICMP</code>协议打包这个数据包和机器<code>B</code>的<code>IP</code>地址转交给<code>IP</code>协议层</p></li><li class="lvl-2"><p><code>IP</code>层协议将以机器<code>B</code>的<code>IP</code>地址为目的地址,本机<code>IP</code>地址为源地址,加上一些其他的控制信息,构建一个IP数据包</p></li><li class="lvl-2"><p>获取机器<code>B</code>的<code>MAC</code>地址</p></li></ul><p><code>IP</code>层协议通过机器<code>B</code>的<code>IP</code>地址和自己的子网掩码,发现它跟自己属同一网络,就直接在本网络查找这台机器的<code>MAC</code>。</p><p>若两台机器之前有过通信,在机器<code>A</code>的<code>ARP</code>缓存表应该有<code>B</code>机<code>IP</code>与其<code>MAC</code>的映射关系;若没有,则发送<code>ARP</code>请求广播,得到机器<code>B</code>的<code>MAC</code>地址,一并交给数据链路层</p><p>数据链路层构建一个数据帧,目的地址是<code>IP</code>层传过来的<code>MAC</code>地址,源地址是本机的<code>MAC</code>地址,再附加一些控制信息,依据以太网的介质访问规则,将他们传送出去机器B收到这个数据帧后,先检查目的地址,和本机<code>MAC</code>地址对比</p><p>符合,接收。接收后检查该数据帧,将<code>IP</code>数据包从帧中提取出来,交给本机的<code>IP</code>协议层协议。<code>IP</code>层检查后,将有用的信息提取交给<code>ICMP</code>协议,后者处理后,马上构建一个<code>ICMP</code>应答包,发送给主机A,其过程和主机A发送ICMP请求包到主机B类似(这时候主机B已经知道了主机A的MAC地址,不需再发ARP请求);不符合,丢弃。</p><h5 id="不同网段">不同网段</h5><ul class="lvl-0"><li class="lvl-2"><p><code>ping</code>通知系统建立一个固定格式的<code>ICMP</code>请求数据包</p></li><li class="lvl-2"><p><code>ICMP</code>协议打包这个数据包和机器<code>B</code>的<code>IP</code>地址转交给<code>IP</code>协议层(一组后台运行的进程,与<code>ICMP</code>类似)</p></li><li class="lvl-2"><p><code>IP</code>层协议将以机器<code>B</code>的<code>IP</code>地址为目的地址,本机<code>IP</code>地址为源地址,加上一些其他的控制信息,构建一个<code>IP</code>数据包</p></li><li class="lvl-2"><p>获取主机<code>B</code>的<code>MAC</code>地址</p></li></ul><p><code>IP</code>协议通过计算发现主机<code>B</code>与自己不在同一网段内,就直接交给路由处理,就是将路由的<code>MAC</code>取过来,至于怎么得到路由的<code>MAC</code>地址,和之前一样,先在<code>ARP</code>缓存表中寻找,找不到可以利用广播。路由得到这个数据帧之后,再跟主机<code>B</code>联系,若找不到,就向主机<code>A</code>返回一个超时信息。</p><h4 id="ping命令产生的数据包详解">ping命令产生的数据包详解</h4><pre><code class="hljs">ping命令本身属于应用层,在执行的时候会通过调用网络层TCP/IP协议簇中的ICMP协议,此时首先会产生一个IMCP数据报文,报文的所有内容如如下图所示:</code></pre><p><img src="image-20221102112810945.png" alt="ICMP报文格式"></p><p>将其中的内容大致分开,可分为两个部分,分别是ICMP首部和ICMP数据</p><p>为了进行传输,在网络层中还会再次在ICMP报文前面加上IP首部,首部主要包括双方的IP地址等</p><p><img src="image-20221102111633184.png" alt="ICMP报文封装进IP数据报"></p><p>这里就完成了网络层的IP数据包的封装</p><p>网络层将封装好的IP数据包传输到下一层数据链路层,在这里会进行再次封装,在IP数据包前面加入帧首部,主要是双方的MAC地址。如果本机内的ARP缓存中存储着IP对应的MAC地址,则直接使用ARP缓存中的MAC地址;如果没有则计算子网掩码,如果发现在同一网段中直接发送ARP广播从而获取对应IP的MAC地址,如果不在同一网段,则先向上层路由器获取MAC地址,路由器如果具有则从路由器的ARP缓存中获取,没有则路由器向上层继续申请。原本的IP数据包就成为了帧数据区。</p><p>此时这个数据包就可以转成二进制流通过物理层传输出去。</p><p>当这个数据包通过物理层传输到另一台机器的时候,目的机器会从物理层到数据链路层到网络层,与封包过程相反,将数据包解开</p><p>在数据链路层去除掉帧首部,得到IP数据包,在网络层解析出其中的ICMP数据报,并做出相应的回复,此时不再去寻找来源机器的IP与MAC地址,全部可以从数据包中获得。ICMP协议处理数据之后将相应的数据包返回给来源机器,当执行ping的机器收到数据包,可以统计这一整个过程的时长从而以及接收的数据包是否完整,从计算出对应的延迟与丢包率。</p><h4 id="Wireshark抓包分析">Wireshark抓包分析</h4><pre><code class="hljs">通过Wireshark抓包,可以获取一段时间内设备上的所有的数据包的收发记录</code></pre><p><img src="image-20221102113300338.png" alt="WireShark抓包分析"></p><pre><code class="hljs">这是在ping命令执行期间所有的经过WLAN网卡数据包的记录,通过显示过滤可以获取到ping命令的数据包限定到达的IP地址可以过滤出相关的数据包,我ping的目标地址是192.168.31.200所以使用`ip.dst == 192.168.31.200`命令就可以过滤出所有目的地址为192.168.31.200的数据包</code></pre><p><img src="image-20221102125639735.png" alt="通过目的地址进行过滤"></p><pre><code class="hljs">过滤后可以看见有四条相同的抓包记录,分别对应了Windows的四次抓包</code></pre><p><img src="image-20221102130125548.png" alt="Ping记录"></p><p>每一次进行ping测试都会有一个对应产生的数据包。</p><h3 id="分析访问网站的过程">分析访问网站的过程</h3><h4 id="访问网站的全部流程">访问网站的全部流程</h4><ul class="lvl-0"><li class="lvl-2"><p>本机访问DNS服务器,收到DNS服务器返回请求域名的IP</p></li><li class="lvl-2"><p>建立TCP协议的三次握手</p></li><li class="lvl-2"><p>通过www协议从服务器获取数据</p></li><li class="lvl-2"><p>TCP/IP进行四次挥手断开连接</p></li></ul><h4 id="访问网站产生的相关数据包的解析">访问网站产生的相关数据包的解析</h4><h5 id="捕捉DNS请求过程">捕捉DNS请求过程</h5><p>在访问网站的时候,首先设备需要知道目的网站的IP地址,在有域名的情况下,先在本机的host文件内寻找;若没有,则请求所连接的局域网内的路由器的DNS缓存来获取,仍然没有则需要去DNS服务器内寻找相应的与域名对应的IP地址。</p><p>在Wireshark软件在访问<code>www.ujs.edu.cn</code>这段时间内进行抓包记录,再对抓取的结果进行过滤,即可找到相关过程的数据包。</p><p>为了找到我们寻找<code>www.ujs.edu.cn</code>这个域名所对应的IP的时候相关的数据包,可以通过协议的方式来过滤我们抓去到的结果。</p><p><img src="image-20221102182757945.png" alt="通过DNS协议寻找数据包"></p><p>在抓取结果的上方直接输入我们需要找的数据包采用的协议,可以直接过滤出所有采用这种协议的数据包。</p><p>输入<code>dns</code>后在访问网站过程中的所有采用<code>dns</code>协议的数据包会被一一罗列。通过Info栏下的信息,我们可以找到对<code>www.ujs.edu.cn</code>这个域名IP地址的请求数据包以及相应的应答数据包。</p><p>通过这个数据包我们可以获得到<code>www.ujs.edu.cn</code>这个域名所对应的IP地址为<code>36.156.27.229</code>。</p><h5 id="捕捉连接的过程">捕捉连接的过程</h5><p>在获取到域名对应的IP地址后,通过这个IP使用TCP/IP协议,建立TCP连接。</p><p><img src="image-20221102184747297.png" alt="监测TCP连接过程进行抓包"></p><p>从抓包的结果来看,数据交换采用的协议为TCP协议和TLSv1.3协议。</p><p>TCP协议是用来在广域网中与服务器建立连接用的,其过程双方在三次握手后建立相互保持的连接,然后稳定的传输数据,再经过三次挥手的过程来断开连接,在连接的过程中一但有一方单开了连接则整改连接过程全部关闭。</p><p>而TLS协议是由于目标网站开启了https服务。由于普通的http协议在传输过程中所有的数据都是明文传输,导致了传输过程通过抓包即可获取所有的传输数据,通过这个协议的加入,在连接开始传输数据之前,可以进行双方的秘钥的分发,从而进行加密传输,增强了传输数据的安全性。</p><h4 id="TCP协议的数据包分析">TCP协议的数据包分析</h4><p>(1)TCP分析:一个TCP报文段分为首部和数据两部分。TCP报文段首部的前二十个字节是固定的,后面有4N个字节是根据需要而增加的选项。因此TCP的最小长度是20个字节。</p><p><img src="image-20221102191437188.png" alt="分析TCP数据包"></p><p>(2)源端口和目的端口字段:各占两个字节,分别写入源端口号和目的端口号。在抓取的数据报中,源端口号和目的端口号的值分别是:443和26739</p><p><img src="image-20221102191556848.png" alt="寻找目的端口和源端口"></p><p>序号字段:占4个字节。序号范围是0到2^32-1 ,共2^32个序号</p><p>(3)确认号字段:在四个字节,是期望收到对方下一个报文段的第一个字节的序号。</p><p><img src="image-20221102191740214.png" alt="确认号字段"></p><p>(4)数据偏移字段:占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段实际上是指出TCP报文段的首部长度。由于首部中还有长度不确定的选项字段。因此数据偏移字段是必要的。现在本字段的值是32。</p><p><img src="image-20221102191822666.png" alt="数据偏移字段"></p><p>(5)保留字段:占6位,保留为今后使用;(6)窗口字段:占两个字节。窗口指的是发送本报文段的一方的接收窗口,而不是自己的发送窗口。本数据包中窗口字段的值是64240。</p><p><img src="image-20221102191916127.png" alt="窗口字段"></p><p>(7)校验和字段:占2个字节。校验和字段检验的范围包括首部和数据这两部分。</p><p><img src="image-20221102192047826.png" alt="校验和字段"></p><p>(8)紧急指针字段:占两个字节。紧急指针仅仅在URG=1时才有意义,它指出+选项字段:长度可变最长可达40个字节,当没有使用选项时,TCP的首部长度是20个字节。本数据包中没有选项字段。</p><h3 id="数据链路层与网络层的具体思考">数据链路层与网络层的具体思考</h3><p>数据链路层是OSI网络模型的倒数第二层,上层为网络层,下层为物理层,其作用为将网络层的数据转换成可以在物理层中传输的数据流的形式,也就是说数据链路层将网络层传来的IP数据包加上帧首部之后,封装成数据包,其表识方式为机器的MAC地址。</p><p>网络层是OSI网络模型的倒数第三层,其中具有大量的网络协议,其主要是从将应用层的数据封装,在数据包前加上IP报头,IP与数据链路层中的MAC地址有些类似,但是IP地址更适用于在大型的网络中进行传输。</p><p>数据链路层功能主要有:</p><ul class="lvl-0"><li class="lvl-2"><p>逻辑链路控制</p></li><li class="lvl-2"><p>媒体访问控制</p></li><li class="lvl-2"><p>封装链路层帧</p></li><li class="lvl-2"><p>MAC 寻址</p></li><li class="lvl-2"><p>差错检测与处理</p></li><li class="lvl-2"><p>定义物理层标准</p></li></ul><p>网络层主要功能为:</p><ul class="lvl-0"><li class="lvl-2"><p>IP 寻址</p></li><li class="lvl-2"><p>选路</p></li><li class="lvl-2"><p>封装打包</p></li><li class="lvl-2"><p>分片</p><p>总体来说,在当前网络规模巨大的背景下,单纯靠MAC地址去传输是不切实际的,现在的数据链路层更多的是与物理层一起为网络层的传输提供服务。而网络层是在数据链路层提供的两个相邻端点之间的数据帧的传送功能上,进一步管理网络中的数据通信,将数据设法从源端经过若干个中间节点传送到目的端,从而向运输层提供最基本的端到端的数据传送服务。只有当两层一起共同工作,共同发挥作用才能让保障我们的网络稳定与畅通。</p></li></ul>]]></content>
<summary type="html"><h2 id="一、作业目的">一、作业目的</h2>
<ol>
<li class="lvl-3">了解网络通信的分层实现过程,了解不同层次PDU的逐层封装与解封过程;</li>
<li class="lvl-3">了解数据通信的过程,进一步认知协议的构成与通信过程,进而对TC</summary>
<category term="大学学习" scheme="https://xiaolaji.site/categories/%E5%A4%A7%E5%AD%A6%E5%AD%A6%E4%B9%A0/"/>
<category term="大作业" scheme="https://xiaolaji.site/tags/%E5%A4%A7%E4%BD%9C%E4%B8%9A/"/>
</entry>
<entry>
<title>Linux用户权限管理</title>
<link href="https://xiaolaji.site/20221003/Linux%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86/"/>
<id>https://xiaolaji.site/20221003/Linux%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86/</id>
<published>2022-10-04T01:23:21.000Z</published>
<updated>2023-05-27T03:19:52.000Z</updated>
<content type="html"><![CDATA[<p>Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管 理员申请一个账号,然后以这个账号的身份进入系统。</p><p>为了更加方便的管理多个用户,就出现了用户组的概念,关于用户和用户组:</p><ul class="lvl-0"><li class="lvl-2"><p>系统上的每个进程(运行的程序)都是作为特定用户运行</p></li><li class="lvl-2"><p>每个文件是由一个特定的用户拥有</p></li><li class="lvl-2"><p>访问文件和目录受到用户的限制</p></li><li class="lvl-2"><p>与正在运行的进程相关联的用户确定该进程可访问的文件和目录</p></li></ul><p>实现用户账号的管理,要完成的工作主要有如下几个方面:</p><ul class="lvl-0"><li class="lvl-2"><p>用户账号的添加、删除与修改</p></li><li class="lvl-2"><p>用户账号的添加、删除与修改</p></li><li class="lvl-2"><p>用户账号的添加、删除与修改</p></li></ul><h1>用户和用户组查看</h1><h2 id="id">id</h2><p>xxxxxxxxxx static { System.out.println(“我是静态代码块中的内容”);}//这个会随着类的加载而加载,即在整个程序的最开始的时候进行执行。而且只加载一次就可以,不管其出现在什么地方java</p><p>id会显示用户以及所属群组的实际与有效ID。若两个ID相同,则仅显示实际ID。若仅指定用户名称,则 显示目前用户的ID。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">id [OPTION]... [USER]<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>-g:显示用户所属群组的ID。</p></li><li class="lvl-2"><p>-G:显示用户所属附加群组的ID。</p></li><li class="lvl-2"><p>-n:显示用户,所属群组或附加群组的名称。</p></li><li class="lvl-2"><p>-n:显示用户,所属群组或附加群组的名称。</p></li><li class="lvl-2"><p>-u:显示用户ID。</p></li></ul><h3 id="uid的约定">uid的约定</h3><p>Linux操作系统会依据用户的uid数值来判定这个用户的角色,分别如下</p><ul class="lvl-0"><li class="lvl-2"><p>0:超级管理员,也就是root,在linux系统中拥有所有权力</p></li><li class="lvl-2"><p>1~999:系统用户,系统用户往往是用来约束系统中的服务的</p></li><li class="lvl-2"><p>1000+:普通用户,可以用来登陆和使用Linux操作系统</p></li></ul><p>关于root用户</p><ul class="lvl-0"><li class="lvl-2"><p>uid是0</p></li><li class="lvl-2"><p>拥有操作系统所有权力</p></li><li class="lvl-2"><p>该用户有权力覆盖文件系统上的普通权限</p></li><li class="lvl-2"><p>安装或删除软件并管理系统文件和目录</p></li><li class="lvl-2"><p>大多数设备只能由root控制</p></li></ul><h3 id="实例">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>查看当前登陆的用户信息</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# id<br>uid=0(root) gid=0(root) 组=0(root) 环境<br>=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查看文件的拥有者</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# ll anaconda-ks.cfg<br>-rw-------. 1 root root 1241 4月 4 16:53 anaconda-ks.cfg<br></code></pre></td></tr></table></figure><p><img src="image-20220714090329104.png" alt="ll命令解析"></p><ul class="lvl-0"><li class="lvl-2"><p>查看运行进程的用户名,ps命令会在后面进程管理部分讲解</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# ps aux<br>USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND<br>root 2 0.0 0.0 0 0 ? S 09:06 0:00 [kthreadd]<br>root 3 0.0 0.0 0 0 ? S 09:06 0:01 [ksoftirqd/0]<br>root 4 0.1 0.0 0 0 ? R 09:06 0:09 [kworker/0:0]<br>root 5 0.0 0.0 0 0 ? S< 09:06 0:00 [kworker/0:0H]<br></code></pre></td></tr></table></figure><h1>相关的文件</h1><p>之前说过Linux一切皆文件,所以用户和用户组相关的信息也都是保存在文本文件中的,下面列举出相关 的文件。</p><h2 id="passwd文件">passwd文件</h2><p>用于保存用户的信息,一般第一行是root用户,下面都是其他用户</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# head -n 1 /etc/passwd<br>root:x:0:0:root:/root:/bin/bash<br><span class="hljs-meta prompt_"># </span><span class="language-bash">这个格式为用户名:密码:uid:gid:描述:家目录:登陆后执行的命令</span><br></code></pre></td></tr></table></figure><h2 id="shadow文件">shadow文件</h2><p>格式中密码占位置太长了,所以使用x来替代,Linux系统会到shadow中查找x部分的的密码内容</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# head -n 1 /etc/shadow<br>root:$6$frokclXSnQa8EbKs$pWElbjPlmxjYh30tr8qLsTQVOhuPg7GmW9Sanm2yXAK8TNMgje1g<br>yc/vwPgqvmSMf6VaoEvveM0gFvtETmXy/.::0:99999:7:::<br><span class="hljs-meta prompt_"># </span><span class="language-bash">这个格式为用户名:加密密码:最后一次修改时间:最小修改时间间隔:密码有效期:密码需要变更前</span><br>的警告天数:密码过期后的宽限时间:账号失效时间:保留字段<br></code></pre></td></tr></table></figure><p>格式不需要大家记住,只需要知道关于这个用户的密码和有效期都在这个文件中即可。 密码在 passwd 文件中会使用加密算法加密,所以别想知道我的密码是什么,加密算法默认是 $6 ,这个 类型6的加密算法是sha-512。我们也可以在man手册中看到对shadow文件的详细解释。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# man 5 shadow<br><span class="hljs-meta prompt_"># </span><span class="language-bash">man手册一个有9个章节,其中第5个章节是对文件格式的说明</span><br><span class="hljs-meta prompt_"># </span><span class="language-bash">对man手册感兴趣的同学,也可以自己在网上查找学习man手册的更多内容</span><br></code></pre></td></tr></table></figure><h2 id="group文件">group文件</h2><p>用户和组的对应关系,会保存在group文件中</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# head -n 1 /etc/group<br>root:x:0:<br><span class="hljs-meta prompt_"># </span><span class="language-bash">这个格式是组名:口令:组标识号:组内用户列表</span><br></code></pre></td></tr></table></figure><h2 id="group文件-2">group文件</h2><p>用户和组的对应关系,会保存在group文件中</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# head -n 1 /etc/group<br>root:x:0:<br><span class="hljs-meta prompt_"># </span><span class="language-bash">这个格式是组名:口令:组标识号:组内用户列表</span><br></code></pre></td></tr></table></figure><h1>用户组管理</h1><h2 id="添加用户组:groupadd">添加用户组:groupadd</h2><p>groupadd 命令用于创建一个新的工作组,新工作组的信息将被添加到系统文件中</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">groupadd [选项] 组<br></code></pre></td></tr></table></figure><h2 id="选项">选项</h2><ul class="lvl-0"><li class="lvl-2"><p>-g:指定新建工作组的 id;</p></li><li class="lvl-2"><p>-r:创建系统工作组,系统工作组的组ID小于 500;</p></li><li class="lvl-2"><p>-K:覆盖配置文件 /etc/login.defs</p></li><li class="lvl-2"><p>-o:允许添加组 ID 号不唯一的工作组。</p></li><li class="lvl-2"><p>-f:如果指定的组已经存在,此选项将失明了仅以成功状态退出。当与 -g 一起使用,并且指定的 GID_MIN已经存在时,选择另一个唯一的GID(即-g关闭)。</p></li></ul><h3 id="实例-2">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>按照下图创建组,并且指定gid,并且检查是否成功</p></li></ul><p><img src="image-20220714120434011.png" alt="创建组示例"></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# groupadd hr -g 1000<br>[root@localhost ~]# groupadd sale -g 2000<br>[root@localhost ~]# groupadd it -g 3000<br>[root@localhost ~]# groupadd fd -g 4000<br>[root@localhost ~]# tail -n 4 /etc/group<br>hr:x:1000:<br>sale:x:2000:<br>it:x:3000:<br>fd:x:4000:<br></code></pre></td></tr></table></figure><h2 id="修改用户组:groupmod">修改用户组:groupmod</h2><p>groupmod命令用于更改群组识别码或名称</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">groupmod [选项] 组<br></code></pre></td></tr></table></figure><h3 id="选项-2">选项</h3><ul class="lvl-0"><li class="lvl-2"><p>-g:将组 ID 改为 GID</p></li><li class="lvl-2"><p>-n:改名为 NEW_GROUP</p></li><li class="lvl-2"><p>-o:允许使用重复的 GID</p></li></ul><h3 id="实例-3">实例</h3><p>修改fd组的名字为finance</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# groupmod -n finance fd<br>[root@localhost ~]# tail -n 1 /etc/group<br>finance:x:4000:<br></code></pre></td></tr></table></figure><h2 id="删除用户组:groupdel">删除用户组:groupdel</h2><p>groupdel命令用于删除群组</p><p>需要从系统上删除群组时,可用groupdel(group delete)指令来完成这项工作。倘若该群组中仍包括某 些用户,则必须先删除这些用户后,方能删除群组。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">groupdel [组名]<br></code></pre></td></tr></table></figure><h3 id="实例-4">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>删除一个用户组</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# groupadd test<br>[root@localhost ~]# groupdel test<br></code></pre></td></tr></table></figure><h2 id="用户组成员管理:gpasswd">用户组成员管理:gpasswd</h2><p>gpasswd 是 Linux 下工作组文件 /etc/group 和 /etc/gshadow 管理工具,用于将一个用户添加到组或 者从组中删除</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">gpasswd [选项] 组<br></code></pre></td></tr></table></figure><h3 id="选项-3">选项</h3><ul class="lvl-0"><li class="lvl-2"><p>-a:添加用户到组;</p></li><li class="lvl-2"><p>-d:从组删除用户;</p></li><li class="lvl-2"><p>-A:指定管理员;</p></li><li class="lvl-2"><p>-M:指定组成员和-A的用途差不多;</p></li><li class="lvl-2"><p>-R:限制用户登入组,只有组中的成员才可以用newgrp加入该组。</p></li></ul><h3 id="实例-5">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>创建用户itadmin,并且将其加入it组</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# useradd itadmin<br>[root@localhost ~]# gpasswd -a itadmin it<br>正在将用户“itadmin”加入到“it”组中<br>[root@localhost ~]# cat /etc/group |grep it:<br>it:x:3000:itadmin<br><span class="hljs-meta prompt_"># </span><span class="language-bash">在组文件中,可以看到这个组的成员</span><br>[root@localhost ~]# id itadmin<br>uid=6667(itadmin) gid=6667(itadmin) 组=6667(itadmin),3000(it)<br><span class="hljs-meta prompt_"># </span><span class="language-bash">在用户的信息中,可以看到这个用户的所属组</span><br></code></pre></td></tr></table></figure><h1>用户管理</h1><h2 id="添加用户:useradd">添加用户:useradd</h2><p>useradd可以用来添加新的用户账号</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">useradd [选项] 用户名<br></code></pre></td></tr></table></figure><h3 id="选项-4">选项</h3><ul class="lvl-0"><li class="lvl-2"><p><strong>-c</strong> **comment:**指定一段注释性描述。</p></li><li class="lvl-2"><p><strong>-d</strong> **目录:**指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主目录。</p></li><li class="lvl-2"><p><strong>-m</strong>:创建用户的主目录</p></li><li class="lvl-2"><p><strong>-g</strong> **用户组:**指定用户所属的用户组,默认会创建一个和用户名同名的用户组。</p></li><li class="lvl-2"><p><strong>-G</strong> **用户组:**用户组 指定用户所属的附加组,一个用户可以属于多个附加组。</p></li><li class="lvl-2"><p><strong>-s</strong> **Shell文件:**指定用户的登录Shell。</p></li><li class="lvl-2"><p>**-u 用户号:**指定用户的用户号,如果同时有-o选项,则可以重复使用其他用户的标识号。</p></li></ul><h3 id="实例-6">实例</h3><p>添加一般用户</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# useradd user01<br></code></pre></td></tr></table></figure><p>为添加的用户指定相应的用户组</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# useradd -g root user02<br></code></pre></td></tr></table></figure><p>为新添加的用户指定home目录</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# useradd -d /home/test user03<br></code></pre></td></tr></table></figure><p>建立一个不给登录的用户</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# useradd -s /sbin/nologin user04<br></code></pre></td></tr></table></figure><h2 id="修改用户:usermod">修改用户:usermod</h2><p>usermod命令用于修改用户帐号</p><p>usermod可用来修改用户帐号的各项设定</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">usermod [选项] 登录<br></code></pre></td></tr></table></figure><h3 id="选项-5">选项</h3><ul class="lvl-0"><li class="lvl-2"><p>**-c<备注>:**修改用户帐号的备注文字。</p></li><li class="lvl-2"><p>**-a:**追加:默认的修改是覆盖</p></li><li class="lvl-2"><p>**-d登入目录>:**修改用户登入时的目录。</p></li><li class="lvl-2"><p>**-e<有效期限>:**修改帐号的有效期限。</p></li><li class="lvl-2"><p>**-f<缓冲天数>:**修改在密码过期后多少天即关闭该帐号。</p></li><li class="lvl-2"><p>**-g<群组>:**修改用户所属的群组。</p></li><li class="lvl-2"><p>**-G<群组>:**修改用户所属的附加群组。</p></li><li class="lvl-2"><p>**-l<帐号名称>:**修改用户帐号名称。</p></li><li class="lvl-2"><p>**L:**锁定用户密码,使密码无效。</p></li><li class="lvl-2"><p>**-s:**修改用户登入后所使用的shell。</p></li><li class="lvl-2"><p>**-u:**修改用户ID。</p></li><li class="lvl-2"><p>**-U:**解除密码锁定。</p></li></ul><h3 id="实例-7">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>更改登录的目录</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# usermod -d /home user01<br>[root@localhost ~]# su - user01<br>-bash-4.2$ pwd<br>/home<br></code></pre></td></tr></table></figure><p>改变用户的uid</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# usermod -u 6666 user02<br></code></pre></td></tr></table></figure><h2 id="删除用户:userdel">删除用户:userdel</h2><p>userdel命令用于删除用户帐号</p><p>userdel可删除用户帐号与相关的文件。若不加参数,则仅删除用户帐号,而不删除相关文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">userdel [-r][用户帐号]<br></code></pre></td></tr></table></figure><h3 id="选项-6">选项</h3><ul class="lvl-0"><li class="lvl-2"><p>-r:删除用户登入目录以及目录中所有文件</p></li></ul><h3 id="实例-8">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>删除用户账号</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# userdel user04<br></code></pre></td></tr></table></figure><h1>passwd文件中的shell</h1><p>查看 /etc/passwd 文件会发现在每行的最后是登录成功之后执行的命令,有两种是使用最为频繁的:</p><ul class="lvl-0"><li class="lvl-2"><p>/bin/bash:这个是Linux的命令行工具,我们正常登陆之后默认就是进入命令行</p></li><li class="lvl-2"><p>/sbin/nologin:如果写成nologin,那么用户将无法登录,有些用户是作为进程权限管理而存在 的,不需要登录。如果提供登录的功能反而不安全,所以写成nologin</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# cat /etc/passwd<br>root:x:0:0:root:/root:/bin/bash<br>bin:x:1:1:bin:/bin:/sbin/nologin<br>daemon:x:2:2:daemon:/sbin:/sbin/nologin<br>adm:x:3:4:adm:/var/adm:/sbin/nologin<br>lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin<br></code></pre></td></tr></table></figure><p>我们可以新建一个用户,然后尝试自定义登录成功之后执行的命令,用来加深印象。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# useradd test01<br>[root@localhost ~]# tail -n 1 /etc/passwd<br>test01:x:1000:1000::/home/test01:/bin/vi<br></code></pre></td></tr></table></figure><p>切换到test01用户,会发现自动进入vi的界面,说明最后的这个段内容就是用户登录之后会运行的程序</p><p><img src="image-20220714122150998.png" alt="用户逻辑图"></p><h1>用户密码管理</h1><p>root用户可以直接设置普通用户密码,普通用户必须要提供原密码,才可以修改自己密码。</p><h2 id="passwd">passwd</h2><p>passwd命令用来更改使用者的密码</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">passwd [选项...] <帐号名称><br></code></pre></td></tr></table></figure><h3 id="选项-7">选项</h3><ul class="lvl-0"><li class="lvl-2"><p>-k:保持身份验证令牌不过期</p></li><li class="lvl-2"><p>-d:删除已命名帐号的密码(只有根用户才能进行此操作)</p></li><li class="lvl-2"><p>-l:锁定指名帐户的密码(仅限 root 用户)</p></li><li class="lvl-2"><p>-u:解锁指名账户的密码(仅限 root 用户)</p></li><li class="lvl-2"><p>-x:密码的最长有效时限(只有根用户才能进行此操作)</p></li><li class="lvl-2"><p>-n:密码的最短有效时限(只有根用户才能进行此操作)</p></li><li class="lvl-2"><p>-w:在密码过期前多少天开始提醒用户(只有根用户才能进行此操作)</p></li><li class="lvl-2"><p>-i:当密码过期后经过多少天该帐号会被禁用(只有根用户才能进行此操作)</p></li><li class="lvl-2"><p>-S:报告已命名帐号的密码状态(只有根用户才能进行此操作)</p></li><li class="lvl-2"><p>–stdin:从标准输入读取令牌(只有根用户才能进行此操作)</p></li></ul><h3 id="实例-9">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>修改test01用户密码</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# passwd test01<br>更改用户 test01 的密码 。<br>新的 密码:<br>重新输入新的 密码:<br>passwd:所有的身份验证令牌已经成功更新。<br></code></pre></td></tr></table></figure><p>使用管道符设置用户密码</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# echo 123456 | passwd --stdin test01<br>更改用户 test01 的密码 。<br>passwd:所有的身份验证令牌已经成功更新。<br></code></pre></td></tr></table></figure><h1>login.defs文件</h1><p>/etc/login.defs 文件是用来创建用户时进行一定的限制,但是优先级低于 /etc/passwd 和 /etc/shadow ,如果有冲突的地方,系统会以 /etc/passwd 和 /etc/shadow 为准</p><p>下面是这个文件的内容,egrep命令我们后续会讲到,这边可以理解为不看文件的注释和空行。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# egrep -v '^[ ]*$|^#' /etc/login.defs<br>MAIL_DIR /var/spool/mail # 系统消息(邮件)文件夹<br>PASS_MAX_DAYS 99999 # 密码有效最大天数<br>PASS_MIN_DAYS 0 # 密码有效最小天数<br>PASS_MIN_LEN 5 # 密码长度<br>PASS_WARN_AGE 7 # 密码失效警告倒计时<br>UID_MIN 1000 # 用户UID最小1000<br>UID_MAX 60000 # 用户UID最大60000<br>SYS_UID_MIN 201 # 系统用户UID最小201<br>SYS_UID_MAX 999 # 系统用户UID最大999<br>GID_MIN 1000 # 用户组GID最小1000<br>GID_MAX 60000 # 用户组GID最大60000<br>SYS_GID_MIN 201<br>SYS_GID_MAX 999<br>CREATE_HOME yes # 创建家目录<br>UMASK 077 # 创建文件/目录的权限掩码<br>USERGROUPS_ENAB yes # 创建用户时同时生成组是 如果此处是no 创建的用户 会是<br>gid=100(users)groups=100(users)<br>ENCRYPT_METHOD SHA512 # 加密 方法 sha 512 这个方法生成的密码<br>在/etc/shadow里面的第二列会以$6$开头<br></code></pre></td></tr></table></figure><h2 id="chage">chage</h2><p>chage是用于更改用户密码过期信息</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">chage [选项] 登录<br></code></pre></td></tr></table></figure><h3 id="选项-8">选项</h3><ul class="lvl-0"><li class="lvl-2"><p>-d:将最近一次密码设置时间设为“最近日期”</p></li><li class="lvl-2"><p>-E 过期日期:将帐户过期时间设为“过期日期”</p></li><li class="lvl-2"><p>-I INACITVE:过期 INACTIVE 天数后,设定密码为失效状态</p></li><li class="lvl-2"><p>-l:显示帐户年龄信息</p></li><li class="lvl-2"><p>-l:显示帐户年龄信息</p></li><li class="lvl-2"><p>-M 最大天数:将两次改变密码之间相距的最大天数设为“最大天数”</p></li><li class="lvl-2"><p>-W 警告天数:将过期警告天数设为“警告天数”</p></li></ul><h3 id="实例-10">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>强制用户在下次登录的时候换密码</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# chage -d 0 test01<br>[root@localhost ~]# logout<br>You must change your password now and login again!<br>更改用户 test01 的密码 。<br>为 test01 更改 STRESS 密码。<br>(当前)UNIX 密码:<br></code></pre></td></tr></table></figure><p>**小知识:**当你新建用户的时候,用户的home目录下会有一些默认的隐藏文件,这些隐藏文件是在创建 用户的时候从 /etc/skel/ 中复制过去的。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# cd /etc/skel<br>[root@localhost ~]# vim readme.txt<br>注意账号安全!!!<br>[root@localhost ~]# useradd user06<br>[root@localhost ~]# su -user06<br>发现里面有个readme.txt文件<br></code></pre></td></tr></table></figure><h2 id="sudoers">sudoers</h2><p>Linux是多用户多任务的操作系统, 共享该系统的用户往往不只一个。出于安全性考虑, 有必要通过 useradd创建一些非root用户, 只让它们拥有不完全的权限; 如有必要,再来提升权限执行。</p><p>sudo就是来解决这个需求的: 这些非root用户不需要知道root的密码,就可以提权到root,执行一些 root才能执行的命令。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">sudo [选项] [用户名] [命令]<br></code></pre></td></tr></table></figure><h2 id="sudo命令执行过程">sudo命令执行过程</h2><ol><li class="lvl-3"><p>当用户执行sudo时,系统会主动寻找 /etc/sudoers 文件,判断该用户是否有执行sudo的权限</p></li><li class="lvl-3"><p>确认用户具有可执行sudo的权限后,让用户输入用户自己的密码确认</p></li><li class="lvl-3"><p>确认用户具有可执行sudo的权限后,让用户输入用户自己的密码确认</p></li></ol><h2 id="赋予用户sudo操作的权限">赋予用户sudo操作的权限</h2><p>通过useradd添加的用户,并不具备sudo权限。在ubuntu/centos等系统下, 需要将用户加入admin组或 者wheel组或者sudo组。以root用户身份执行如下命令, 将用户加入wheel/admin/sudo组。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">usermod -a -G wheel <用户名><br></code></pre></td></tr></table></figure><p>如果提示wheel组不存在, 则还需要先创建该组</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">groupadd wheel<br></code></pre></td></tr></table></figure><h2 id="配置文件">配置文件</h2><p>sudo的权限控制可以在 /etc/sudoers 文件中查看到。一般来说,通过cat /etc/sudoers指令来查看该 文件, 会看到如下几行代码。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# egrep -v '^[ ]*$|^#' /etc/sudoers<br>=====省略=====<br>root ALL=(ALL) ALL<br><span class="hljs-meta prompt_">%</span><span class="language-bash">wheel ALL=(ALL) ALL</span><br></code></pre></td></tr></table></figure><p>对/etc/sudoers文件进行编辑的代码公式可以概括为</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">授权用户/组 主机=[(切换到哪些用户或组)] [是否需要输入密码验证] 命令1,命令2,...<br>字段1 字段2 =[(字段3)] [字段4] 字段5<br></code></pre></td></tr></table></figure><p>凡是[ ]中的内容, 都能省略; 命令和命令之间用 , 号分隔,字段3、字段4,是可以省略的。</p><p>“字段1"不以%号开头的表示"将要授权的用户”,以%号开头的表示"将要授权的组"。</p><p>"字段2"表示允许登录的主机, ALL表示所有,;如果该字段不为ALL,表示授权用户只能在某些机器上 登录本服务器来执行sudo命令</p><p>"字段2"表示允许登录的主机, ALL表示所有,;如果该字段不为ALL,表示授权用户只能在某些机器上 登录本服务器来执行sudo命令</p><p>"字段3"如果省略, 相当于(root:root),表示可以通过sudo提权到root,如果为(ALL)或者(ALL:ALL), 表示能够提权到(任意用户:任意用户组)。</p><p>"字段4"的可能取值是NOPASSWD:。请注意NOPASSWD后面带有冒号:。表示执行sudo时可以不需 要输入密码。</p><p>比如: lucy ALL=(ALL) NOPASSWD: /bin/useradd 表示: 普通用户lucy可以在任何主机上, 通 过sudo执行/bin/useradd命令, 并且不需要输入密码</p><p>比如: peter ALL=(ALL) NOPASSWD: ALL ,表示: 普通用户peter可以在任何主机上, 通过sudo 执行任何命令, 并且不需要输入密码。</p><p>"字段5"是使用逗号分开一系列命令,这些命令就是授权给用户的操作; ALL表示允许所有操作。命令 都是使用绝对路径, 这是为了避免目录下有同名命令被执行,从而造成安全隐患。</p><p>如果你将授权写成如下安全性欠妥的格式: lucy ALL=(ALL) chown,chmod,useradd 那么用 户就有可能创建一个他自己的程序, 也命名为userad, 然后放在它的本地路径中, 如此一来他就 能够使用root来执行这个"名为useradd的程序"。这是相当危险的!</p><h2 id="编辑配置文件">编辑配置文件</h2><p>在实践中,去编辑 /etc/sudoers 文件,系统提示我没权限,这是因为 /etc/sudoers 的内容如此敏感, 以至于该文件是只读的。所以,编辑该文件前,请确认清楚你知道自己正在做什么。</p><p>强烈建议通过 visudo 命令来修改该文件,通过 visudo 修改,如果配置出错,会有提示。</p><p>官方文档推荐的做法,不是直接修改 /etc/sudoers 文件,而是将修改写在 /etc/sudoers.d/ 目录下的 文件中。如果使用这种方式修改sudoers,需要在 /etc/sudoers 文件的最后行,加上 #includedir /etc/sudoers.d 一行(默认已有)。需要注意,这个 #includedir /etc/sudoers.d 中的 # 并不是注 释,请勿修改。</p><h3 id="选项-9">选项</h3><ul class="lvl-0"><li class="lvl-2"><p>**-u:**以指定用户或 ID 运行命令(或编辑文件)</p></li><li class="lvl-2"><p>**-l:**显示出自己(执行 sudo 的使用者)的权限</p></li><li class="lvl-2"><p>**-b:**将要执行的指令放在后台执行</p></li><li class="lvl-2"><p><strong>-i:</strong> 以目标用户身份运行一个登录 shell;可同时指定一条命令。相当于切换到root,不过只需要用 户自己的密码即可。</p></li></ul><h3 id="实例-11">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>以管理员身份查看shadow文件</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# useradd user<br>[root@localhost ~]# echo 123456 | passwd --stdin user<br>[root@localhost ~]# usermod -a -G wheel user<br>[root@localhost ~]# su - user<br>[user@localhost ~]$ cat /etc/shadow<br>cat: /etc/shadow: 权限不够<br>[user@localhost ~]$ sudo -u root cat /etc/shadow<br>[sudo] user 的密码:<br>[user@localhost ~]$ sudo cat /etc/shadow<br><span class="hljs-meta prompt_"># </span><span class="language-bash">sudo -u root用的比较多,可以被精简为sudo</span><br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查看下列示例</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">papi ALL=(root) NOPASSWD: /bin/chown,/usr/sbin/useradd<br></code></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">* 表示: 用户papi能在所有可能出现的主机上, 提权到root下执行`/bin/chown`, 不必输入密码;<br>但运行`/usr/sbin/useradd`命令时需要密码<br>* 在具有sudo操作的用户下, 执行`sudo -l`可以查看到该用户被允许和被禁止运行的命令<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查看下列示例</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">papi ALL=/usr/sbin/,/sbin/,!/usr/sbin/fdisk<br></code></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">* 命令前面加上!号表示取消该命令<br>* 用户papi在所有可能出现的主机上, 能够运行目录/usr/sbin和/sbin下所有的程序, 但fdisk除外。<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>默认情况下输入一次sudo可以保持15分钟不再要求输入密码,如果想要延长这个时间,可以修改 配置文件</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# visudo<br>Defaults env_reset,pwfeedback,timestamp_timeout=60<br><span class="hljs-meta prompt_"># </span><span class="language-bash">这个是改成60分钟才会需要再次输入密码,并且输入密码的时候会显示*号</span><br></code></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管 理员申请一个账号,然后以这个账号的身份进入系统。</p>
<p>为了更加方便的管理多个用户,就出现了用户组的概念,关于用户和用户组:</p>
<ul class="lvl-0"</summary>
<category term="Linux" scheme="https://xiaolaji.site/categories/Linux/"/>
<category term="Linux权限管理" scheme="https://xiaolaji.site/tags/Linux%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86/"/>
</entry>
<entry>
<title>Linux文件基本属性与文件查找</title>
<link href="https://xiaolaji.site/20221003/Linux%E6%96%87%E4%BB%B6%E5%9F%BA%E6%9C%AC%E5%B1%9E%E6%80%A7%E4%B8%8E%E6%96%87%E4%BB%B6%E6%9F%A5%E6%89%BE/"/>
<id>https://xiaolaji.site/20221003/Linux%E6%96%87%E4%BB%B6%E5%9F%BA%E6%9C%AC%E5%B1%9E%E6%80%A7%E4%B8%8E%E6%96%87%E4%BB%B6%E6%9F%A5%E6%89%BE/</id>
<published>2022-10-04T01:21:22.000Z</published>
<updated>2023-05-27T03:19:42.000Z</updated>
<content type="html"><![CDATA[<h1>文件时间</h1><p>任何一个操作系统都有时间的概念,时间的概念主要用于对文件和系统中发生的时间进行记录,在Linux 中,可以使用stat查看Linux系统中文件的时间</p><h2 id="stat">stat</h2><p>用于显示文件时间和 inode 内容,inode相关的知识会在后面的磁盘管理章节详细讲解,这边主要来看 文件的时间</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">stat [选项]... 文件...<br></code></pre></td></tr></table></figure><h3 id="实例">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>stat查看文件时间,这边为了我们方便看得懂,建议改为英文系统环境</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# export LANG="en_US.UTF-8"<br><span class="hljs-meta prompt_"># </span><span class="language-bash">改回中文是LANG=<span class="hljs-string">"zh_CN.UTF-8"</span></span><br>[root@localhost ~]# stat anaconda-ks.cfg<br>File: ‘anaconda-ks.cfg’<br>Size: 1241 Blocks: 8 IO Block: 4096 regular file<br>Device: fd00h/64768d Inode: 33574979 Links: 1<br>Access: (0600/-rw-------) Uid: ( 0/ root) Gid: ( 0/ root)<br>Context: system_u:object_r:admin_home_t:s0<br>Access: 2021-04-04 17:54:09.700844151 +0800<br>Modify: 2021-04-04 16:53:30.524854041 +0800<br>Change: 2021-04-04 16:53:30.524854041 +0800<br>Birth: -<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>Access:访问时间,也叫atime</p><ul class="lvl-2"><li class="lvl-4">当文件被访问的时候,这个时间就会发生改变</li><li class="lvl-4">Linux文件运行的时候查看文件又频繁数量又大,如果每次atime发生变化的时候都记入硬 盘,或造成很大的压力。RHEL6开始relatime,atime延迟修改,必须满足其中一个条件:<ul class="lvl-4"><li class="lvl-6">自上次atime修改后,已达到86400秒</li><li class="lvl-6">发生写操作时</li></ul></li></ul></li><li class="lvl-2"><p>Modify:修改时间,也叫mtime</p><ul class="lvl-2"><li class="lvl-4">当文件内容发生变化的时候,这个时间就会发生改变</li></ul></li><li class="lvl-2"><p>Change:改变时间,也叫ctime</p><ul class="lvl-2"><li class="lvl-4">当文件状态被改变的时候,这个时间就会发生修改</li></ul></li></ul><h1>文件类型</h1><p>Linux系统和Windows系统有很大的区别,Windows系统查看文件的后缀名就可以知道这个是什么类型 的文件,比如: test.jpg 这个是一个图片,如果你在windows上双击打开,就会使用支持查看图片的 软件打开。</p><p>Linux系统就根本不看文件的后缀名,你认为这个是什么文件,你就使用什么工具打开这个文件,如果打 开错误,就会报错,看下面的案例</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# cat file<br>cat: file: Is a directory<br></code></pre></td></tr></table></figure><h2 id="方法一:ls">方法一:ls</h2><p>使用ls可以查看当前目录下有哪些文件,我们会发现文件夹和文件的颜色并不一样,所以我们可以简单 的通过颜色来进行判断,不过这种判断的方式并不准确,因为不同的Linux发行套件颜色的标准并不一 样,不同的远程管理工具对颜色的理解也有偏差,比如可能把蓝色显示为淡蓝色,而淡蓝色又显示成其 他颜色。所以最推荐的做法是通过 ls -l 查看第一个字母:</p><ul class="lvl-0"><li class="lvl-2"><p>-普通文件(文本文档,二进制文件,压缩文件,电影,图片。。。)</p></li><li class="lvl-2"><p>d目录文件(蓝色)</p></li><li class="lvl-2"><p>b块设备文件(块设备)存储设备硬盘,U盘 /dev/sda,/dev/sda1</p></li><li class="lvl-2"><p>c字符设备文件(字符设备)打印机,终端 /dev/tty1,/dev/zero</p></li><li class="lvl-2"><p>s套接字文件</p></li><li class="lvl-2"><p>p管道文件</p></li><li class="lvl-2"><p>p管道文件</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# type ll<br>ll 是 `ls -l --color=auto' 的别名<br>[root@localhost ~]# ll -d /etc/hosts /bin/ls /home /dev/sda /dev/tty1<br>/etc/grub2.cfg /dev/log /run/dmeventd-client<br>-rwxr-xr-x. 1 root root 117680 10月 31 2018 /bin/ls<br>srw-rw-rw-. 1 root root 0 4月 4 16:54 /dev/log<br>brw-rw----. 1 root disk 8, 0 4月 4 16:54 /dev/sda<br>crw--w----. 1 root tty 4, 1 4月 4 16:56 /dev/tty1<br>lrwxrwxrwx. 1 root root 22 4月 4 16:49 /etc/grub2.cfg -><br>../boot/grub2/grub.cfg<br>-rw-r--r--. 1 root root 158 6月 7 2013 /etc/hosts<br>drwxr-xr-x. 2 root root 6 4月 11 2018 /home<br>prw-------. 1 root root 0 4月 4 16:54 /run/dmeventd-client<br></code></pre></td></tr></table></figure><p>对于初学者而言,我们现在只要知道可以通过这样的方式查看文件的类型,并且能够知道 - 和 d 的意思 即可。后面在学习的过程中,会慢慢的将所有文件类型都掌握的。</p><h2 id="方法二:file">方法二:file</h2><p>file是专门用来查看文件的类型的命令,有时候也可以使用</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# file /etc/hosts<br>/etc/hosts: ASCII text<br>[root@localhost ~]# file /bin/ls<br>/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically<br>linked (uses shared libs), for GNU/Linux 2.6.32,<br>BuildID[sha1]=ceaf496f3aec08afced234f4f36330d3d13a657b, stripped<br>[root@localhost ~]# file /dev/sda<br>/dev/sda: block special<br>[root@localhost ~]# file /dev/tty1<br>/dev/tty1: character special<br>[root@localhost ~]# file /etc/grub2.cfg<br>/etc/grub2.cfg: symbolic link to `../boot/grub2/grub.cfg'<br>[root@localhost ~]# file /home<br>/home: directory<br>[root@localhost ~]# file /run/dmeventd-client<br>/run/dmeventd-client: fifo (named pipe)<br></code></pre></td></tr></table></figure><h2 id="方法三:stat">方法三:stat</h2><p>这个命令上面已经介绍过了,在输出结果中也是可以看到文件的类型</p><h1>文件查找</h1><p>在windows中可以在文件管理器中很方便的输入文件名查找文件,然而Linux的文件查找功能更加的方 便,并且功能更加的强大,现在就介绍三个用于查找文件的命令。</p><p>在这三种查找命令中功能最强大的是 find 命令,所以在学习的时候, which 和 locate 需要掌握, find 命令需要熟练掌握!</p><h2 id="which">which</h2><p>用于查找文件</p><p>which指令会在环境变量 $PATH 设置的目录里查找符合条件的文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">which [文件...]<br></code></pre></td></tr></table></figure><h3 id="补充知识:环境变量">补充知识:环境变量</h3><p>环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数, 如:临时文件夹位置和系统文件夹位置等。</p><p>简单的理解就是告诉操作系统在程序运行的时候,有一些默认的设置是什么。</p><p>比如上面我们修改了 LANG 变量,就是一个环境变量,会影响到显示的语言是中文还是英文。</p><p>比如在讲解 pwd 命令的时候,我们修改了 $PWD 变量,就影响了当前所处的文件夹。</p><p>在我们使用shell命令行输入命令的时候,其实每个命令都是有一个可执行文件去完成我们下达的任务, 这个可执行文件在操作系统中是分布在不同的文件夹中的,我们总不能每次执行的时候都要告诉操作系 统这个文件在哪里,那么就算是查看一个文件,我们都需要输入如下的命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# /usr/bin/ls -lh<br><span class="hljs-meta prompt_"># </span><span class="language-bash">在Linux中,<span class="hljs-built_in">ls</span>的可执行程序在/usr/bin目录下</span><br></code></pre></td></tr></table></figure><p>这样就太麻烦了,所以就指定了一个环境变量 $PATH ,这个变量中有很多的目录地址,当我们执行命令 的时候,操作系统就会到这些目录中查找,是否存在你所输入的命令。如果有那么就会去执行。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# echo $PATH<br>/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin<br></code></pre></td></tr></table></figure><p>如果你想让自己安装的某个软件可以在操作系统的任意位置直接输入文件名执行,那么你也可以把自定 义的目录加入到这个 $PATH 中</p><h3 id="实例-2">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>查看ls命令的可执行文件在什么目录</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# which ls<br>alias ls='ls --color=auto'<br>/usr/bin/ls<br><span class="hljs-meta prompt_"># </span><span class="language-bash"><span class="hljs-built_in">which</span>会先告诉你<span class="hljs-built_in">ls</span>其实是一个别名</span><br><span class="hljs-meta prompt_"># </span><span class="language-bash">然后显示出来<span class="hljs-built_in">ls</span>所在的具体位置</span><br></code></pre></td></tr></table></figure><p>**小知识:**我们在执行 ls 的时候,其实执行的是 ls --color=auto 这条命令,在显示文件的时候使用不 同的颜色表示不同的文件类型,如果我们想执行 ls 本体,而不想执行别名,我们可以输入 \ls 就可以 了,这样就不会有不同的颜色表示文件类型了。</p><ul class="lvl-0"><li class="lvl-2"><p>查看poweroff在什么目录</p></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs she">[root@localhost ~]# which poweroff<br>/usr/sbin/poweroff<br></code></pre></td></tr></table></figure><h2 id="locate">locate</h2><p>用于查找符合条件的文件,他会去保存文件和目录名称的数据库内,查找合乎范本样式条件的文件或目 录</p><p>在centos7的最小化安装中,并没有自带locate命令,我们需要输入如下命令进行安装。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# yum -y install mlocate<br><span class="hljs-meta prompt_"># </span><span class="language-bash">注意,在安装的时候需要确保虚拟机有网络</span><br></code></pre></td></tr></table></figure><p>ocate的使用方式如下</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">locate [选项]... [范本样式]...<br></code></pre></td></tr></table></figure><p>在使用locate之前,需要更新一下数据库,因为locate只会在数据库中查找文件所在的位置,所以locate 查找速度极快,缺点就是数据库更新并不是实时的,更新数据库有两种方式:</p><ul class="lvl-0"><li class="lvl-2"><p>手动更新,输入 updatedb</p></li><li class="lvl-2"><p>默认情况下, updatedb 会每天自动执行一次</p></li><li class="lvl-2"><p>配置文件在/etc/updatedb.conf</p></li></ul><h3 id="选项">选项</h3><ul class="lvl-0"><li class="lvl-2"><p>-c:只输出找到的数量</p></li><li class="lvl-2"><p>-c:只输出找到的数量</p></li><li class="lvl-2"><p>-i:忽略大小写</p></li><li class="lvl-2"><p>-r:使用基本正则表达式</p></li><li class="lvl-2"><p>–regex:使用扩展正则表达式</p></li><li class="lvl-2"><p>-d DBPATH:使用 DBPATH 指定的数据库,而不是默认数据库 /var/lib/mlocate/mlocate.db</p></li></ul><h3 id="实例-3">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>查找passwd文件所在的位置</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# updatedb<br><span class="hljs-meta prompt_"># </span><span class="language-bash">更新数据库并不是每次查找都需要,但是建议更新数据库来保证数据是最新的</span><br>[root@localhost ~]# locate passwd<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查找ens33网卡配置文件所在的位置</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">查找ens33网卡配置文件所在的位置<br></code></pre></td></tr></table></figure><p>关于正则表达式,我们会在后续文本三剑客中详细学习</p><h2 id="find">find</h2><p>实时查找工具,通过遍历指定路径下的文件系统完成文件查找</p><p>工作特点:</p><ul class="lvl-0"><li class="lvl-2"><p>查找速度略慢</p></li><li class="lvl-2"><p>精确查找</p></li><li class="lvl-2"><p>实时查找</p></li><li class="lvl-2"><p>可以满足多种条件匹配</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs shell">find [选项] [路径] [查找条件 + 处理动作]<br>查找路径:指定具体目录路径,默认是当前文件夹<br>查找条件:指定的查找标准(文件名/大小/类型/权限等),默认是找出所有文件<br>处理动作:对符合条件的文件做什么操作,默认输出屏幕<br></code></pre></td></tr></table></figure><h3 id="查找条件">查找条件</h3><ul class="lvl-0"><li class="lvl-2"><p>根据文件名查找</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /etc -name "ifcfg-ens33"<br>[root@localhost ~]# find /etc -iname "ifcfg-ens33" # 忽略大小写<br>[root@localhost ~]# find /etc -iname "ifcfg*"<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>按文件大小</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /etc -size +5M # 大于5M<br>[root@localhost ~]# find /etc -size 5M # 等于5M<br>[root@localhost ~]# find /etc -size -5M # 小于5M<br>[root@localhost ~]# find /etc -size +5M -ls # 找到的处理动作-ls<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>指定查找的目录深度</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find / -maxdepth 3 -a -name "ifcfg-ens33" # 最大查找深度<br><span class="hljs-meta prompt_"># </span><span class="language-bash">-a是同时满足,-o是或</span><br>[root@localhost ~]# find / -mindepth 3 -a -name "ifcfg-ens33" # 最小查找深度<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>按时间找</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /etc -mtime +5 # 修改时间超过5天<br>[root@localhost ~]# find /etc -mtime 5 # 修改时间等于5天<br>[root@localhost ~]# find /etc -mtime -5 # 修改时间5天以内<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>按照文件属主、属组找,文件的属主和属组,会在下一篇详细讲解。</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /home -user xwz # 属主是xwz的文件<br>[root@localhost ~]# find /home -group xwz<br>[root@localhost ~]# find /home -user xwz -group xwz<br>[root@localhost ~]# find /home -user xwz -a -group root<br>[root@localhost ~]# find /home -user xwz -o -group root<br>[root@localhost ~]# find /home -nouser # 没有属主的文件<br>[root@localhost ~]# find /home -nogroup # 没有属组的文件<br></code></pre></td></tr></table></figure><p>按文件类型</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /dev -type d<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>按文件权限,文件权限会在下一篇详细讲解</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find / -perm 644 -ls<br>[root@localhost ~]# find / -perm -644 -ls # 权限小于644的<br>[root@localhost ~]# find / -perm 4000 -ls<br>[root@localhost ~]# find / -perm -4000 -ls<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>按正则表达式</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /etc -regex '.*ifcfg-ens[0-9][0-9]'<br><span class="hljs-meta prompt_"># </span><span class="language-bash">.* 任意多个字符</span><br><span class="hljs-meta prompt_"># </span><span class="language-bash">[0-9] 任意一个数字</span><br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>条件组合</p><ul class="lvl-2"><li class="lvl-4"><p>-a:多个条件and并列</p></li><li class="lvl-4"><p>-o:多个条件or并列</p></li><li class="lvl-4"><p>-not:条件取反</p></li></ul></li></ul><h2 id="处理动作">处理动作</h2><ul class="lvl-0"><li class="lvl-2"><p>‐print:默认的处理动作,显示至屏幕</p></li><li class="lvl-2"><p>‐ls:类型于对查找到的文件执行 ls ‐l 命令</p></li><li class="lvl-2"><p>‐delete:删除查找到的文件</p></li><li class="lvl-2"><p>‐fls /path/to/somefile:查找到的所有文件的长格式信息保存至指定文件中</p></li><li class="lvl-2"><p><em>‐ok COMMAND {}</em>:对查找到的每个文件执行由COMMAND指定的命令,需要确认</p></li><li class="lvl-2"><p>*‐exec COMMAND {} *:对查找到的每个文件执行由COMMAND指定的命令,不需要确认</p></li><li class="lvl-2"><p>*‐exec COMMAND {} *:对查找到的每个文件执行由COMMAND指定的命令,不需要确认</p></li></ul><p>下面的实例大家学习完后续用户权限管理之后,就可以完全看的懂了</p><h3 id="实例-4">实例</h3><ul class="lvl-0"><li class="lvl-2"><p>查找/var目录下属主为root,且属组为mail的所有文件或目录</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /var ‐user root ‐group mail<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查找/usr目录下不属于root,bin或Hadoop的所有文件或目录</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /usr ‐not ‐user root ‐a ‐not ‐user bin ‐a ‐not ‐user<br>centos<br>[root@localhost ~]# find /usr ‐not \(‐user root ‐o ‐user bin ‐o ‐user hadoop\)<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查找/etc目录下最近一周内容曾被修改过的文件或目录</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /etc/ ‐mtime ‐7<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查找当前系统上没有属主或属组,且最近一周内曾被访问过的文件或目录</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find / \(‐nouser ‐o ‐nogroup\) ‐a ‐atime ‐7<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查找/etc目录下大于1M且类型为普通文件的所有文件或目录</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /etc ‐size +1M ‐type f<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查找/etc目录下所有用户都没有写权限的文件</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /etc ‐not ‐perm -222<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查找/etc目录下至少一类用户没有执行权限的文件</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]# find /etc ‐not ‐perm ‐111<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>查找/etc/init.d目录下,所有用户都执行权限,且其它用户写权限的文件</p></li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">[root@localhost ~]#find /etc/init.d ‐perm ‐113<br></code></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1>文件时间</h1>
<p>任何一个操作系统都有时间的概念,时间的概念主要用于对文件和系统中发生的时间进行记录,在Linux 中,可以使用stat查看Linux系统中文件的时间</p>
<h2 id="stat">stat</h2>
<p>用于显示文件时间和 inode 内</summary>
<category term="Linux" scheme="https://xiaolaji.site/categories/Linux/"/>
<category term="Linux文件管理" scheme="https://xiaolaji.site/tags/Linux%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86/"/>
</entry>
<entry>
<title>Python与协程</title>
<link href="https://xiaolaji.site/20221001/Python%E4%B8%8E%E5%8D%8F%E7%A8%8B/"/>
<id>https://xiaolaji.site/20221001/Python%E4%B8%8E%E5%8D%8F%E7%A8%8B/</id>
<published>2022-10-01T04:48:25.000Z</published>
<updated>2023-05-27T03:20:10.000Z</updated>
<content type="html"><![CDATA[<h1>协程理论</h1><p>进程是资源分配的最小单位,线程是CPU调度的最小单位</p><p>无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程、创建线程、以及管理 他们之间的切换。</p><p>随着我们对于效率的追求不断提高,基于单线程来实现并发又成为一个新的课题,即只用一个主线程 (很明显可利用的cpu只有一个)情况下实现并发。这样就可以节省创建线进程所消耗的时间。</p><p>cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情 况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长</p><p><img src="image-20220711210310648.png" alt="CPU任务切换图"></p><p>其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的 效果,如果多个任务都是纯计算的,这种切换反而会降低效率。</p><p>为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法</p><ol><li class="lvl-3"><p>yield可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制 的,更轻量级</p></li><li class="lvl-3"><p>send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换</p></li></ol><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">consumer</span>():<br><span class="hljs-string">'''任务1:接收数据,处理数据'''</span><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br><span class="hljs-comment"># print("消费")</span><br>x=<span class="hljs-keyword">yield</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">producer</span>():<br> <span class="hljs-string">'''任务2:生产数据'''</span><br> g=consumer()<br> <span class="hljs-built_in">next</span>(g)<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10000000</span>):<br> <span class="hljs-comment"># print("生产")</span><br> g.send(i)<br> <br>start=time.time()<br><span class="hljs-comment">#基于yield保存状态,实现两个任务直接来回切换,即并发的效果</span><br><span class="hljs-comment">#PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.</span><br>producer()<br><br>stop=time.time()<br><span class="hljs-built_in">print</span>(stop-start) <span class="hljs-comment">#2.0272178649902344</span><br></code></pre></td></tr></table></figure><p>第一种情况的切换。在任务一遇到io情况下,切到任务二去执行,这样就可以利用任务一阻塞的时间完 成任务二的计算,效率的提升就在于此。但是如果一直在执行高强度的计算,这样切换反而会降低效率。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">consumer</span>():<br> <span class="hljs-string">'''任务1:接收数据,处理数据'''</span><br> <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>x=<span class="hljs-keyword">yield</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">producer</span>():<br> <span class="hljs-string">'''任务2:生产数据'''</span><br> g=consumer()<br> <span class="hljs-built_in">next</span>(g)<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10000000</span>):<br> g.send(i)<br> time.sleep(<span class="hljs-number">2</span>)<br><br>start=time.time()<br>producer() <span class="hljs-comment">#并发执行,但是任务producer遇到io就会阻塞住,并不会切到该线程内的其他任务去执行</span><br><br>stop=time.time()<br><span class="hljs-built_in">print</span>(stop-start)<br></code></pre></td></tr></table></figure><ol><li class="lvl-3"><p>可以控制多个任务之间的切换,切换之前将任务的状态保存下来,以便重新运行时,可以基于暂停 的位置继续执行。</p></li><li class="lvl-3"><p>可以控制多个任务之间的切换,切换之前将任务的状态保存下来,以便重新运行时,可以基于暂停 的位置继续执行。</p></li></ol><h1>协程</h1><p>协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。</p><ol><li class="lvl-3"><p>python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫 交出cpu执行权限,切换其他线程运行)</p></li><li class="lvl-3"><p>单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效 率(!!!非io操作的切换与效率无关)</p></li></ol><p>对比操作系统控制线程的切换,用户在单线程内控制协程的切换</p><p>优点:</p><ol><li class="lvl-3"><p>协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级</p></li><li class="lvl-3"><p>单线程内就可以实现并发的效果,最大限度地利用cpu</p></li></ol><p>缺点:</p><ol><li class="lvl-3"><p>协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线 程,每个线程内开启协程</p></li><li class="lvl-3"><p>协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程</p></li></ol><p>协程特点:</p><ol><li class="lvl-3"><p>必须在只有一个单线程里实现并发</p></li><li class="lvl-3"><p>修改共享数据不需加锁</p></li><li class="lvl-3"><p>用户程序里自己保存多个控制流的上下文栈</p></li><li class="lvl-3"><p>附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现, 就用到了gevent模块(select机制)</p></li></ol><h1>Greenlet模块</h1><p>pip install greenlet</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> greenlet <span class="hljs-keyword">import</span> greenlet<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>(<span class="hljs-params">name</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s eat 1'</span> %name)<br> g2.switch(<span class="hljs-string">'aaron'</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s eat 2'</span> %name)<br> g2.switch()<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">play</span>(<span class="hljs-params">name</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s play 1'</span> %name)<br> g1.switch()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s play 2'</span> %name)<br> <br>g1=greenlet(eat)<br>g2=greenlet(play)<br><br>g1.switch(<span class="hljs-string">'aaron'</span>) <span class="hljs-comment"># 可以在第一次switch时传入参数,以后都不需要</span><br></code></pre></td></tr></table></figure><p>单纯的切换(在没有io的情况下或者没有重复开辟内存空间的操作),反而会降低程序的执行速度</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#顺序执行</span><br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>():<br> res=<span class="hljs-number">1</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10000000</span>):<br>res+=i<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f2</span>():<br> res=<span class="hljs-number">1</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10000000</span>):<br>res*=i<br><br>start=time.time()<br>f1()<br>f2()<br>stop=time.time()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'run time is %s'</span> %(stop-start))<br><br><span class="hljs-comment">#切换</span><br><span class="hljs-keyword">from</span> greenlet <span class="hljs-keyword">import</span> greenlet<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>():<br> res=<span class="hljs-number">1</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10000000</span>):<br> res+=i<br> g2.switch()<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f2</span>():<br> res=<span class="hljs-number">1</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10000000</span>):<br> res*=i<br>g1.switch()<br> <br>start=time.time()<br>g1=greenlet(f1)<br>g2=greenlet(f2)<br>g1.switch()<br>stop=time.time()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'run time is %s'</span> %(stop-start))<br></code></pre></td></tr></table></figure><p>greenlet只是提供了一种比generator更加便捷的切换方式,当切到一个任务执行时如果遇到io,那就原 地阻塞,仍然是没有解决遇到IO自动切换来提升效率的问题。</p><p>单线程里的这20个任务的代码通常会既有计算操作又有阻塞操作,我们完全可以在执行任务1时遇到阻 塞,就利用阻塞的时间去执行任务2。。。。如此,才能提高效率,这就用到了Gevent模块。</p><h1>Gevent模块</h1><p>pip install gevent</p><p>Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式 是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进 程的内部,但它们被协作式地调度。</p><p>用法介绍</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python">g1=gevent.spawn(func,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,x=<span class="hljs-number">4</span>,y=<span class="hljs-number">5</span>) <span class="hljs-comment"># 创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的</span><br><br>g2=gevent.spawn(func2)<br><br>g1.join() <span class="hljs-comment">#等待g1结束</span><br><br>g2.join() <span class="hljs-comment">#等待g2结束</span><br><br><span class="hljs-comment">#或者上述两步合作一步:gevent.joinall([g1,g2])</span><br><br>g1.value<span class="hljs-comment">#拿到func1的返回值</span><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> gevent<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>(<span class="hljs-params">name</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s eat 1'</span> %name)<br> gevent.sleep(<span class="hljs-number">2</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s eat 2'</span> %name)<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">play</span>(<span class="hljs-params">name</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s play 1'</span> %name)<br> gevent.sleep(<span class="hljs-number">1</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s play 2'</span> %name)<br> <br>g1=gevent.spawn(eat,<span class="hljs-string">'aaron'</span>)<br>g2=gevent.spawn(play,name=<span class="hljs-string">'aaron'</span>)<br>g1.join()<br>g2.join()<br><span class="hljs-comment">#或者gevent.joinall([g1,g2])</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>)<br></code></pre></td></tr></table></figure><p>上例gevent.sleep(2)模拟的是gevent可以识别的io阻塞,而time.sleep(2)或其他的阻塞,gevent是不能直接识别的需要用下面一行代码,打补丁,就可以识别了</p><p>from gevent import monkey;monkey.patch_all()必须放到被打补丁者的前面,如time,socket模块之前</p><p>或者我们干脆记忆成:要用gevent,需要将from gevent import monkey;monkey.patch_all()放到文件的开头</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> gevent <span class="hljs-keyword">import</span> monkey;monkey.patch_all()<br><br><span class="hljs-keyword">import</span> gevent<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>():<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'eat food 1'</span>)<br> time.sleep(<span class="hljs-number">2</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'eat food 2'</span>)<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">play</span>():<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'play 1'</span>)<br> time.sleep(<span class="hljs-number">1</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'play 2'</span>)<br> <br>g1=gevent.spawn(eat)<br>g2=gevent.spawn(play)<br>gevent.joinall([g1,g2])<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>)<br></code></pre></td></tr></table></figure><p>用threading.current_thread().getName()来查看每个g1和g2,查看的结果为DummyThread-n,即假线程</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> gevent <span class="hljs-keyword">import</span> monkey;monkey.patch_all()<br><span class="hljs-keyword">import</span> threading<br><span class="hljs-keyword">import</span> gevent<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>():<br> <span class="hljs-built_in">print</span>(threading.current_thread().getName())<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'eat food 1'</span>)<br> time.sleep(<span class="hljs-number">2</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'eat food 2'</span>)<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">play</span>():<br> <span class="hljs-built_in">print</span>(threading.current_thread().getName())<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'play 1'</span>)<br> time.sleep(<span class="hljs-number">1</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'play 2'</span>)<br> <br>g1=gevent.spawn(eat)<br>g2=gevent.spawn(play)<br>gevent.joinall([g1,g2])<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>)<br></code></pre></td></tr></table></figure><h1>Gevent之同步与异步</h1><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> gevent <span class="hljs-keyword">import</span> spawn,joinall,monkey;monkey.patch_all()<br><br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">task</span>(<span class="hljs-params">pid</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> Some non-deterministic task</span><br><span class="hljs-string"> """</span><br> time.sleep(<span class="hljs-number">0.5</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'Task %s done'</span> % pid)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">synchronous</span>(): <span class="hljs-comment"># 同步</span><br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>):<br>task(i)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">asynchronous</span>(): <span class="hljs-comment"># 异步</span><br>g_l=[spawn(task,i) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>)]<br>joinall(g_l)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'DONE'</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'Synchronous:'</span>)<br> synchronous()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'Asynchronous:'</span>)<br> asynchronous()<br><span class="hljs-comment"># 上面程序的重要部分是将task函数封装到Greenlet内部线程的gevent.spawn。</span><br><span class="hljs-comment"># 初始化的greenlet列表存放在数组threads中,此数组被传给gevent.joinall 函数,</span><br><span class="hljs-comment"># 后者阻塞当前流程,并执行所有给定的greenlet任务。执行流程只会在 所有greenlet执行完后才会继续向下走。</span><br></code></pre></td></tr></table></figure><h1>Gevent之应用举例一</h1><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> gevent <span class="hljs-keyword">import</span> monkey;monkey.patch_all()<br><span class="hljs-keyword">import</span> gevent<br><span class="hljs-keyword">import</span> requests<br><span class="hljs-keyword">import</span> time<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">get_page</span>(<span class="hljs-params">url</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'GET: %s'</span> %url)<br> response=requests.get(url)<br> <span class="hljs-keyword">if</span> response.status_code == <span class="hljs-number">200</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%d bytes received from %s'</span> %(<span class="hljs-built_in">len</span>(response.text),url))<br> <br>start_time=time.time()<br>gevent.joinall([<br> gevent.spawn(get_page,<span class="hljs-string">'https://www.python.org/'</span>),<br> gevent.spawn(get_page,<span class="hljs-string">'https://www.yahoo.com/'</span>),<br> gevent.spawn(get_page,<span class="hljs-string">'https://github.com/'</span>),<br>])<br>stop_time=time.time()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'run time is %s'</span> %(stop_time-start_time))<br></code></pre></td></tr></table></figure><h1>Gevent之应用举例二,协程并发聊天室</h1><p>通过gevent实现单线程下的socket并发</p><p>注意 :from gevent import monkey;monkey.patch_all()一定要放到导入socket模块之前,否则gevent 无法识别socket的阻塞</p><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> gevent <span class="hljs-keyword">import</span> monkey;<br>monkey.patch_all()<br><span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> *<br><span class="hljs-keyword">import</span> gevent<br><br><span class="hljs-comment">#如果不想用money.patch_all()打补丁,可以用gevent自带的socket</span><br><span class="hljs-comment"># from gevent import socket</span><br><span class="hljs-comment"># s=socket.socket()</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">server</span>(<span class="hljs-params">server_ip,port</span>):<br> s=socket(AF_INET,SOCK_STREAM)<br> s.setsockopt(SOL_SOCKET,SO_REUSEADDR,<span class="hljs-number">1</span>)<br> s.bind((server_ip,port))<br> s.listen(<span class="hljs-number">5</span>)<br> <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> conn,addr=s.accept()<br> gevent.spawn(talk,conn,addr)<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">talk</span>(<span class="hljs-params">conn,addr</span>):<br><span class="hljs-keyword">try</span>:<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> res=conn.recv(<span class="hljs-number">1024</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'client %s:%s msg: %s'</span> %(addr[<span class="hljs-number">0</span>],addr[<span class="hljs-number">1</span>],res))<br> conn.send(res.upper())<br><span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:<br><span class="hljs-built_in">print</span>(e)<br><span class="hljs-keyword">finally</span>:<br>conn.close()<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>server(<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8088</span>)<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> *<br><br>client=socket(AF_INET,SOCK_STREAM)<br>client.connect((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> msg=<span class="hljs-built_in">input</span>(<span class="hljs-string">'>>: '</span>).strip()<br> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> msg:<span class="hljs-keyword">continue</span><br> <br> client.send(msg.encode(<span class="hljs-string">'utf-8'</span>))<br> msg=client.recv(<span class="hljs-number">1024</span>)<br> <span class="hljs-built_in">print</span>(msg.decode(<span class="hljs-string">'utf-8'</span>))<br></code></pre></td></tr></table></figure><p>多线程并发客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> *<br><span class="hljs-keyword">import</span> threading<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">client</span>(<span class="hljs-params">server_ip,port</span>):<br>c=socket(AF_INET,SOCK_STREAM) <span class="hljs-comment">#套接字对象一定要加到函数内,即局部名称空间内,放在函数外则被所有线程共享,则大家公用一个套接字对象,那么客户端端口永远一样了</span><br>c.connect((server_ip,port))<br><br> count=<span class="hljs-number">0</span><br> <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>c.send((<span class="hljs-string">'%s say hello %s'</span> %<br>(threading.current_thread().getName(),count)).encode(<span class="hljs-string">'utf-8'</span>))<br> msg=c.recv(<span class="hljs-number">1024</span>)<br> <span class="hljs-built_in">print</span>(msg.decode(<span class="hljs-string">'utf-8'</span>))<br> count+=<span class="hljs-number">1</span><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">500</span>):<br> t=Thread(target=client,args=(<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8088</span>))<br> t.start()<br></code></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1>协程理论</h1>
<p>进程是资源分配的最小单位,线程是CPU调度的最小单位</p>
<p>无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程、创建线程、以及管理 他们之间的切换。</p>
<p>随着我们对于效率的追求不断提高,基于单线程来实现并发又</summary>
<category term="Python" scheme="https://xiaolaji.site/categories/Python/"/>
<category term="Python学习" scheme="https://xiaolaji.site/tags/Python%E5%AD%A6%E4%B9%A0/"/>
</entry>
<entry>
<title>Python与线程</title>
<link href="https://xiaolaji.site/20221001/Python%E4%B8%8E%E7%BA%BF%E7%A8%8B/"/>
<id>https://xiaolaji.site/20221001/Python%E4%B8%8E%E7%BA%BF%E7%A8%8B/</id>
<published>2022-10-01T04:46:51.000Z</published>
<updated>2023-05-27T03:20:02.000Z</updated>
<content type="html"><![CDATA[<h1>操作系统线程理论</h1><h2 id="进程">进程</h2><p>进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。</p><p>进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。</p><h2 id="线程">线程</h2><p>60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端</p><ol><li class="lvl-3"><p>是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;</p></li><li class="lvl-3"><p>是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。</p></li></ol><p>因此在80年代,出现了能独立运行的基本单位——线程(Threads)。</p><p>注意:进程是资源分配的最小单位,线程是CPU调度的最小单位.每一个进程中至少有一个线程。</p><h2 id="进程和线程的关系">进程和线程的关系</h2><p><img src="image-20220711181423215.png" alt="进程与线程示意图"></p><p>线程与进程的区别可以归纳为以下4点:</p><ol><li class="lvl-3"><p>地址空间和其它资源共享(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内 的线程在其它进程不可见。</p></li><li class="lvl-3"><p>通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程 同步和互斥手段的辅助,以保证数据的一致性。</p></li><li class="lvl-3"><p>调度和切换:线程上下文切换比进程上下文切换要快得多。</p><ul class="lvl-2"><li class="lvl-5"><p>**上下文切换:**操作系统通过处理器调度让处理器轮流执行多个进程。实现不同进程中指令交替 执行的机制称为进程的上下文切换。</p></li><li class="lvl-5"><p>**进程的上下文:**进程的物理实体(代码和数据等)和支持运行的环境合称为进程的上下文。进 程的上下文包括用户级上下文和系统级上下文</p></li></ul></li></ol><h2 id="使用线程的实际场景">使用线程的实际场景</h2><p>开启一个字处理软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动 将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地 开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能 输入和处理文字。</p><h2 id="内存中的线程">内存中的线程</h2><p><img src="image-20220711181634439.png" alt="内存中的线程"></p><p>线程通常是有益的,但是带来了不小程序设计难度,线程的问题是:</p><ol><li class="lvl-3"><p>父进程有多个线程,那么开启的子线程是否需要同样多的线程</p></li><li class="lvl-3"><p>在同一个进程中,如果一个线程关闭了文件,而另外一个线程正准备往该文件内写内容呢?</p></li></ol><p>因此,在多线程的代码中,需要更多的心思来设计程序的逻辑、保护程序的数据。</p><h1>python使用线程</h1><h2 id="全局解释器锁GIL">全局解释器锁GIL</h2><p>Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环 中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程 在解释器中运行。</p><p>对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运 行。</p><p>在多线程环境中,Python 虚拟机按以下方式执行:</p><p><img src="image-20220711181746655.png" alt="Python 虚拟机运行方式"></p><p>设置 GIL;</p><p>切换到一个线程去运行;</p><p>运行指定数量的字节码指令或者线程主动让出控制(可以调用 time.sleep(0));</p><p>把线程设置为睡眠状态;</p><p>解锁 GIL;</p><p>再次重复以上所有步骤。</p><p>在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期 间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。</p><p><a href="https://blog.csdn.net/weixin_42239402/article/details/95375147">https://blog.csdn.net/weixin_42239402/article/details/95375147</a></p><h2 id="python线程模块的选择">python线程模块的选择</h2><p>Python提供了几个用于多线程编程的模块,包括thread、threading和Queue等。thread和threading 模块允许程序员创建和管理线程。thread模块提供了基本的线程和锁的支持,threading提供了更高级别、功能更强的线程管理的功能。Queue模块允许用户创建一个可以用于多个线程之间共享数据的队列 数据结构。</p><p>避免使用thread模块,因为更高级别的threading模块更为先进,对线程的支持更为完善,而且使用 thread模块里的属性有可能会与threading出现冲突;其次低级别的thread模块的同步原语很少(实际上 只有一个),而threading模块则有很多;再者,thread模块中当主线程结束时,所有的线程都会被强制 结束掉,没有警告也不会有正常的清除工作,至少threading模块能确保重要的子线程退出后进程才退 出。</p><p>thread模块不支持守护线程,当主线程退出时,所有的子线程不论它们是否还在工作,都会被强行退 出。而threading模块支持守护线程,守护线程一般是一个等待客户请求的服务器,如果没有客户提出请 求它就在那等着,如果设定一个线程为守护线程,就表示这个线程是不重要的,在进程退出的时候,不 用等待这个线程退出。</p><h1>threading模块</h1><h2 id="线程的创建">线程的创建</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">sayhi</span>(<span class="hljs-params">name</span>):<br> time.sleep(<span class="hljs-number">2</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s say hello'</span> %name)<br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> t=Thread(target=sayhi,args=(<span class="hljs-string">'aaron'</span>,))<br> t.start()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主线程'</span>)<br></code></pre></td></tr></table></figure><p>另一种以类继承创建进程的方式</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Sayhi</span>(<span class="hljs-title class_ inherited__">Thread</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name</span>):<br><span class="hljs-built_in">super</span>().__init__()<br>self.name=name<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">run</span>(<span class="hljs-params">self</span>):<br>time.sleep(<span class="hljs-number">2</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s say hello'</span> % self.name)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>t = Sayhi(<span class="hljs-string">'aaron'</span>)<br>t.start()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主线程'</span>)<br></code></pre></td></tr></table></figure><h2 id="多线程与多进程">多线程与多进程</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><span class="hljs-keyword">import</span> os<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>():<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'hello'</span>,os.getpid())<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> <span class="hljs-comment">#part1:在主进程下开启多个线程,每个线程都跟主进程的pid一样</span><br> t1=Thread(target=work)<br> t2=Thread(target=work)<br> t1.start()<br> t2.start()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主线程/主进程pid'</span>,os.getpid())<br><br> <span class="hljs-comment">#part2:开多个进程,每个进程都有不同的pid</span><br> p1=Process(target=work)<br> p2=Process(target=work)<br> p1.start()<br> p2.start()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主线程/主进程pid'</span>,os.getpid())<br></code></pre></td></tr></table></figure><p>效率对比</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">say_hi</span>(<span class="hljs-params">n</span>):<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>):<br><span class="hljs-built_in">print</span>(n+<span class="hljs-number">1</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>t_list=[]<br>t1=time.time()<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">100</span>):<br>t=Thread(target=say_hi,args=(i,))<br>t.start()<br>t_list.append(t)<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> t_list:<br>i.join()<br>t2=time.time()<br><span class="hljs-built_in">print</span>(t2-t1)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"主线程"</span>)<br></code></pre></td></tr></table></figure><p>内存数据共享</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>():<br> <span class="hljs-keyword">global</span> n<br> n=<span class="hljs-number">0</span><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> <span class="hljs-comment"># n=100</span><br> <span class="hljs-comment"># p=Process(target=work)</span><br> <span class="hljs-comment"># p.start()</span><br> <span class="hljs-comment"># p.join()</span><br> <span class="hljs-comment"># print('主',n) #毫无疑问子进程p已经将自己的全局的n改成了0,但改的仅仅是它自己的,查看父进程的n仍然为100</span><br><br> n=<span class="hljs-number">1</span><br> t=Thread(target=work)<br> t.start()<br> t.join()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>,n) <span class="hljs-comment">#查看结果为0,因为同一进程内的线程之间共享进程内的数据</span><br></code></pre></td></tr></table></figure><h1>多线程实现socket</h1><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> multiprocessing<br><span class="hljs-keyword">import</span> threading<br><br><span class="hljs-keyword">import</span> socket<br>s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)<br>s.bind((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br>s.listen(<span class="hljs-number">5</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">action</span>(<span class="hljs-params">conn</span>):<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> data=conn.recv(<span class="hljs-number">1024</span>)<br> <span class="hljs-built_in">print</span>(data)<br> conn.send(data.upper())<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> conn,addr=s.accept()<br><br> p=threading.Thread(target=action,args=(conn,))<br> p.start()<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br>s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)<br>s.connect((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> msg=<span class="hljs-built_in">input</span>(<span class="hljs-string">'>>: '</span>).strip()<br> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> msg:<span class="hljs-keyword">continue</span><br> <br> s.send(msg.encode(<span class="hljs-string">'utf-8'</span>))<br> data=s.recv(<span class="hljs-number">1024</span>)<br> <span class="hljs-built_in">print</span>(data)<br></code></pre></td></tr></table></figure><h2 id="Thread类的其他方法">Thread类的其他方法</h2><ul class="lvl-0"><li class="lvl-2"><p>Thread实例对象的方法</p><ul class="lvl-2"><li class="lvl-4">isAlive(): 返回线程是否活动的。</li><li class="lvl-4">getName(): 返回线程名。</li><li class="lvl-4">setName(): 设置线程名。</li></ul></li><li class="lvl-2"><p>threading模块提供的一些方法:</p><ul class="lvl-2"><li class="lvl-4">threading.currentThread(): 返回当前的线程变量。</li><li class="lvl-4">threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。</li><li class="lvl-4">threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。</li></ul></li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">import</span> threading<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><span class="hljs-keyword">import</span> os<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>():<br><span class="hljs-keyword">import</span> time<br>time.sleep(<span class="hljs-number">3</span>)<br><span class="hljs-built_in">print</span>(threading.current_thread().getName())<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br><span class="hljs-comment">#在主进程下开启线程</span><br>t=Thread(target=work)<br>t.start()<br><br> <span class="hljs-built_in">print</span>(threading.current_thread().getName())<br> <span class="hljs-built_in">print</span>(threading.current_thread()) <span class="hljs-comment">#主线程</span><br> <span class="hljs-built_in">print</span>(threading.<span class="hljs-built_in">enumerate</span>()) <span class="hljs-comment">#连同主线程在内有两个运行的线程</span><br> <span class="hljs-built_in">print</span>(threading.active_count())<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主线程/主进程'</span>)<br></code></pre></td></tr></table></figure><p>使用join</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">sayhi</span>(<span class="hljs-params">name</span>):<br> time.sleep(<span class="hljs-number">2</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s say hello'</span> %name)<br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> t=Thread(target=sayhi,args=(<span class="hljs-string">'aaron'</span>,))<br> t.start()<br> t.join()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主线程'</span>)<br> <span class="hljs-built_in">print</span>(t.is_alive())<br></code></pre></td></tr></table></figure><h1>守护线程</h1><p>无论是进程还是线程,都遵循:守护xx会等待主xx运行完毕后被销毁。需要强调的是:运行完毕并非终止运行</p><ol><li class="lvl-3"><p>对主进程来说,运行完毕指的是主进程代码运行完毕</p><p>主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守 护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,</p></li><li class="lvl-3"><p>对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运 行完毕</p><p>主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结 束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。</p></li></ol><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">sayhi</span>(<span class="hljs-params">name</span>):<br> time.sleep(<span class="hljs-number">2</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s say hello'</span> %name)<br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> t=Thread(target=sayhi,args=(<span class="hljs-string">'aaron'</span>,))<br> t.setDaemon(<span class="hljs-literal">True</span>) <span class="hljs-comment">#必须在t.start()之前设置</span><br> t.start()<br> <br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主线程'</span>)<br> <span class="hljs-built_in">print</span>(t.is_alive())<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">foo</span>():<br> <span class="hljs-built_in">print</span>(<span class="hljs-number">123</span>)<br> time.sleep(<span class="hljs-number">1</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"end123"</span>)<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">bar</span>():<br> <span class="hljs-built_in">print</span>(<span class="hljs-number">456</span>)<br> time.sleep(<span class="hljs-number">3</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"end456"</span>)<br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> t1=Thread(target=foo)<br> t2=Thread(target=bar)<br> <br> t1.daemon=<span class="hljs-literal">True</span><br> t1.start()<br> t2.start()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"main"</span>)<br><span class="hljs-comment">#结果:</span><br><span class="hljs-comment">#123</span><br><span class="hljs-comment">#456</span><br><span class="hljs-comment">#main</span><br><span class="hljs-comment">#end123</span><br><span class="hljs-comment">#end456</span><br><span class="hljs-comment">#出现结果的原因时因为要等主进程内全部线程运行完成,守护线程才会跟着主进程一起结束而结束</span><br></code></pre></td></tr></table></figure><h1>锁</h1><h2 id="同步锁">同步锁</h2><p>没有锁的情况下</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread<br><span class="hljs-keyword">import</span> os,time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>():<br> <span class="hljs-keyword">global</span> n<br> temp=n<br> time.sleep(<span class="hljs-number">0.1</span>)<br> n=temp-<span class="hljs-number">1</span><br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> n=<span class="hljs-number">100</span><br> l=[]<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">100</span>):<br> p=Thread(target=work)<br> l.append(p)<br> p.start()<br> <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> l:<br>p.join()<br><br><span class="hljs-built_in">print</span>(n)<br><span class="hljs-comment">#线程太快了,大家都操作了一下就返回了,结果为99</span><br></code></pre></td></tr></table></figure><p>同步锁</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> threading<br>R=threading.Lock()<br>R.acquire()<br><span class="hljs-string">'''</span><br><span class="hljs-string">对公共数据的操作</span><br><span class="hljs-string">'''</span><br>R.release()<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread,Lock<br><span class="hljs-keyword">import</span> os,time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>():<br> <span class="hljs-keyword">global</span> n<br> lock.acquire()<br> temp=n<br> time.sleep(<span class="hljs-number">0.1</span>)<br> n=temp-<span class="hljs-number">1</span><br> lock.release()<br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> lock=Lock()<br> n=<span class="hljs-number">100</span><br> l=[]<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">100</span>):<br> p=Thread(target=work)<br> l.append(p)<br> p.start()<br><span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> l:<br>p.join()<br><br><span class="hljs-built_in">print</span>(n) <span class="hljs-comment">#结果肯定为0,由原来的并发执行变成串行,牺牲了执行效率保证了数据安全</span><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#不加锁:并发执行,速度快,数据不安全</span><br><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> current_thread,Thread,Lock<br><span class="hljs-keyword">import</span> os,time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">task</span>():<br> <span class="hljs-keyword">global</span> n<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s is running'</span> %current_thread().getName())<br> temp=n<br> time.sleep(<span class="hljs-number">0.5</span>)<br> n=temp-<span class="hljs-number">1</span><br> <br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> n=<span class="hljs-number">100</span><br> lock=Lock()<br> threads=[]<br> start_time=time.time()<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">100</span>):<br> t=Thread(target=task)<br> threads.append(t)<br> t.start()<br><span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> threads:<br>t.join()<br><br> stop_time=time.time()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主:%s n:%s'</span> %(stop_time-start_time,n))<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#不加锁:未加锁部分并发执行,加锁部分串行执行,速度慢,数据安全</span><br><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> current_thread,Thread,Lock<br><span class="hljs-keyword">import</span> os,time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">task</span>():<br> <span class="hljs-comment">#未加锁的代码并发运行</span><br> time.sleep(<span class="hljs-number">3</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s start to run'</span> %current_thread().getName())<br> <span class="hljs-keyword">global</span> n<br> <span class="hljs-comment">#加锁的代码串行运行</span><br> lock.acquire()<br> temp=n<br> time.sleep(<span class="hljs-number">0.5</span>)<br> n=temp-<span class="hljs-number">1</span><br> lock.release()<br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> n=<span class="hljs-number">100</span><br> lock=Lock()<br> threads=[]<br> start_time=time.time()<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">100</span>):<br> t=Thread(target=task)<br> threads.append(t)<br> t.start()<br><span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> threads:<br> t.join()<br> stop_time=time.time()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主:%s n:%s'</span> %(stop_time-start_time,n))<br></code></pre></td></tr></table></figure><p>有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊</p><p>没错:在start之后立刻使用join,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是 安全的,但问题是</p><p>start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串 行的</p><p>单从保证数据安全方面,二者都可以实现,但很明显是加锁的效率更高.</p><p>立刻join版</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> current_thread,Thread,Lock<br><span class="hljs-keyword">import</span> os,time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">task</span>():<br> time.sleep(<span class="hljs-number">3</span>)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s start to run'</span> %current_thread().getName())<br> <span class="hljs-keyword">global</span> n<br> temp=n<br> time.sleep(<span class="hljs-number">0.5</span>)<br> n=temp-<span class="hljs-number">1</span><br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> n=<span class="hljs-number">100</span><br> lock=Lock()<br> start_time=time.time()<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">100</span>):<br>t=Thread(target=task)<br>t.start()<br>t.join()<br>stop_time=time.time()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主:%s n:%s'</span> %(stop_time-start_time,n))<br></code></pre></td></tr></table></figure><h2 id="死锁与递归锁">死锁与递归锁</h2><p>两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为<strong>死锁进程</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Lock <span class="hljs-keyword">as</span> Lock<br><span class="hljs-keyword">import</span> time<br>mutexA=Lock()<br>mutexA.acquire()<br>mutexA.acquire() <span class="hljs-comment"># 上面已经拿过一次key了,这边就拿不到了</span><br><span class="hljs-built_in">print</span>(<span class="hljs-number">123</span>)<br>mutexA.release()<br>mutexA.release()<br><span class="hljs-comment">#程序就一直卡住了</span><br></code></pre></td></tr></table></figure><p>解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁 RLock。</p><p>这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> RLock <span class="hljs-keyword">as</span> Lock<br><span class="hljs-keyword">import</span> time<br>mutexA=Lock()<br>mutexA.acquire()<br>mutexA.acquire()<br><span class="hljs-built_in">print</span>(<span class="hljs-number">123</span>)<br>mutexA.release()<br>mutexA.release()<br></code></pre></td></tr></table></figure><p>吃面的问题</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread,Lock<br>noodle_lock = Lock()<br>fork_lock = Lock()<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat1</span>(<span class="hljs-params">name</span>):<br> noodle_lock.acquire()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 抢到了面条'</span>%name)<br> fork_lock.acquire()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 抢到了叉子'</span>%name)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃面'</span>%name)<br> fork_lock.release()<br> noodle_lock.release()<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat2</span>(<span class="hljs-params">name</span>):<br> fork_lock.acquire()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 抢到了叉子'</span> % name)<br> time.sleep(<span class="hljs-number">1</span>)<br> noodle_lock.acquire()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 抢到了面条'</span> % name)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃面'</span> % name)<br> noodle_lock.release()<br> fork_lock.release()<br> <br><span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> [<span class="hljs-string">'顾客1'</span>,<span class="hljs-string">'顾客2'</span>,<span class="hljs-string">'顾客3'</span>]:<br> t1 = Thread(target=eat1,args=(name,))<br> t2 = Thread(target=eat2,args=(name,))<br> t1.start()<br> t2.start()<br><span class="hljs-comment">#有人只有叉子,有人只有面,就会死锁</span><br></code></pre></td></tr></table></figure><p>使用递归锁解决问题</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">from</span> threading <span class="hljs-keyword">import</span> Thread,RLock<br><br>noodle_lock = fork_lock = RLock()<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat1</span>(<span class="hljs-params">name</span>):<br> noodle_lock.acquire()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 抢到了面条'</span>%name)<br> fork_lock.acquire()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 抢到了叉子'</span>%name)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃面'</span>%name)<br> fork_lock.release()<br> noodle_lock.release()<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat2</span>(<span class="hljs-params">name</span>):<br> fork_lock.acquire()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 抢到了叉子'</span> % name)<br> time.sleep(<span class="hljs-number">1</span>)<br> noodle_lock.acquire()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 抢到了面条'</span> % name)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃面'</span> % name)<br> noodle_lock.release()<br> fork_lock.release()<br><span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> [<span class="hljs-string">'顾客1'</span>,<span class="hljs-string">'顾客2'</span>,<span class="hljs-string">'顾客3'</span>]:<br> t1 = Thread(target=eat1,args=(name,))<br> t2 = Thread(target=eat2,args=(name,))<br> t1.start()<br> t2.start()<br></code></pre></td></tr></table></figure><h2 id="线程队列">线程队列</h2><p>queue队列 :使用import queue,用法与进程Queue一样</p><p>先进先出</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> queue<br><br>q=queue.Queue()<br>q.put(<span class="hljs-string">'first'</span>)<br>q.put(<span class="hljs-string">'second'</span>)<br>q.put(<span class="hljs-string">'third'</span>)<br><br><span class="hljs-built_in">print</span>(q.get())<br><span class="hljs-built_in">print</span>(q.get())<br><span class="hljs-built_in">print</span>(q.get())<br></code></pre></td></tr></table></figure><p>先进后出</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> queue<br><br>q=queue.LifoQueue()<br>q.put(<span class="hljs-string">'first'</span>)<br>q.put(<span class="hljs-string">'second'</span>)<br>q.put(<span class="hljs-string">'third'</span>)<br><br><span class="hljs-built_in">print</span>(q.get())<br><span class="hljs-built_in">print</span>(q.get())<br><span class="hljs-built_in">print</span>(q.get())<br></code></pre></td></tr></table></figure><p>优先级队列</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> queue<br><br>q=queue.PriorityQueue()<br><span class="hljs-comment">#put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优</span><br>先级越高<br>q.put((<span class="hljs-number">20</span>,<span class="hljs-string">'a'</span>))<br>q.put((<span class="hljs-number">10</span>,<span class="hljs-string">'b'</span>))<br>q.put((<span class="hljs-number">30</span>,<span class="hljs-string">'c'</span>))<br><br><span class="hljs-built_in">print</span>(q.get())<br><span class="hljs-built_in">print</span>(q.get())<br><span class="hljs-built_in">print</span>(q.get())<br></code></pre></td></tr></table></figure><h1>多进程多线程总结</h1><table><thead><tr><th>比较内容</th><th>多线程</th><th>多进程</th></tr></thead><tbody><tr><td>引入模块</td><td>from threading import Thread</td><td>from multiprocessing import Process</td></tr><tr><td>创建使用</td><td>t =Thread(target=func1, args=(i,))</td><td>p = Process(target=func, args= (i,))</td></tr><tr><td>队列</td><td>import queue</td><td>from multiprocessing import Queue</td></tr><tr><td>锁</td><td>from threading import Lock</td><td>from multiprocessing import Lock</td></tr><tr><td>池</td><td>from concurrent.futures import ThreadPoolExecutor</td><td>from multiprocessing import Pool</td></tr></tbody></table>]]></content>
<summary type="html"><h1>操作系统线程理论</h1>
<h2 id="进程">进程</h2>
<p>进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。</p>
<p>进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执</summary>
<category term="Python" scheme="https://xiaolaji.site/categories/Python/"/>
<category term="Python学习" scheme="https://xiaolaji.site/tags/Python%E5%AD%A6%E4%B9%A0/"/>
</entry>
<entry>
<title>Python与进程</title>
<link href="https://xiaolaji.site/20221001/Python%E4%B8%8E%E8%BF%9B%E7%A8%8B/"/>
<id>https://xiaolaji.site/20221001/Python%E4%B8%8E%E8%BF%9B%E7%A8%8B/</id>
<published>2022-10-01T04:45:45.000Z</published>
<updated>2023-05-27T03:19:58.000Z</updated>
<content type="html"><![CDATA[<h1>什么是进程?</h1><p>进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基 本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体; 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进 程是程序的实体。</p><p>狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。</p><p>广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态 执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。</p><ol><li class="lvl-3"><p>进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码; 数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和 本地变量。</p></li><li class="lvl-3"><p>进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统 执行之),它才能成为一个活动的实体,我们称其为进程。 进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情 况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的 基础上。</p></li></ol><p>进程的特性</p><p>动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。</p><p>并发性:任何进程都可以同其他进程一起并发执行</p><p>独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;</p><p>异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进</p><p>结构特征:进程由程序、数据和进程控制块三部分组成。</p><p>多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结 果;但是执行过程中,程序不能发生改变</p><p>程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。</p><p>而进程是程序在处理机上的一次执行过程,它是一个动态的概念。</p><p>程序可以作为一种软件资料长期存在,而进程是有一定生命期的。</p><p>程序可以作为一种软件资料长期存在,而进程是有一定生命期的。</p><h1>进程调度</h1><p>扩展阅读</p><p>要想多个进程交替运行,操作系统必须对这些进程进行调度,这个调度也不是随即进行的,而是需要遵 循一定的法则,由此就有了进程的调度算法。</p><p>先来先服务(FCFS)调度算法</p><blockquote><p>短作业(进程)优先调度算法(SJ/PF)是指对短作业或短进程优先调度的算法,该算法既可用于作业调 度,也可用于进程调度。但其对长作业不利;不能保证紧迫性作业(进程)被及时处理;作业的长短只是 被估算出来的。</p></blockquote><p>时间片轮转(Round Robin,RR)法</p><blockquote><p>时间片轮转(Round Robin,RR)法的基本思路是让每个进程在就绪队列中的等待时间与享受服务的时间 成比例。在时间片轮转法中,需要将CPU的处理时间分成固定大小的时间片,例如,几十毫秒至几百毫 秒。如果一个进程在被调度选中之后用完了系统规定的时间片,但又未完成要求的任务,则它自行释放自 己所占有的CPU而排到就绪队列的末尾,等待下一次调度。同时,进程调度程序又去调度当前就绪队列中 的第一个进程。</p><p>显然,轮转法只能用来调度分配一些可以抢占的资源。这些可以抢占的资源可以随时被剥夺,而且可以将 它们再分配给别的进程。CPU是可抢占资源的一种。但打印机等资源是不可抢占的。由于作业调度是对除 了CPU之外的所有系统硬件资源的分配,其中包含有不可抢占资源,所以作业调度不使用轮转法。 在轮转法中,时间片长度的选取非常重要。首先,时间片长度的选择会直接影响到系统的开销和响应时 间。如果时间片长度过短,则调度程序抢占处理机的次数增多。这将使进程上下文切换次数也大大增加, 从而加重系统开销。反过来,如果时间片长度选择过长,例如,一个时间片能保证就绪队列中所需执行时 间最长的进程能执行完毕,则轮转法变成了先来先服务法。时间片长度的选择是根据系统对响应时间的要 求和就绪队列中所允许最大的进程数来确定的。 在轮转法中,加入到就绪队列的进程有3种情况:</p><p>一种是分给它的时间片用完,但进程还未完成,回到就绪队列的末尾等待下次调度去继续执行。</p><p>另一种情况是分给该进程的时间片并未用完,只是因为请求I/O或由于进程的互斥与同步关系而被阻 塞。当阻塞解除之后再回到就绪队列。</p><p>第三种情况就是新创建进程进入就绪队列。 如果对这些进程区别对待,给予不同的优先级和时间片从直观上看,可以进一步改善系统服务质量和效 率。例如,我们可把就绪队列按照进程到达就绪队列的类型和进程被阻塞时的阻塞原因分成不同的就绪队 列,每个队列按FCFS原则排列,各队列之间的进程享有不同的优先级,但同一队列内优先级相同。这样, 当一个进程在执行完它的时间片之后,或从睡眠中被唤醒以及被创建之后,将进入不同的就绪队列。</p></blockquote><p>多级反馈队列</p><blockquote><p>前面介绍的各种用作进程调度的算法都有一定的局限性。如短进程优先的调度算法,仅照顾了短进程而忽 略了长进程,而且如果并未指明进程的长度,则短进程优先和基于进程长度的抢占式调度算法都将无法使 用。</p><p>而多级反馈队列调度算法则不必事先知道各种进程所需的执行时间,而且还可以满足各种类型进程的需 要,因而它是目前被公认的一种较好的进程调度算法。在采用多级反馈队列调度算法的系统中,调度算法 的实施过程如下所述。</p><p>(1) 应设置多个就绪队列,并为各个队列赋予不同的优先级。第一个队列的优先级最高,第二个队列次 之,其余各队列的优先权逐个降低。该算法赋予各个队列中进程执行时间片的大小也各不相同,在优先权 愈高的队列中,为每个进程所规定的执行时间片就愈小。例如,第二个队列的时间片要比第一个队列的时 间片长一倍,……,第i+1个队列的时间片要比第i个队列的时间片长一倍。</p><p>(2) 当一个新进程进入内存后,首先将它放入第一队列的末尾,按FCFS原则排队等待调度。当轮到该进 程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程 序便将该进程转入第二队列的末尾,再同样地按FCFS原则等待调度执行;如果它在第二队列中运行一个时 间片后仍未完成,再依次将它放入第三队列,……,如此下去,当一个长作业(进程)从第一队列依次降到第 n队列后,在第n 队列便采取按时间片轮转的方式运行。</p><p>(3) 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;仅当第1~(i-1)队列均空时,才会 调度第i队列中的进程运行。如果处理机正在第i队列中为某进程服务时,又有新进程进入优先权较高的队 列(第1~(i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在 运行的进程放回到第i队列的末尾,把处理机分配给新到的高优先权进程。</p></blockquote><h1>进程的并行与并发</h1><p><strong>并行 :</strong> 并行是指两者同时执行,比如赛跑,两个人都在不停的往前跑;(资源够用,比如三个线程,四 核的CPU )</p><p><strong>并发 :</strong> 并发是指资源有限的情况下,两者交替轮流使用资源,比如一段路(单核CPU资源)同时只能过一个 人,A走一段后,让给B,B用完继续给A ,交替使用,目的是提高效率。</p><p><strong>区别:</strong></p><p><strong>并行</strong>是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器。</p><p><strong>并发</strong>是从宏观上,在一个时间段上可以看出是同时执行的,比如一个服务器同时处理多个session。</p><h1>同步异步阻塞非阻塞</h1><p><img src="image-20220711153025029.png" alt="进程三状态转换示意图"></p><p>在了解其他概念之前,我们首先要了解进程的几个状态。在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。</p><ul class="lvl-0"><li class="lvl-2"><p>就绪(Ready)状态</p><p>当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状 态称为就绪状态。</p></li><li class="lvl-2"><p>执行/运行(Running)状态</p><p>当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。</p></li><li class="lvl-2"><p>阻塞(Blocked)状态</p><p>正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起 进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等</p></li></ul><p><img src="image-20220711153151271.png" alt="阻塞距离示意图"></p><h2 id="同步和异步">同步和异步</h2><p>所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才 能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。</p><p>所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即 执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法 确定,所以它是不可靠的任务序列。</p><ul class="lvl-0"><li class="lvl-2"><p>异步 =>“我去吃饭了。”</p></li><li class="lvl-2"><p>同步 =>“我去吃饭了。” ”嗯“</p></li></ul><h2 id="阻塞与非阻塞">阻塞与非阻塞</h2><p>阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的</p><h2 id="同步-异步与阻塞-非阻塞">同步/异步与阻塞/非阻塞</h2><ul class="lvl-0"><li class="lvl-2"><p>同步阻塞形式</p><p>效率最低。就是你专心排队,什么别的事都不做。</p></li><li class="lvl-2"><p>异步阻塞形式</p><p>如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发(通知),也就是领了一 张小纸条,假如在这段时间里他不能离开银行做其它的事情,那么很显然,这个人被阻塞在了 这个等待的操作上面</p><p>异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息通知时被阻 塞。</p></li><li class="lvl-2"><p>同步非阻塞形式</p><p>实际上是效率低下的。</p><p>想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,如果把打电话和观察排队 的位置看成是程序的两个操作的话,这个程序需要在这两种不同的行为之间来回的切换,效率 可想而知是低下的。</p></li><li class="lvl-2"><p>异步非阻塞形式</p><p>效率更高</p></li><li class="lvl-2"><p>因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,程序没有在两种不同的 操作中来回切换。</p></li><li class="lvl-2"><p>比如说,这个人突然发觉自己烟瘾犯了,需要出去抽根烟,于是他告诉大堂经理说,排到我这个号 码的时候麻烦到外面通知我一下,那么他就没有被阻塞在这个等待的操作上面,自然这个就是异步 +非阻塞的方式了。现在很多餐厅取号就是这样的形式。</p></li></ul><p>很多人会把同步和阻塞混淆,是因为很多时候同步操作会以阻塞的形式表现出来,同样的,很多人也会 把异步和非阻塞混淆,因为异步操作一般都不会在真正的IO操作处被阻塞。</p><h1>进程的创建与结束</h1><h2 id="进程的创建">进程的创建</h2><p>但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦启动微波炉,所有的进程都已经存在</p><p>而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4中形式 创建新的进程:</p><ol><li class="lvl-3"><p>系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互, 后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮 件、web页面、新闻、打印)</p></li><li class="lvl-3"><p>一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)</p></li><li class="lvl-3"><p>用户的交互式请求,而创建一个新进程(如用户双击暴风影音)</p></li><li class="lvl-3"><p>一个批处理作业的初始化(只在大型机的批处理系统中应用)</p></li></ol><p>无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的。</p><h2 id="进程的结束">进程的结束</h2><ol><li class="lvl-3"><p>正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在 linux中用exit,在windows中用ExitProcess)</p></li><li class="lvl-3"><p>出错退出(自愿,python a.py中a.py不存在)</p></li><li class="lvl-3"><p>严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常, try…except…)</p></li><li class="lvl-3"><p>被其他进程杀死(非自愿,如kill -9)</p></li></ol><h1>multiprocess模块</h1><p>由于提供的子模块非常多,为了方便大家归类记忆,我将这部分大致分为四个部分:创建进程部分,进 程同步部分,进程池部分,进程之间数据共享。</p><h1>multiprocess.process模块</h1><h2 id="process模块介绍">process模块介绍</h2><p>process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。</p><figure class="highlight fortran"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs fortran">Process([group [, <span class="hljs-keyword">target</span> [, <span class="hljs-keyword">name</span> [, args [, kwargs]]]]]),由该类实例化得到的对<br>象,表示一个子进程中的任务(尚未启动)<br>强调:<br><span class="hljs-number">1.</span> 需要使用关键字的方式来指定参数<br><span class="hljs-number">2.</span> args指定的为传给<span class="hljs-keyword">target</span>函数的位置参数,是一个元组形式,必须有逗号<br>参数介绍:<br><span class="hljs-number">1</span> group参数未使用,值始终为<span class="hljs-keyword">None</span><br><span class="hljs-number">2</span> <span class="hljs-keyword">target</span>表示调用对象,即子进程要执行的任务<br><span class="hljs-number">3</span> args表示调用对象的位置参数元组<br><span class="hljs-number">4</span> kwargs表示调用对象的字典<br><span class="hljs-number">5</span> <span class="hljs-keyword">name</span>为子进程的名称<br></code></pre></td></tr></table></figure><p>方法介绍</p><table><thead><tr><th>p.start()</th><th>启动进程,并调用该子进程中的p.run()</th></tr></thead><tbody><tr><td>p.run()</td><td>进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类 中一定要实现该方法</td></tr><tr><td>p.terminate()</td><td>强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就 成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那 么也将不会被释放,进而导致死锁</td></tr><tr><td>p.is_alive()</td><td>如果p仍然运行,返回True</td></tr><tr><td>p.join([timeout])</td><td>主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状 态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开 启的进程,而不能join住run开启的进程</td></tr></tbody></table><p>属性介绍</p><table><thead><tr><th>p.daemon</th><th>默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止 时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在 p.start()之前设置</th></tr></thead><tbody><tr><td><a href="http://p.name">p.name</a></td><td>进程的名称</td></tr><tr><td>p.pid</td><td>进程的pid</td></tr><tr><td>p.exitcode</td><td>进程在运行时为None、如果为–N,表示被信号N结束(了解即可)</td></tr><tr><td>p.authkey</td><td>进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的 用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的 身份验证键时才能成功(了解即可)</td></tr></tbody></table><p>注意:在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会 自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。因此如果将process()直接写在 文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用 if <strong>name</strong> ==‘<strong>main</strong>’ 判断保护起来,import 的时候 ,就不会递归运行了。</p><h1>使用process模块创建进程</h1><p>在一个python进程中开启子进程,start方法和并发效果。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>(<span class="hljs-params">name</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'hello'</span>,name)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'子进程'</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>p = Process(target=f,args=(<span class="hljs-string">'aaron'</span>,))<br>p.start()<br>time.sleep(<span class="hljs-number">1</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主程序'</span>)<br></code></pre></td></tr></table></figure><p>使用join方法</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>(<span class="hljs-params">name</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'hello'</span>,name)<br>time.sleep(<span class="hljs-number">1</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'子进程'</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>p = Process(target=f,args=(<span class="hljs-string">'zhangsan'</span>,))<br>p.start()<br>p.join()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主程序'</span>)<br></code></pre></td></tr></table></figure><p>查看进程号(通过进程号可以看出来哪个程序是先结束)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>(<span class="hljs-params">x</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'子进程id:'</span>,os.getpid(),<span class="hljs-string">'父进程id:'</span>,os.getppid())<br><span class="hljs-keyword">return</span> x*x<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主进程id: '</span>,os.getpid())<span class="hljs-comment">#去查看进程号</span><br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>):<br>p = Process(target=f,args=(i,))<br>p.start()<br></code></pre></td></tr></table></figure><p>进阶,多个进程同时运行(注意,子进程的执行顺序不是根据启动顺序决定的)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>(<span class="hljs-params">name</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'hello'</span>,name)<br>time.sleep(<span class="hljs-number">1</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>p_lst = []<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>):<br>p = Process(target=f, args=(i,))<br>p.start()<br>p_lst.append(p)<br></code></pre></td></tr></table></figure><p>多进程同时运行使用join方法</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>(<span class="hljs-params">name</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'hello'</span>,name)<br>time.sleep(<span class="hljs-number">1</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>):<br>p = Process(target=f, args=(i,))<br>p.start()<br>p.join()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主进程'</span>)<br></code></pre></td></tr></table></figure><p>还是想要借助join的同时,进程之间是异步的</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>(<span class="hljs-params">name</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'hello'</span>,name)<br>time.sleep(<span class="hljs-number">1</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>p_lst = []<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>):<br>p = Process(target=f, args=(i,))<br>p.start()<br>p_lst.append(p)<br>[p.join() <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> p_lst]<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主进程'</span>)<br></code></pre></td></tr></table></figure><p>以继承Process类的形式开启进程的方式</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">MyProcess</span>(<span class="hljs-title class_ inherited__">Process</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name</span>):<br><span class="hljs-built_in">super</span>().__init__()<br>self.name=name<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">run</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(os.getpid())<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 正在和女主播聊天'</span> %self.name)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> p1 = MyProcess(<span class="hljs-string">'陈松'</span>)<br> p2 = MyProcess(<span class="hljs-string">'松哥'</span>)<br> p3 = MyProcess(<span class="hljs-string">'松松'</span>)<br><br> p1.start()<br> p2.start()<br> p3.start()<br><br> p1.join()<br> p2.join()<br> p3.join()<br><br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主进程'</span>)<br></code></pre></td></tr></table></figure><h1>守护进程</h1><p>会随着主进程的结束而结束。</p><p>主进程创建守护进程</p><ol><li class="lvl-3"><p><strong>守护进程会在主进程代码执行结束后就终止</strong></p></li><li class="lvl-3"><p><strong>守护进程内无法再开启子进程,否则抛出异常</strong></p></li></ol><p>注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Myprocess</span>(<span class="hljs-title class_ inherited__">Process</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name</span>):<br><span class="hljs-built_in">super</span>().__init__()<br>self.name = name<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">run</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(os.getpid(),self.name)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s正在和女主播聊天'</span> %self.name)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>p=Myprocess(<span class="hljs-string">'陈松'</span>)<br>p.daemon=<span class="hljs-literal">True</span> <span class="hljs-comment">#一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行</span><br>p.start()<br>time.sleep(<span class="hljs-number">10</span>) <span class="hljs-comment"># 在sleep时查看进程id对应的进程</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>)<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><span class="hljs-keyword">import</span> time<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">foo</span>():<br><span class="hljs-built_in">print</span>(<span class="hljs-number">123</span>)<br>time.sleep(<span class="hljs-number">1</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"end123"</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">bar</span>():<br><span class="hljs-built_in">print</span>(<span class="hljs-number">456</span>)<br>time.sleep(<span class="hljs-number">3</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"end456"</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>p1=Process(target=foo)<br>p2=Process(target=bar)<br><br>p1.daemon=<span class="hljs-literal">True</span><br>p1.start()<br>p2.start()<br>time.sleep(<span class="hljs-number">0.1</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"main-------"</span>)<br><span class="hljs-comment"># 打印该行则主进程代码结束,则守护进程p1应该被终止.#可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止.</span><br></code></pre></td></tr></table></figure><h1>socket聊天并发实例</h1><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> *<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br>server=socket(AF_INET,SOCK_STREAM)<br>server.setsockopt(SOL_SOCKET,SO_REUSEADDR,<span class="hljs-number">1</span>)<br>server.bind((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br>server.listen(<span class="hljs-number">5</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">talk</span>(<span class="hljs-params">conn,client_addr</span>):<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br><span class="hljs-keyword">try</span>:<br>msg=conn.recv(<span class="hljs-number">1024</span>)<br><span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> msg:<span class="hljs-keyword">break</span><br>conn.send(msg.upper())<br><span class="hljs-keyword">except</span> Exception:<br><span class="hljs-keyword">break</span><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>: <span class="hljs-comment">#windows下start进程一定要写到这下面</span><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>conn,client_addr=server.accept()<br><span class="hljs-built_in">print</span>(client_addr)<br>p=Process(target=talk,args=(conn,client_addr))<br>p.start()<br></code></pre></td></tr></table></figure><p>客户端:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> *<br><br>client=socket(AF_INET,SOCK_STREAM)<br>client.connect((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>msg=<span class="hljs-built_in">input</span>(<span class="hljs-string">'>>: '</span>).strip()<br><span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> msg:<span class="hljs-keyword">continue</span><br><br>client.send(msg.encode(<span class="hljs-string">'utf-8'</span>))<br>msg=client.recv(<span class="hljs-number">1024</span>)<br><span class="hljs-built_in">print</span>(msg.decode(<span class="hljs-string">'utf-8'</span>))<br></code></pre></td></tr></table></figure><h2 id="多进程中的其他方法">多进程中的其他方法</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">import</span> random<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Myprocess</span>(<span class="hljs-title class_ inherited__">Process</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,person</span>):<br>self.name=person<br><span class="hljs-built_in">super</span>().__init__()<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">run</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s正在和陈松聊天'</span> %self.name)<br>time.sleep(random.randrange(<span class="hljs-number">1</span>,<span class="hljs-number">5</span>))<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s还在和陈松聊天'</span> %self.name)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>p1=Myprocess(<span class="hljs-string">'陈松'</span>)<br>p1.start()<br>p1.terminate() <span class="hljs-comment"># 关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活</span><br><span class="hljs-built_in">print</span>(p1.is_alive()) <span class="hljs-comment"># 结果为True</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">'开始'</span>)<br>time.sleep(<span class="hljs-number">0.5</span>)<br><span class="hljs-built_in">print</span>(p1.is_alive()) <span class="hljs-comment"># 结果为False</span><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">import</span> random<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Myprocess</span>(<span class="hljs-title class_ inherited__">Process</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,person</span>):<br>self.name=person <span class="hljs-comment"># name属性是Process中的属性,标示进程的名字</span><br><span class="hljs-built_in">super</span>().__init__() <span class="hljs-comment"># 执行父类的初始化方法会覆盖name属性</span><br><span class="hljs-comment">#self.name = person # 在这里设置就可以修改进程名字了</span><br><span class="hljs-comment">#self.person = person #如果不想覆盖进程名,就修改属性名称就可以了</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">run</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s正在和女主播聊天'</span> %self.name)<br><span class="hljs-comment"># print('%s正在和网红脸聊天' %self.person)</span><br>time.sleep(random.randrange(<span class="hljs-number">1</span>,<span class="hljs-number">5</span>))<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s正在和女主播聊天'</span> %self.name)<br><span class="hljs-comment"># print('%s正在和网红脸聊天' %self.person)</span><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>p1=Myprocess(<span class="hljs-string">'陈松'</span>)<br>p1.start()<br><span class="hljs-built_in">print</span>(p1.pid) <span class="hljs-comment">#可以查看子进程的进程id</span><br></code></pre></td></tr></table></figure><h1>进程同步(multiprocess.Lock)</h1><h2 id="锁-——-multiprocess-Lock">锁 —— multiprocess.Lock</h2><p>当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">import</span> random<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>(<span class="hljs-params">n</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s: %s is running'</span> %(n,os.getpid()))<br>time.sleep(random.random())<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s:%s is done'</span> %(n,os.getpid()))<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>):<br>p=Process(target=work,args=(i,))<br>p.start()<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">import</span> random<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process,Lock<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>(<span class="hljs-params">lock,n</span>):<br>lock.acquire()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s: %s is running'</span> % (n, os.getpid()))<br>time.sleep(random.random())<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s: %s is done'</span> % (n, os.getpid()))<br>lock.release()<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>lock=Lock()<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>):<br>p=Process(target=work,args=(lock,i))<br>p.start()<br></code></pre></td></tr></table></figure><p>上面这种情况虽然使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了 时间,却保证了数据的安全。</p><p>写一个抢票程序</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#文件db的内容为:{"count":1}</span><br><span class="hljs-comment">#注意一定要用双引号,不然json无法识别</span><br><span class="hljs-comment">#并发运行,效率高,但竞争写同一文件,数据写入错乱</span><br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process,Lock<br><span class="hljs-keyword">import</span> time,json,random<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">search</span>():<br>dic=json.load(<span class="hljs-built_in">open</span>(<span class="hljs-string">'db'</span>))<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'\033[43m剩余票数%s\033[0m'</span> %dic[<span class="hljs-string">'count'</span>])<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">get</span>():<br>dic=json.load(<span class="hljs-built_in">open</span>(<span class="hljs-string">'db'</span>))<br>time.sleep(<span class="hljs-number">0.1</span>) <span class="hljs-comment">#模拟读数据的网络延迟</span><br><span class="hljs-keyword">if</span> dic[<span class="hljs-string">'count'</span>] ><span class="hljs-number">0</span>:<br>dic[<span class="hljs-string">'count'</span>]-=<span class="hljs-number">1</span><br>time.sleep(<span class="hljs-number">0.2</span>) <span class="hljs-comment">#模拟写数据的网络延迟</span><br>json.dump(dic,<span class="hljs-built_in">open</span>(<span class="hljs-string">'db'</span>,<span class="hljs-string">'w'</span>))<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'\033[43m购票成功\033[0m'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">task</span>():<br>search()<br>get()<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">100</span>): <span class="hljs-comment">#模拟并发100个客户端抢票</span><br>p=Process(target=task)<br>p.start()<br></code></pre></td></tr></table></figure><p>用锁来保护票</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#文件db的内容为:{"count":1}</span><br><span class="hljs-comment">#注意一定要用双引号,不然json无法识别</span><br><span class="hljs-comment">#并发运行,效率高,但竞争写同一文件,数据写入错乱</span><br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process,Lock<br><span class="hljs-keyword">import</span> time,json,random<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">search</span>():<br> dic=json.load(<span class="hljs-built_in">open</span>(<span class="hljs-string">'db'</span>))<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'\033[43m剩余票数%s\033[0m'</span> %dic[<span class="hljs-string">'count'</span>])<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">get</span>():<br> dic=json.load(<span class="hljs-built_in">open</span>(<span class="hljs-string">'db'</span>))<br> time.sleep(<span class="hljs-number">0.1</span>) <span class="hljs-comment">#模拟读数据的网络延迟</span><br> <span class="hljs-keyword">if</span> dic[<span class="hljs-string">'count'</span>] ><span class="hljs-number">0</span>:<br> dic[<span class="hljs-string">'count'</span>]-=<span class="hljs-number">1</span><br> time.sleep(<span class="hljs-number">0.2</span>) <span class="hljs-comment">#模拟写数据的网络延迟</span><br> json.dump(dic,<span class="hljs-built_in">open</span>(<span class="hljs-string">'db'</span>,<span class="hljs-string">'w'</span>))<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'\033[43m购票成功\033[0m'</span>)<br><span class="hljs-keyword">else</span>:<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'\033[31m购票失败\033[0m'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">task</span>(<span class="hljs-params">lock</span>):<br> search()<br> lock.acquire()<br> get()<br> lock.release()<br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> lock = Lock()<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">50</span>): <span class="hljs-comment">#模拟并发50个客户端抢票</span><br> p=Process(target=task,args=(lock,))<br> p.start()<br></code></pre></td></tr></table></figure><p>虽然可以用文件共享数据实现进程间通信,但问题是:</p><ol><li class="lvl-3"><p>效率低(共享数据基于文件,而文件是硬盘上的数据)</p></li><li class="lvl-3"><p>需要自己加锁处理</p></li></ol><p>队列和管道都是将数据存放于内存中</p><p>队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来,</p><p>我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,而且在</p><p>进程数目增多时,往往可以获得更好的可获展性</p><h1>进程间通信——队列 (multiprocess.Queue)</h1><h2 id="进程间通信">进程间通信</h2><p>IPC(Inter-Process Communication)</p><p>进程之间的数据隔离问题</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>():<br><span class="hljs-keyword">global</span> n<br>n = <span class="hljs-number">0</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">'子进程'</span>,n)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>n = <span class="hljs-number">100</span><br>p = Process(target=work)<br>p.start()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主进程'</span>,n)<br></code></pre></td></tr></table></figure><h2 id="队列">队列</h2><h3 id="概念介绍">概念介绍</h3><p>创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs python">Queue([maxsize])<br>创建共享的进程队列。<br>参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。<br>底层队列使用管道和锁定实现。<br></code></pre></td></tr></table></figure><p>队列方法介绍</p><ul class="lvl-0"><li class="lvl-2"><p>Queue([maxsize])</p><p>创建共享的进程队列。maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。 底层队列使用管道和锁定实现。另外,还需要运行支持线程以便队列中的数据传输到底层管道 中。</p></li><li class="lvl-2"><p>Queue的实例q具有以下方法:</p><p>q.get( [ block [ ,timeout ] ] )</p><p>返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。block用于控 制阻塞行为,默认为True. 如果设置为False,将引发Queue.Empty异常(定义在Queue模块 中)。timeout是可选超时时间,用在阻塞模式中。如果在制定的时间间隔内没有项目变为可 用,将引发Queue.Empty异常。</p><p>q.get_nowait( )</p><p>同q.get(False)方法。</p><p>q.put(item [, block [,timeout ] ] )</p><p>将item放入队列。如果队列已满,此方法将阻塞至有空间可用为止。block控制阻塞行为,默 认为True。如果设置为False,将引发Queue.Empty异常(定义在Queue库模块中)。 timeout指定在阻塞模式中等待可用空间的时间长短。超时后将引发Queue.Full异常。</p><p>q.qsize()</p><p>返回队列中目前项目的正确数量。此函数的结果并不可靠,因为在返回结果和在稍后程序中使 用结果之间,队列中可能添加或删除了项目。在某些系统上,此方法可能引发 NotImplementedError异常。</p><p>q.empty()</p><p>如果调用此方法时 q为空,返回True。如果其他进程或线程正在往队列中添加项目,结果是 不可靠的。也就是说,在返回和使用结果之间,队列中可能已经加入新的项目。</p><p>q.full()</p><p>如果q已满,返回为True. 由于线程的存在,结果也可能是不可靠的(参考q.empty()方 法)。。</p></li></ul><p>其他方法</p><ul class="lvl-0"><li class="lvl-2"><p>q.close()</p><p>关闭队列,防止队列中加入更多数据。调用此方法时,后台线程将继续写入那些已入队列但尚未写 入的数据,但将在此方法完成时马上关闭。如果q被垃圾收集,将自动调用此方法。关闭队列不会 在队列使用者中生成任何类型的数据结束信号或异常。例如,如果某个使用者正被阻塞在get() 操作上,关闭生产者中的队列不会导致get()方法返回错误。</p></li><li class="lvl-2"><p>q.cancel_join_thread()</p><p>不会再进程退出时自动连接后台线程。这可以防止join_thread()方法阻塞。</p></li><li class="lvl-2"><p>q.join_thread()</p><p>连接队列的后台线程。此方法用于在调用q.close()方法后,等待所有队列项被消耗。默认情况下,此方法由不是q的原始创建者的所有进程调用。调用q.cancel_join_thread()方法可以禁止这种行为。</p></li></ul><h2 id="代码实例">代码实例</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Queue<br>q=Queue(<span class="hljs-number">3</span>)<br><br><span class="hljs-comment">#put ,get ,put_nowait,get_nowait,full,empty</span><br>q.put(<span class="hljs-number">1</span>)<br>q.put(<span class="hljs-number">2</span>)<br>q.put(<span class="hljs-number">3</span>)<br><span class="hljs-comment"># q.put(4) # 如果队列已经满了,程序就会停在这里,等待数据被别人取走,再将数据放入队列。</span><br> <span class="hljs-comment"># 如果队列中的数据一直不被取走,程序就会永远停在这里。</span><br><span class="hljs-keyword">try</span>:<br>q.put_nowait(<span class="hljs-number">4</span>) <span class="hljs-comment"># 可以使用put_nowait,如果队列满了不会阻塞,但是会因为队列满了而报错。</span><br><span class="hljs-keyword">except</span>: <span class="hljs-comment"># 因此我们可以用一个try语句来处理这个错误。这样程序不会一直阻塞下去,但是会丢掉这个消息。</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">'队列已经满了'</span>)<br><br><span class="hljs-comment"># 因此,我们再放入数据之前,可以先看一下队列的状态,如果已经满了,就不继续put了。</span><br><span class="hljs-built_in">print</span>(q.full()) <span class="hljs-comment">#满了</span><br><br><span class="hljs-built_in">print</span>(q.get())<br><span class="hljs-built_in">print</span>(q.get())<br><span class="hljs-built_in">print</span>(q.get())<br><span class="hljs-comment"># print(q.get()) # 同put方法一样,如果队列已经空了,那么继续取就会出现阻塞。</span><br><span class="hljs-keyword">try</span>:<br>q.get_nowait(<span class="hljs-number">3</span>) <span class="hljs-comment"># 可以使用get_nowait,如果队列满了不会阻塞,但是会因为没取到值而报错。</span><br><span class="hljs-keyword">except</span>: <span class="hljs-comment"># 因此我们可以用一个try语句来处理这个错误。这样程序不会一直阻塞下去。</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">'队列已经空了'</span>)<br><span class="hljs-built_in">print</span>(q.empty()) <span class="hljs-comment">#空了</span><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process, Queue<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>(<span class="hljs-params">q</span>):<br>q.put([time.asctime(), <span class="hljs-string">'from earth'</span>, <span class="hljs-string">'hello'</span>]) <span class="hljs-comment">#调用主函数中p进程传递过来的进程参数 put函数为向队列中添加一条数据。</span><br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> q = Queue() <span class="hljs-comment">#创建一个Queue对象</span><br> p = Process(target=f, args=(q,)) <span class="hljs-comment">#创建一个进程</span><br> p.start()<br> <span class="hljs-built_in">print</span>(q.get())<br> p.join()<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">import</span> multiprocessing<br><br><span class="hljs-comment"># 向queue中输入数据的函数</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">inputQ</span>(<span class="hljs-params">queue</span>):<br> info = <span class="hljs-built_in">str</span>(os.getpid()) + <span class="hljs-string">'(put):'</span> + <span class="hljs-built_in">str</span>(time.asctime())<br> queue.put(info)<br> <br><span class="hljs-comment"># 向queue中输出数据的函数</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">outputQ</span>(<span class="hljs-params">queue</span>):<br> info = queue.get()<br> <span class="hljs-built_in">print</span> (<span class="hljs-string">'%s%s\033[32m%s\033[0m'</span>%(<span class="hljs-built_in">str</span>(os.getpid()), <span class="hljs-string">'(get):'</span>,info))<br> <br><br><span class="hljs-comment"># Main</span><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> multiprocessing.freeze_support()<br> <span class="hljs-comment"># 解决在Windows下运行有可能崩溃</span><br> record1 = [] <span class="hljs-comment"># store input processes</span><br> record2 = [] <span class="hljs-comment"># store output processes</span><br> queue = multiprocessing.Queue(<span class="hljs-number">3</span>)<br> <br><span class="hljs-comment"># 输入进程</span><br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>):<br> process = multiprocessing.Process(target=inputQ,args=(queue,))<br> time.sleep(<span class="hljs-number">1</span>)<br> process.start()<br> record1.append(process)<br> <br><span class="hljs-comment"># 输出进程</span><br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>):<br> process = multiprocessing.Process(target=outputQ,args=(queue,))<br> process.start()<br> record2.append(process)<br><span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> record1:<br>p.join()<br> <br><span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> record2:<br>p.join()<br></code></pre></td></tr></table></figure><h2 id="生产者消费者模型">生产者消费者模型</h2><p>在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线 程的工作能力来提高程序的整体处理数据的速度。</p><p><strong>为什么要使用生产者和消费者模式</strong></p><p>在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生 产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数 据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问 题于是引入了生产者和消费者模式。</p><p><strong>什么是生产者消费者模式</strong></p><p>生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直 接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞 队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生 产者和消费者的处理能力。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process,Queue<br><span class="hljs-keyword">import</span> time,random,os<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">consumer</span>(<span class="hljs-params">q</span>):<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> res=q.get()<br> time.sleep(random.randint(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>))<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃 %s'</span> %(os.getpid(),res))<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">producer</span>(<span class="hljs-params">q</span>):<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>):<br>time.sleep(random.randint(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>))<br>res=<span class="hljs-string">'包子%s'</span> %i<br>q.put(res)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 生产了 %s'</span> %(os.getpid(),res))<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>q=Queue()<br><br><span class="hljs-comment">#生产者们:即厨师们</span><br>p1=Process(target=producer,args=(q,))<br><br><span class="hljs-comment">#消费者们:即吃货们</span><br>c1=Process(target=consumer,args=(q,))<br><br><span class="hljs-comment">#开始</span><br>p1.start()<br>c1.start()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>)<br></code></pre></td></tr></table></figure><p>消费者c在取空了q之后,则一直处于死循环中且卡在q.get()这一步。</p><p>生产者在生产完毕后,往队列中再发一个结束信号,这样消费者在接收到结束信号后就可以break出死 循环</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process,Queue<br><span class="hljs-keyword">import</span> time,random,os<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">consumer</span>(<span class="hljs-params">q</span>):<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> res=q.get()<br> <span class="hljs-keyword">if</span> res <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:<span class="hljs-keyword">break</span> <span class="hljs-comment">#收到结束信号则结束</span><br> time.sleep(random.randint(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>))<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃 %s'</span> %(os.getpid(),res))<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">producer</span>(<span class="hljs-params">q</span>):<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>):<br>time.sleep(random.randint(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>))<br>res=<span class="hljs-string">'包子%s'</span> %i<br>q.put(res)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 生产了 %s'</span> %(os.getpid(),res))<br>q.put(<span class="hljs-literal">None</span>) <span class="hljs-comment">#发送结束信号</span><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>q=Queue()<br><span class="hljs-comment">#生产者们:即厨师们</span><br>p1=Process(target=producer,args=(q,))<br><br><span class="hljs-comment">#消费者们:即吃货们</span><br>c1=Process(target=consumer,args=(q,))<br><br><span class="hljs-comment">#开始</span><br>p1.start()<br>c1.start()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>)<br></code></pre></td></tr></table></figure><p>结束信号None,不一定要由生产者发,主进程里同样可以发,但主进程需要等生产者结束后才应该发送 该信号</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process,Queue<br><span class="hljs-keyword">import</span> time,random,os<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">consumer</span>(<span class="hljs-params">q</span>):<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> res=q.get()<br> <span class="hljs-keyword">if</span> res <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:<span class="hljs-keyword">break</span> <span class="hljs-comment">#收到结束信号则结束</span><br> time.sleep(random.randint(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>))<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃 %s'</span> %(os.getpid(),res))<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">producer</span>(<span class="hljs-params">q</span>):<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">2</span>):<br>time.sleep(random.randint(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>))<br>res=<span class="hljs-string">'包子%s'</span> %i<br>q.put(res)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 生产了 %s'</span> %(os.getpid(),res))<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>q=Queue()<br><span class="hljs-comment">#生产者们:即厨师们</span><br>p1=Process(target=producer,args=(q,))<br> <br> <span class="hljs-comment">#消费者们:即吃货们</span><br> c1=Process(target=consumer,args=(q,))<br> <br> <span class="hljs-comment">#开始</span><br> p1.start()<br> c1.start()<br> <br> p1.join()<br> q.put(<span class="hljs-literal">None</span>) <span class="hljs-comment">#发送结束信号</span><br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>)<br></code></pre></td></tr></table></figure><p>有多个生产者和多个消费者时 有几个消费者就需要发送几次结束信号</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process,Queue<br><span class="hljs-keyword">import</span> time,random,os<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">consumer</span>(<span class="hljs-params">q</span>):<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> res=q.get()<br> <span class="hljs-keyword">if</span> res <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:<span class="hljs-keyword">break</span> <span class="hljs-comment">#收到结束信号则结束</span><br> time.sleep(random.randint(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>))<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃 %s'</span> %(os.getpid(),res))<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">producer</span>(<span class="hljs-params">name,q</span>):<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">2</span>):<br> time.sleep(random.randint(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>))<br> res=<span class="hljs-string">'%s%s'</span> %(name,i)<br> q.put(res)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 生产了 %s'</span> %(os.getpid(),res))<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> q=Queue()<br> <span class="hljs-comment">#生产者们:即厨师们</span><br> p1=Process(target=producer,args=(<span class="hljs-string">'包子'</span>,q))<br> p2=Process(target=producer,args=(<span class="hljs-string">'骨头'</span>,q))<br> p3=Process(target=producer,args=(<span class="hljs-string">'泔水'</span>,q))<br> <br> <span class="hljs-comment">#消费者们:即吃货们</span><br> c1=Process(target=consumer,args=(q,))<br> c2=Process(target=consumer,args=(q,))<br><br> <span class="hljs-comment">#开始</span><br> p1.start()<br> p2.start()<br> p3.start()<br> c1.start()<br> <span class="hljs-comment"># c2.start()</span><br> p1.join() <span class="hljs-comment">#必须保证生产者全部生产完毕,才应该发送结束信号</span><br> p2.join()<br> p3.join()<br> q.put(<span class="hljs-literal">None</span>) <span class="hljs-comment">#有几个消费者就应该发送几次结束信号None</span><br> <span class="hljs-comment"># q.put(None) #发送结束信号</span><br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>)<br></code></pre></td></tr></table></figure><p>JoinableQueue([maxsize])</p><p>创建可连接的共享进程队列。这就像是一个Queue对象,但队列允许项目的使用者通知生产者项目已经 被成功处理。通知进程是使用共享的信号和条件变量来实现的。</p><ul class="lvl-0"><li class="lvl-2"><p>q.task_done()</p><pre><code class="hljs"> 使用者使用此方法发出信号,表示q.get()返回的项目已经被处理。如果调用此方法的次数大于从队 列中删除的项目数量,将引发ValueError异常。</code></pre></li><li class="lvl-2"><p>q.join()</p><pre><code class="hljs"> 生产者将使用此方法进行阻塞,直到队列中所有项目均被处理。阻塞将持续到为队列中的每个项目 均调用q.task_done()方法为止。</code></pre></li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process, JoinableQueue<br><span class="hljs-keyword">import</span> time, random, os<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">consumer</span>(<span class="hljs-params">q</span>):<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>res = q.get()<br>time.sleep(random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>))<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃 %s'</span> % (os.getpid(), res))<br>q.task_done() <span class="hljs-comment"># 向q.join()发送一次信号,证明一个数据已经被取走了</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">producer</span>(<span class="hljs-params">name, q</span>):<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>):<br>time.sleep(random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>))<br>res = <span class="hljs-string">'%s%s'</span> % (name, i)<br>q.put(res)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 生产了 %s'</span> % (os.getpid(), res))<br>q.join() <span class="hljs-comment"># 生产完毕,使用此方法进行阻塞,直到队列中所有项目均被处理。</span><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> q = JoinableQueue()<br> <span class="hljs-comment"># 生产者们:即厨师们</span><br> p1 = Process(target=producer, args=(<span class="hljs-string">'包子'</span>, q))<br> p2 = Process(target=producer, args=(<span class="hljs-string">'骨头'</span>, q))<br> p3 = Process(target=producer, args=(<span class="hljs-string">'泔水'</span>, q))<br> <br> <span class="hljs-comment"># 消费者们:即吃货们</span><br> c1 = Process(target=consumer, args=(q,))<br> c2 = Process(target=consumer, args=(q,))<br> c1.daemon = <span class="hljs-literal">True</span><br> c2.daemon = <span class="hljs-literal">True</span><br> <br> <span class="hljs-comment"># 开始</span><br> p_l = [p1, p2, p3, c1, c2]<br> <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> p_l:<br>p.start()<br><br> p1.join()<br> p2.join()<br> p3.join()<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'主'</span>)<br><br><span class="hljs-comment"># 主进程等--->p1,p2,p3等---->c1,c2</span><br><span class="hljs-comment"># p1,p2,p3结束了,证明c1,c2肯定全都收完了p1,p2,p3发到队列的数据</span><br><span class="hljs-comment"># 因而c1,c2也没有存在的价值了,不需要继续阻塞在进程中影响主进程了。应该随着主进程的结束而结束,所以设置成守护进程就可以了。</span><br></code></pre></td></tr></table></figure><h1>进程之间的数据共享</h1><p>但进程间应该尽量避免通信,即便需要通信,也应该选择进程安全的工具来避免加锁带来的问题。</p><p>以后我们会尝试使用数据库来解决现在进程之间的数据共享问题</p><p>进程间数据是独立的,可以借助于队列或管道实现通信,二者都是基于消息传递的</p><p>虽然进程间数据独立,但可以通过Manager实现数据共享,事实上Manager的功能远不止于此</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Manager,Process,Lock<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>(<span class="hljs-params">d,lock</span>):<br><br><span class="hljs-keyword">with</span> lock: <span class="hljs-comment">#不加锁而操作共享的数据,肯定会出现数据错乱</span><br>d[<span class="hljs-string">'count'</span>]-=<span class="hljs-number">1</span><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>lock=Lock()<br><span class="hljs-keyword">with</span> Manager() <span class="hljs-keyword">as</span> m:<br>dic=m.<span class="hljs-built_in">dict</span>({<span class="hljs-string">'count'</span>:<span class="hljs-number">10</span>})<br>p_l=[]<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>):<br>p=Process(target=work,args=(dic,lock))<br>p_l.append(p)<br>p.start()<br><span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> p_l:<br>p.join()<br><span class="hljs-built_in">print</span>(dic)<br></code></pre></td></tr></table></figure><h1>进程池和multiprocess.Pool模块</h1><h2 id="进程池">进程池</h2><p>那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要 消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执 行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。</p><p>定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理 完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进 程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池 中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难 度,还节省了开闭进程的时间,也一定程度上能够实现并发效果。</p><h2 id="multiprocess-Pool模块">multiprocess.Pool模块</h2><h3 id="概念介绍-2">概念介绍</h3><p><code>Pool([numprocess [,initializer [, initargs]]]):创建进程池</code></p><p>numprocess:要创建的进程数,如果省略,将默认使用cpu_count()的值</p><p>initializer:是每个工作进程启动时要执行的可调用对象,默认为None</p><p>initargs:是要传给initializer的参数组</p><p><strong>方法介绍</strong></p><p>p.apply(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。</p><p>‘’‘需要强调的是:此操作并不会在所有池工作进程中并执行func函数。如果要通过不同参数并发地执行 func函数,必须从不同线程调用p.apply()函数或者使用p.apply_async()’‘’</p><p>p.apply_async(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。</p><p>‘’‘此方法的结果是AsyncResult类的实例,callback是可调用对象,接收输入参数。当func的结果变为可 用时,将理解传递给callback。callback禁止执行任何阻塞操作,否则将接收其他异步操作中的结果。’‘’</p><p>p.close():关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成 P.join():等待所有工作进程退出。此方法只能在close()或teminate()之后调用</p><p><strong>其他方法</strong></p><p>方法apply_async()和map_async()的返回值是AsyncResul的实例obj。实例具有以下方法</p><p>obj.get():返回结果,如果有必要则等待结果到达。timeout是可选的。如果在指定时间内还没有到达</p><p>将引发一场。如果远程操作中引发了异常,它将在调用此方法时再次被引发。</p><p>obj.ready():如果调用完成,返回True</p><p>obj.successful():如果调用完成且没有引发异常,返回True,如果在结果就绪之前调用此方法,引发异常</p><p>obj.wait([timeout]):等待结果变为可用。</p><p>obj.terminate():立即终止所有工作进程,同时不执行任何清理或结束任何挂起工作。如果p被垃圾回 收,将自动调用此函数</p><h2 id="代码实例-2">代码实例</h2><p><strong>进程池和多进程效率对比</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Process<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">n</span>):<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>): <span class="hljs-comment"># 同样将1到100,每个数打印十次</span><br><span class="hljs-built_in">print</span>(n+<span class="hljs-number">1</span>)<br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:<br>t1 = time.time()<br>p_list = []<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">100</span>):<br>p = Process(target=func, args=(i,))<br>p_list.append(p)<br>p.start()<br><span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> p_list:<br>p.join()<br>t2 = (time.time() - t1)<br><span class="hljs-built_in">print</span>(t2)<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Pool<br><span class="hljs-keyword">import</span> time<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">n</span>):<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>): <span class="hljs-comment"># 将1到100,每个数打印十次</span><br><span class="hljs-built_in">print</span>(n +<span class="hljs-number">1</span>)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:<br> start = time.time()<br> pool = Pool(<span class="hljs-number">5</span>)<br> pool.<span class="hljs-built_in">map</span>(func, <span class="hljs-built_in">range</span>(<span class="hljs-number">100</span>)) <span class="hljs-comment"># 一百个任务</span><br> t2 = (time.time() - start)<br> <span class="hljs-built_in">print</span>(t2)<br></code></pre></td></tr></table></figure><p><strong>同步和异步</strong></p><p>同步调用</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> os,time<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Pool<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>(<span class="hljs-params">n</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s run'</span> %os.getpid())<br> time.sleep(<span class="hljs-number">3</span>)<br> <span class="hljs-keyword">return</span> n**<span class="hljs-number">2</span><br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> <span class="hljs-comment">#进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务</span><br> p=Pool(<span class="hljs-number">3</span>)<br> res_l=[]<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>):<br><span class="hljs-comment"># 同步调用,直到本次任务执行完毕拿到res,等待任务work执行的过程中可能有阻塞也可能没有阻塞</span><br>res=p.apply(work,args=(i,))<br><span class="hljs-comment"># 但不管该任务是否存在阻塞,同步调用都会在原地等着</span><br><span class="hljs-built_in">print</span>(res_l)<br></code></pre></td></tr></table></figure><p>异步调用</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">import</span> random<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Pool<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">work</span>(<span class="hljs-params">n</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'%s run'</span> %os.getpid())<br> time.sleep(random.random())<br> <span class="hljs-keyword">return</span> n**<span class="hljs-number">2</span><br> <br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br> p=Pool(<span class="hljs-number">3</span>) <span class="hljs-comment">#进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务</span><br> res_l=[]<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">10</span>):<br>res=p.apply_async(work,args=(i,)) <span class="hljs-comment"># 异步运行,根据进程池中有的进程数,每次最多3个子进程在异步执行</span><br><span class="hljs-comment"># 返回结果之后,将结果放入列表,归还进程,之后再执行新的任务</span><br><span class="hljs-comment"># 需要注意的是,进程池中的三个进程不会同时开启或者同时结束</span><br><span class="hljs-comment"># 而是执行完一个就释放一个进程,这个进程就去接收新的任务。</span><br>res_l.append(res)<br><span class="hljs-comment"># 异步apply_async用法:如果使用异步提交的任务,主进程需要使用join,等待进程池内任务都处理完,然后可以用get收集结果</span><br><span class="hljs-comment"># 否则,主进程结束,进程池可能还没来得及执行,也就跟着一起结束了</span><br> p.close()<br> p.join()<br> <span class="hljs-keyword">for</span> res <span class="hljs-keyword">in</span> res_l:<br> <span class="hljs-built_in">print</span>(res.get()) <span class="hljs-comment">#使用get来获取apply_aync的结果,如果是apply,则没有get方法,因为apply是同步执行,立刻获取结果,也根本无需get</span><br></code></pre></td></tr></table></figure><p>进程池聊天</p><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#Pool内的进程数默认是cpu核数,假设为4(查看方法os.cpu_count())</span><br><span class="hljs-comment">#开启6个客户端,会发现2个客户端处于等待状态</span><br><span class="hljs-comment">#在每个进程内查看pid,会发现pid使用为4个,即多个客户端公用4个进程</span><br><span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> *<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Pool<br><span class="hljs-keyword">import</span> os<br><br>server=socket(AF_INET,SOCK_STREAM)<br>server.setsockopt(SOL_SOCKET,SO_REUSEADDR,<span class="hljs-number">1</span>)<br>server.bind((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br>server.listen(<span class="hljs-number">5</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">talk</span>(<span class="hljs-params">conn</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'进程pid: %s'</span> %os.getpid())<br> <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br><span class="hljs-keyword">try</span>:<br> msg=conn.recv(<span class="hljs-number">1024</span>)<br> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> msg:<span class="hljs-keyword">break</span><br> conn.send(msg.upper())<br> <span class="hljs-keyword">except</span> Exception:<br> <span class="hljs-keyword">break</span><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>p=Pool(<span class="hljs-number">4</span>)<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> conn,addr=server.accept()<br> p.apply_async(talk,args=(conn,))<br> <span class="hljs-comment">#p.apply(talk,args=(conn,)) # 同步的话,则同一时间只有一个客户端能访问</span><br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> *<br><br>client=socket(AF_INET,SOCK_STREAM)<br>client.connect((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> msg=<span class="hljs-built_in">input</span>(<span class="hljs-string">'>>: '</span>).strip()<br> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> msg:<span class="hljs-keyword">continue</span><br><br> client.send(msg.encode(<span class="hljs-string">'utf-8'</span>))<br> msg=client.recv(<span class="hljs-number">1024</span>)<br> <span class="hljs-built_in">print</span>(msg.decode(<span class="hljs-string">'utf-8'</span>))<br></code></pre></td></tr></table></figure><p>并发开启多个客户端,服务端同一时间只有4个不同的pid,只能结束一个客户端,另外一个客户端才会 进来.</p><p><strong>回调函数</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs python">需要回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理<br>我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数<br><br>我们可以把耗时间(阻塞)的任务放到进程池中,然后指定回调函数(主进程负责执行),这样主进程在<br>执行回调函数时就省去了I/O的过程,直接拿到的是任务的结果。<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Pool<br><span class="hljs-keyword">import</span> requests<br><span class="hljs-keyword">import</span> json<br><span class="hljs-keyword">import</span> os<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">get_page</span>(<span class="hljs-params">url</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'<进程%s> get %s'</span> %(os.getpid(),url))<br> respone=requests.get(url)<br> <span class="hljs-keyword">if</span> respone.status_code == <span class="hljs-number">200</span>:<br><span class="hljs-keyword">return</span> {<span class="hljs-string">'url'</span>:url,<span class="hljs-string">'text'</span>:respone.text}<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pasrse_page</span>(<span class="hljs-params">res</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'<进程%s> parse %s'</span> %(os.getpid(),res[<span class="hljs-string">'url'</span>]))<br> parse_res=<span class="hljs-string">'url:<%s> size:[%s]\n'</span> %(res[<span class="hljs-string">'url'</span>],<span class="hljs-built_in">len</span>(res[<span class="hljs-string">'text'</span>]))<br> <span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(<span class="hljs-string">'db.txt'</span>,<span class="hljs-string">'a'</span>) <span class="hljs-keyword">as</span> f:<br>f.write(parse_res)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>urls=[<br> <span class="hljs-string">'https://www.baidu.com'</span>,<br> <span class="hljs-string">'https://www.python.org'</span>,<br> <span class="hljs-string">'https://www.openstack.org'</span>,<br> <span class="hljs-string">'http://www.sina.com.cn/'</span><br>]<br><br> p=Pool(<span class="hljs-number">3</span>)<br> res_l=[]<br> <span class="hljs-keyword">for</span> url <span class="hljs-keyword">in</span> urls:<br> res=p.apply_async(get_page,args=(url,),callback=pasrse_page)<br> res_l.append(res)<br> p.close()<br>p.join()<br><span class="hljs-built_in">print</span>([res.get()[<span class="hljs-string">'url'</span>] <span class="hljs-keyword">for</span> res <span class="hljs-keyword">in</span> res_l]) <span class="hljs-comment">#拿到的是get_page的结果,其实完全没必要拿该结果,该结果已经传给回调函数处理了</span><br></code></pre></td></tr></table></figure><p>爬虫实例</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> re<br><span class="hljs-keyword">from</span> urllib.request <span class="hljs-keyword">import</span> urlopen<br><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Pool<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">get_page</span>(<span class="hljs-params">url,pattern</span>):<br> response=urlopen(url).read().decode(<span class="hljs-string">'utf-8'</span>)<br> <span class="hljs-keyword">return</span> pattern,response<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">parse_page</span>(<span class="hljs-params">info</span>):<br> pattern,page_content=info<br> res=re.findall(pattern,page_content)<br> <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> res:<br>dic={<br> <span class="hljs-string">'index'</span>:item[<span class="hljs-number">0</span>].strip(),<br> <span class="hljs-string">'title'</span>:item[<span class="hljs-number">1</span>].strip(),<br> <span class="hljs-string">'actor'</span>:item[<span class="hljs-number">2</span>].strip(),<br> <span class="hljs-string">'time'</span>:item[<span class="hljs-number">3</span>].strip(),<br> }<br><span class="hljs-built_in">print</span>(dic)<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>regex = <span class="hljs-string">r'<dd>.*?<.*?class="board-index.*?>(\d+)</i>.*?title="(.*?)".*?</span><br><span class="hljs-string">class="movie-item-info".*?<p class="star">(.*?)</p>.*?<p</span><br><span class="hljs-string">class="releasetime">(.*?)</p>'</span><br>pattern1=re.<span class="hljs-built_in">compile</span>(regex,re.S)<br><br>url_dic={<br><span class="hljs-string">'http://maoyan.com/board/7'</span>:pattern1,<br>}<br><br> p=Pool()<br> res_l=[]<br> <span class="hljs-keyword">for</span> url,pattern <span class="hljs-keyword">in</span> url_dic.items():<br> res=p.apply_async(get_page,args=(url,pattern),callback=parse_page)<br> res_l.append(res)<br><br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> res_l:<br>i.get()<br></code></pre></td></tr></table></figure><p>如果在主进程中等待进程池中所有任务都执行完毕后,再统一处理结果,则无需回调函数</p>]]></content>
<summary type="html"><h1>什么是进程?</h1>
<p>进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基 本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体; 在当代面向线程设计的计算机结构中,进程是线程的容器</summary>
<category term="Python" scheme="https://xiaolaji.site/categories/Python/"/>
<category term="Python学习" scheme="https://xiaolaji.site/tags/Python%E5%AD%A6%E4%B9%A0/"/>
</entry>
<entry>
<title>Python的套接字</title>
<link href="https://xiaolaji.site/20221001/Python%E7%9A%84%E5%A5%97%E6%8E%A5%E5%AD%97/"/>
<id>https://xiaolaji.site/20221001/Python%E7%9A%84%E5%A5%97%E6%8E%A5%E5%AD%97/</id>
<published>2022-10-01T04:39:00.000Z</published>
<updated>2023-05-27T12:04:38.000Z</updated>
<content type="html"><![CDATA[<h1>套接字的工作流程(基于TCP和 UDP两个协议)</h1><h2 id="TCP和UDP对比">TCP和UDP对比</h2><ul class="lvl-0"><li class="lvl-2"><p>TCP(Transmission Control Protocol)</p><ul class="lvl-2"><li class="lvl-4">可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、 面向字节流。使用TCP的应用:Web浏览器;文件传输程序。</li></ul></li><li class="lvl-2"><p>UDP(User Datagram Protocol)</p><ul class="lvl-2"><li class="lvl-4">不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对 多、面向报文(数据包),尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS); 视频流;IP语音(VoIP)。</li></ul></li></ul><h2 id="TCP协议下的socket">TCP协议下的socket</h2><p><img src="image-20220712140039302.png" alt="TCP过程示意图"></p><p>服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客 户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时 客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应 数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><span class="hljs-comment"># 初始化格式如下</span><br>socket.socket(socket_family,socket_type,protocal=<span class="hljs-number">0</span>)<br><span class="hljs-comment"># socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或</span><br>SOCK_DGRAM。protocol 一般不填,默认值为 <span class="hljs-number">0</span>。<br><span class="hljs-comment"># 获取tcp/ip套接字</span><br>tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><span class="hljs-comment"># 获取udp/ip套接字</span><br>udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<br><span class="hljs-comment"># 由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使</span><br>用 <span class="hljs-string">'from socket import *'</span>,我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这<br>样能 大幅减短我们的代码。<br><span class="hljs-comment"># 例如</span><br>tcpSock = socket(AF_INET, SOCK_STREAM)<br></code></pre></td></tr></table></figure><p><strong>服务端</strong>套接字函数</p><table><thead><tr><th>s.bind()</th><th>绑定(主机,端口号)到套接字</th></tr></thead><tbody><tr><td>s.listen()</td><td>开始TCP监听</td></tr><tr><td>s.accept()</td><td>被动接受TCP客户的连接,(阻塞式)等待连接的到来</td></tr></tbody></table><p><strong>客户端</strong>套接字函数</p><table><thead><tr><th>s.connect()</th><th>s.connect_ex()</th></tr></thead><tbody><tr><td>s.connect_ex()</td><td>connect()函数的扩展版本,出错时返回出错码,而不是抛出异常</td></tr></tbody></table><p>公共用途的套接字函数</p><table><thead><tr><th>s.recv()</th><th>接收TCP数据</th></tr></thead><tbody><tr><td>s.send()</td><td>发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不 会发完)</td></tr><tr><td>s.sendall()</td><td>发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己 端缓存区剩余空间时,数据不丢失,循环调用send直到发完)</td></tr><tr><td>s.recvfrom()</td><td>接收UDP数据</td></tr><tr><td>s.sendto()</td><td>发送UDP数据</td></tr><tr><td>s.getpeername()</td><td>连接到当前套接字的远端的地址</td></tr><tr><td>s.getsockname()</td><td>当前套接字的地址</td></tr><tr><td>s.getsockopt()</td><td>返回指定套接字的参数</td></tr><tr><td>s.setsockopt()</td><td>设置指定套接字的参数</td></tr><tr><td>s.close()</td><td>关闭套接字</td></tr></tbody></table><p>面向锁的套接字方法</p><table><thead><tr><th>s.setblocking()</th><th>设置套接字的阻塞与非阻塞模式</th></tr></thead><tbody><tr><td>s.settimeout()</td><td>设置阻塞套接字操作的超时时间</td></tr><tr><td>s.gettimeout()</td><td>得到阻塞套接字操作的超时时间</td></tr></tbody></table><p>面向文件的套接字的函数</p><table><thead><tr><th>s.fileno()</th><th>套接字的文件描述符</th></tr></thead><tbody><tr><td>s.makefile()</td><td>创建一个与该套接字相关的文件</td></tr></tbody></table><p>第一版,单个客户端与服务端通信</p><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br>phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) <span class="hljs-comment"># 买电话</span><br><br>phone.bind((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>)) <span class="hljs-comment"># 0 ~ 65535 1024之前系统分配好的端口 绑定电话卡</span><br><br>phone.listen(<span class="hljs-number">5</span>) <span class="hljs-comment"># 同一时刻有5个请求,但是可以有N多个链接。 开机。</span><br><br><br>conn, client_addr = phone.accept() <span class="hljs-comment"># 接电话</span><br><span class="hljs-built_in">print</span>(conn, client_addr, sep=<span class="hljs-string">'\n'</span>)<br><br>from_client_data = conn.recv(<span class="hljs-number">1024</span>) <span class="hljs-comment"># 一次接收的最大限制 bytes</span><br><span class="hljs-built_in">print</span>(from_client_data.decode(<span class="hljs-string">'utf-8'</span>))<br><br>conn.send(from_client_data.upper())<br><br>conn.close() <span class="hljs-comment"># 挂电话</span><br><br>phone.close() <span class="hljs-comment"># 关机</span><br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br>phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) <span class="hljs-comment"># 买电话</span><br><br>phone.connect((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>)) <span class="hljs-comment"># 与客户端建立连接, 拨号</span><br><br>phone.send(<span class="hljs-string">'hello'</span>.encode(<span class="hljs-string">'utf-8'</span>))<br><br>from_server_data = phone.recv(<span class="hljs-number">1024</span>)<br><br><span class="hljs-built_in">print</span>(from_server_data)<br><br>phone.close() <span class="hljs-comment"># 挂电话</span><br></code></pre></td></tr></table></figure><p>第二版,通信循环</p><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br>phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)<br>phone.bind((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br>phone.listen(<span class="hljs-number">5</span>)<br><br>conn,client_addr = phone.accept()<br><span class="hljs-built_in">print</span>(conn,client_addr,sep=<span class="hljs-string">'\n'</span>)<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br><span class="hljs-keyword">try</span>:<br>from_client_data = conn.recv(<span class="hljs-number">1024</span>)<br><span class="hljs-built_in">print</span>(from_client_data.decode(<span class="hljs-string">'utf-8'</span>))<br><br>conn.send(from_client_data.upper())<br><span class="hljs-keyword">except</span> ConnectionResetError:<br><span class="hljs-keyword">break</span><br><br>conn.close()<br>phone.close()<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br>phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)<br>phone.connect((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> client_data = <span class="hljs-built_in">input</span>(<span class="hljs-string">'>>> '</span>)<br> phone.send(client_data.encode(<span class="hljs-string">'utf-8'</span>))<br> <br> from_server_data = phone.recv(<span class="hljs-number">1024</span>)<br> <span class="hljs-built_in">print</span>(from_server_data.decode(<span class="hljs-string">'utf-8'</span>))<br> <br>phone.close()<br></code></pre></td></tr></table></figure><p>第三版, 通信,连接循环</p><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br>phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)<br>phone.bind((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br><br>phone.listen(<span class="hljs-number">5</span>)<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> conn,client_addr = phone.accept()<br> <span class="hljs-built_in">print</span>(conn,client_addr,sep=<span class="hljs-string">'\n'</span>)<br> <br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br><span class="hljs-keyword">try</span>:<br>from_client_data = conn.recv(<span class="hljs-number">1024</span>)<br><span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> from_client_data:<br><span class="hljs-keyword">break</span><br><span class="hljs-built_in">print</span>(from_client_data.decode(<span class="hljs-string">'utf-8'</span>))<br><br>conn.send(from_client_data.upper())<br><span class="hljs-keyword">except</span>:<br><span class="hljs-keyword">break</span><br><br>conn.close()<br>phone.close()<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br>phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)<br>phone.connect((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8080</span>))<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> client_data = <span class="hljs-built_in">input</span>(<span class="hljs-string">'>>> '</span>)<br> phone.send(client_data.encode(<span class="hljs-string">'utf-8'</span>))<br> <span class="hljs-keyword">if</span> client_data == <span class="hljs-string">'q'</span>:<span class="hljs-keyword">break</span><br> <br> from_server_data = phone.recv(<span class="hljs-number">1024</span>)<br> <span class="hljs-built_in">print</span>(from_server_data.decode(<span class="hljs-string">'utf-8'</span>))<br> <br>phone.close()<br></code></pre></td></tr></table></figure><p>远程执行命令的示例:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> subprocess<br><br>phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><br>phone.bind((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br><br>phone.listen(<span class="hljs-number">5</span>)<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>: <span class="hljs-comment"># 循环连接客户端</span><br> conn, client_addr = phone.accept()<br> <span class="hljs-built_in">print</span>(client_addr)<br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br><span class="hljs-keyword">try</span>:<br> cmd = conn.recv(<span class="hljs-number">1024</span>)<br> ret = subprocess.Popen(cmd.decode(<span class="hljs-string">'utf-8'</span>), shell=<span class="hljs-literal">True</span>,<br>stdout=subprocess.PIPE, stderr=subprocess.PIPE)<br> correct_msg = ret.stdout.read()<br> error_msg = ret.stderr.read()<br> conn.send(correct_msg + error_msg)<br><span class="hljs-keyword">except</span> ConnectionResetError:<br><span class="hljs-keyword">break</span><br><br>conn.close()<br>phone.close()<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br>phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) <span class="hljs-comment"># 买电话</span><br><br>phone.connect((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>)) <span class="hljs-comment"># 与客户端建立连接, 拨号</span><br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br>cmd = <span class="hljs-built_in">input</span>(<span class="hljs-string">'>>>'</span>)<br>phone.send(cmd.encode(<span class="hljs-string">'utf-8'</span>))<br><br>from_server_data = phone.recv(<span class="hljs-number">1024</span>)<br><br><span class="hljs-built_in">print</span>(from_server_data.decode(<span class="hljs-string">'gbk'</span>))<br><br>phone.close() <span class="hljs-comment"># 挂电话</span><br></code></pre></td></tr></table></figure><h1>UDP协议下的socket</h1><p>udp是无链接的,先启动哪一端都不会报错</p><p><img src="image-20220712141427062.png" alt="UDP的过程示意图"></p><p>服务器端先初始化Socket,然后与端口绑定(bind),recvform接收消息,这个消息有两项,消息内容和 对方客户端的地址,然后回复消息时也要带着你收到的这个客户端的地址,发送回去,最后关闭连接, 一次交互结束</p><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br>udp_sk = socket.socket(<span class="hljs-built_in">type</span>=socket.SOCK_DGRAM) <span class="hljs-comment">#创建一个服务器的套接字</span><br>udp_sk.bind((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">9000</span>)) <span class="hljs-comment">#绑定服务器套接字</span><br>msg,addr = udp_sk.recvfrom(<span class="hljs-number">1024</span>)<br><span class="hljs-built_in">print</span>(msg)<br>udp_sk.sendto(<span class="hljs-string">b'hi'</span>,addr) <span class="hljs-comment"># 对话(接收与发送)</span><br>udp_sk.close() <span class="hljs-comment"># 关闭服务器套接字</span><br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br>ip_port=(<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">9000</span>)<br>udp_sk=socket.socket(<span class="hljs-built_in">type</span>=socket.SOCK_DGRAM)<br>udp_sk.sendto(<span class="hljs-string">b'hello'</span>,ip_port)<br>back_msg,addr=udp_sk.recvfrom(<span class="hljs-number">1024</span>)<br><span class="hljs-built_in">print</span>(back_msg.decode(<span class="hljs-string">'utf-8'</span>),addr)<br></code></pre></td></tr></table></figure><p>类似于qq聊天的代码示例</p><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br>ip_port=(<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8081</span>)<br>udp_server_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)<br><span class="hljs-comment">#DGRAM:datagram 数据报文的意思,象征着UDP协议的通信方式</span><br>udp_server_sock.bind(ip_port)<span class="hljs-comment">#你对外提供服务的端口就是这一个,所有的客户端都是通过这个端口和你进行通信的</span><br><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> qq_msg,addr=udp_server_sock.recvfrom(<span class="hljs-number">1024</span>)<span class="hljs-comment"># 阻塞状态,等待接收消息</span><br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'来自[%s:%s]的一条消息:\033[1;34;43m%s\033[0m'</span> %(addr[<span class="hljs-number">0</span>],addr[<span class="hljs-number">1</span>],qq_msg.decode(<span class="hljs-string">'utf-8'</span>)))<br>back_msg=<span class="hljs-built_in">input</span>(<span class="hljs-string">'回复消息: '</span>).strip()<br><br>udp_server_sock.sendto(back_msg.encode(<span class="hljs-string">'utf-8'</span>),addr)<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br>BUFSIZE=<span class="hljs-number">1024</span><br>udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)<br><br>qq_name_dic={<br> <span class="hljs-string">'taibai'</span>:(<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8081</span>),<br> <span class="hljs-string">'Jedan'</span>:(<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8081</span>),<br> <span class="hljs-string">'Jack'</span>:(<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8081</span>),<br> <span class="hljs-string">'John'</span>:(<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8081</span>),<br>}<br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> <span class="hljs-comment"># 选择聊天对象</span><br> <span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> qq_name=<span class="hljs-built_in">input</span>(<span class="hljs-string">'请选择聊天对象: '</span>).strip()<br> <span class="hljs-keyword">if</span> qq_name <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> qq_name_dic:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'没有这个聊天对象'</span>)<br> <span class="hljs-keyword">continue</span><br> <span class="hljs-keyword">break</span><br> <br><span class="hljs-comment"># 聊天过程</span><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>msg=<span class="hljs-string">'发给'</span>+ qq_name + <span class="hljs-string">': '</span> + <span class="hljs-built_in">input</span>(<span class="hljs-string">'请输入消息,回车发送,输入q结束和他的聊天: '</span>).strip()<br><span class="hljs-keyword">if</span> msg == <span class="hljs-string">'q'</span>:<span class="hljs-keyword">break</span><br><span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> msg:<span class="hljs-keyword">continue</span><br>udp_client_socket.sendto(msg.encode(<span class="hljs-string">'utf-8'</span>),qq_name_dic[qq_name])<span class="hljs-comment">#必须带着自己的地址,这就是UDP不一样的地方,不需要建立连接,但是要带着自己的地址给服务端,否则服务端无法判断是谁给我发的消息,并且不知道该把消息回复到什么地方,因为我们之间没有建立连接通道</span><br><br> back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)<span class="hljs-comment"># 同样也是阻塞状态,等待接收消息</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">'来自[%s:%s]的一条消息:\033[1;34;43m%s\033[0m'</span> %(addr[<span class="hljs-number">0</span>],addr[<span class="hljs-number">1</span>],back_msg.decode(<span class="hljs-string">'utf-8'</span>)))<br> <br>udp_client_socket.close()<br></code></pre></td></tr></table></figure><p>自制时间服务器</p><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> *<br><span class="hljs-keyword">from</span> time <span class="hljs-keyword">import</span> strftime<br><span class="hljs-keyword">import</span> time<br>ip_port = (<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">9000</span>)<br>bufsize = <span class="hljs-number">1024</span><br><br>tcp_server = socket(AF_INET, SOCK_DGRAM)<br>tcp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,<span class="hljs-number">1</span>)<br>tcp_server.bind(ip_port)<br><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> msg, addr = tcp_server.recvfrom(bufsize)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'===>'</span>, msg.decode(<span class="hljs-string">'utf-8'</span>))<br> stru_time = time.localtime() <span class="hljs-comment">#当前的结构化时间</span><br> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> msg:<br> time_fmt = <span class="hljs-string">'%Y-%m-%d %X'</span><br> <span class="hljs-keyword">else</span>:<br> time_fmt = msg.decode(<span class="hljs-string">'utf-8'</span>)<br> back_msg = strftime(time_fmt,stru_time)<br> <span class="hljs-built_in">print</span>(back_msg,<span class="hljs-built_in">type</span>(back_msg))<br> tcp_server.sendto(back_msg.encode(<span class="hljs-string">'utf-8'</span>), addr)<br>tcp_server.close()<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> *<br>ip_port=(<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">9000</span>)<br>bufsize=<span class="hljs-number">1024</span><br><br>tcp_client=socket(AF_INET,SOCK_DGRAM)<br><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br> msg=<span class="hljs-built_in">input</span>(<span class="hljs-string">'请输入时间格式(例%Y %m %d)>>: '</span>).strip()<br> tcp_client.sendto(msg.encode(<span class="hljs-string">'utf-8'</span>),ip_port)<br> <br> data=tcp_client.recv(bufsize)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'当前日期:'</span>,<span class="hljs-built_in">str</span>(data,encoding=<span class="hljs-string">'utf-8'</span>))<br></code></pre></td></tr></table></figure><h1>粘包</h1><p><img src="image-20220712142023973.png" alt="粘包过程图"></p><p>每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。</p><p>write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区 发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也 不管它们何时被发送到网络,这些都是TCP协议负责的事情。</p><p>TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断 积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因 素,不由程序员控制。</p><p>read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。</p><p>这些I/O缓冲区特性可整理如下:</p><ol><li class="lvl-3"><p>I/O缓冲区在每个TCP套接字中单独存在;</p></li><li class="lvl-3"><p>I/O缓冲区在创建套接字时自动生成;</p></li><li class="lvl-3"><p>即使关闭套接字也会继续传送输出缓冲区中遗留的数据;</p></li><li class="lvl-3"><p>关闭套接字将丢失输入缓冲区中的数据。</p></li></ol><h2 id="两种情况下会发生粘包">两种情况下会发生粘包</h2><ol><li class="lvl-3"><p>接收方没有及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部 分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)</p></li></ol><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> subprocess<br><br>phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><br>phone.bind((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br><br>phone.listen(<span class="hljs-number">5</span>)<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>: <span class="hljs-comment"># 循环连接客户端</span><br> conn, client_addr = phone.accept()<br> <span class="hljs-built_in">print</span>(client_addr)<br> <br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br><span class="hljs-keyword">try</span>:<br>cmd = conn.recv(<span class="hljs-number">1024</span>)<br>ret = subprocess.Popen(cmd.decode(<span class="hljs-string">'utf-8'</span>), shell=<span class="hljs-literal">True</span>,stdout=subprocess.PIPE, stderr=subprocess.PIPE)<br> correct_msg = ret.stdout.read()<br> error_msg = ret.stderr.read()<br> conn.send(correct_msg + error_msg)<br><span class="hljs-keyword">except</span> ConnectionResetError:<br><span class="hljs-keyword">break</span><br><br>conn.close()<br>phone.close()<br></code></pre></td></tr></table></figure><p>发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据也很小,会合到一 起,产生粘包)</p><p>服务端</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">import</span> socket<br><br><br>phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><br>phone.bind((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br><br>phone.listen(<span class="hljs-number">5</span>)<br><br>conn, client_addr = phone.accept()<br><br>frist_data = conn.recv(<span class="hljs-number">1024</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'1:'</span>,frist_data.decode(<span class="hljs-string">'utf-8'</span>)) <span class="hljs-comment"># 1: helloworld</span><br>second_data = conn.recv(<span class="hljs-number">1024</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'2:'</span>,second_data.decode(<span class="hljs-string">'utf-8'</span>))<br><br><br>conn.close()<br>phone.close()<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><br>phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><br>phone.connect((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br><br>phone.send(<span class="hljs-string">b'hello'</span>)<br>phone.send(<span class="hljs-string">b'world'</span>)<br><br>phone.close()<br></code></pre></td></tr></table></figure><h1>粘包的解决方案</h1><h2 id="struct模块">struct模块</h2><p>该模块可以把一个类型,如数字,转成固定长度的bytes</p><p><img src="image-20220712142819170.png" alt="Struct转换对应图"></p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">import</span> struct<br><span class="hljs-comment"># 将一个数字转化成等长度的bytes类型。</span><br>ret = struct.pack(<span class="hljs-string">'i'</span>, <span class="hljs-number">183346</span>)<br><span class="hljs-built_in">print</span>(ret, <span class="hljs-built_in">type</span>(ret), <span class="hljs-built_in">len</span>(ret))<br><br><span class="hljs-comment"># 通过unpack反解回来</span><br>ret1 = struct.unpack(<span class="hljs-string">'i'</span>,ret)[<span class="hljs-number">0</span>]<br><span class="hljs-built_in">print</span>(ret1, <span class="hljs-built_in">type</span>(ret1), <span class="hljs-built_in">len</span>(ret1))<br><br><span class="hljs-comment"># 但是通过struct 处理不能处理太大</span><br></code></pre></td></tr></table></figure><p>方案一:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> subprocess<br><span class="hljs-keyword">import</span> struct<br><br>phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><br>phone.bind((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br><br>phone.listen(<span class="hljs-number">5</span>)<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> conn, client_addr = phone.accept()<br> <span class="hljs-built_in">print</span>(client_addr)<br> <br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br><span class="hljs-keyword">try</span>:<br> cmd = conn.recv(<span class="hljs-number">1024</span>)<br> ret = subprocess.Popen(cmd.decode(<span class="hljs-string">'utf-8'</span>), shell=<span class="hljs-literal">True</span>,stdout=subprocess.PIPE, stderr=subprocess.PIPE)<br> correct_msg = ret.stdout.read()<br> error_msg = ret.stderr.read()<br><br><span class="hljs-comment"># 1 制作固定报头</span><br> total_size = <span class="hljs-built_in">len</span>(correct_msg) + <span class="hljs-built_in">len</span>(error_msg)<br> header = struct.pack(<span class="hljs-string">'i'</span>, total_size)<br><br><span class="hljs-comment"># 2 发送报头</span><br>conn.send(header)<br><br> <span class="hljs-comment"># 发送真实数据:</span><br> conn.send(correct_msg)<br> conn.send(error_msg)<br> <span class="hljs-keyword">except</span> ConnectionResetError:<br> <span class="hljs-keyword">break</span><br> <br>conn.close()<br>phone.close()<br><br><span class="hljs-comment"># 但是low版本有问题:</span><br><span class="hljs-comment"># 1,报头不只有总数据大小,而是还应该有MD5数据,文件名等等一些数据。</span><br><span class="hljs-comment"># 2,通过struct模块直接数据处理,不能处理太大。</span><br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> struct<br><br>phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><br>phone.connect((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> cmd = <span class="hljs-built_in">input</span>(<span class="hljs-string">'>>>'</span>).strip()<br> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> cmd: <span class="hljs-keyword">continue</span><br> phone.send(cmd.encode(<span class="hljs-string">'utf-8'</span>))<br> <br><span class="hljs-comment"># 1,接收固定报头</span><br>header = phone.recv(<span class="hljs-number">4</span>)<br><br><span class="hljs-comment"># 2,解析报头</span><br>total_size = struct.unpack(<span class="hljs-string">'i'</span>, header)[<span class="hljs-number">0</span>]<br><br><span class="hljs-comment"># 3,根据报头信息,接收真实数据</span><br>recv_size = <span class="hljs-number">0</span><br>res = <span class="hljs-string">b''</span><br><br><span class="hljs-keyword">while</span> recv_size < total_size:<br>recv_data = phone.recv(<span class="hljs-number">1024</span>)<br>res += recv_data<br>recv_size += <span class="hljs-built_in">len</span>(recv_data)<br><br><span class="hljs-built_in">print</span>(res.decode(<span class="hljs-string">'gbk'</span>))<br><br>phone.close()<br></code></pre></td></tr></table></figure><p>方案二:可自定制报头</p><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs arduino">整个流程的大致解释:<br>我们可以把报头做成字典,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后json序列<br>化,然后用struck将序列化后的数据长度打包成<span class="hljs-number">4</span>个字节。<br>我们在网络上传输的所有数据 都叫做数据包,数据包里的所有数据都叫做报文,报文里面不止有你的数<br>据,还有ip地址、mac地址、端口号等等,其实所有的报文都有报头,这个报头是协议规定的,看一下<br><br>发送时:<br>先发报头长度<br>再编码报头内容然后发送<br>最后发真实内容<br><br>接收时:<br>先手报头长度,用<span class="hljs-keyword">struct</span>取出来<br>根据取出的长度收取报头内容,然后解码,反序列化<br>从反序列化的结果中取出待取数据的描述信息,然后去取真实的数据内容<br></code></pre></td></tr></table></figure><p>服务端</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> subprocess<br><span class="hljs-keyword">import</span> struct<br><span class="hljs-keyword">import</span> json<br><br>phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><br>phone.bind((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br><br>phone.listen(<span class="hljs-number">5</span>)<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> conn, client_addr = phone.accept()<br> <span class="hljs-built_in">print</span>(client_addr)<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br><span class="hljs-keyword">try</span>:<br>cmd = conn.recv(<span class="hljs-number">1024</span>)<br>ret = subprocess.Popen(cmd.decode(<span class="hljs-string">'utf-8'</span>), shell=<span class="hljs-literal">True</span>,stdout=subprocess.PIPE, stderr=subprocess.PIPE)<br>correct_msg = ret.stdout.read()<br>error_msg = ret.stderr.read()<br><br> <span class="hljs-comment"># 1 制作固定报头</span><br> total_size = <span class="hljs-built_in">len</span>(correct_msg) + <span class="hljs-built_in">len</span>(error_msg)<br><br>header_dict = {<br> <span class="hljs-string">'md5'</span>: <span class="hljs-string">'fdsaf2143254f'</span>,<br> <span class="hljs-string">'file_name'</span>: <span class="hljs-string">'f1.txt'</span>,<br> <span class="hljs-string">'total_size'</span>: total_size,<br>}<br><br> header_dict_json = json.dumps(header_dict) <span class="hljs-comment"># str</span><br> bytes_headers = header_dict_json.encode(<span class="hljs-string">'utf-8'</span>)<br><br>header_size = <span class="hljs-built_in">len</span>(bytes_headers)<br><br>header = struct.pack(<span class="hljs-string">'i'</span>, header_size)<br><br> <span class="hljs-comment"># 2 发送报头长度</span><br> conn.send(header)<br><br> <span class="hljs-comment"># 3 发送报头</span><br> conn.send(bytes_headers)<br><br> <span class="hljs-comment"># 4 发送真实数据:</span><br> conn.send(correct_msg)<br> conn.send(error_msg)<br><span class="hljs-keyword">except</span> ConnectionResetError:<br><span class="hljs-keyword">break</span><br><br>conn.close()<br>phone.close()<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> struct<br><span class="hljs-keyword">import</span> json<br><br>phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><br>phone.connect((<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-number">8080</span>))<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br> cmd = <span class="hljs-built_in">input</span>(<span class="hljs-string">'>>>'</span>).strip()<br> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> cmd: <span class="hljs-keyword">continue</span><br> phone.send(cmd.encode(<span class="hljs-string">'utf-8'</span>))<br> <br> <span class="hljs-comment"># 1,接收固定报头</span><br> header_size = struct.unpack(<span class="hljs-string">'i'</span>, phone.recv(<span class="hljs-number">4</span>))[<span class="hljs-number">0</span>]<br><br> <span class="hljs-comment"># 2,解析报头长度</span><br> header_bytes = phone.recv(header_size)<br> <br>header_dict = json.loads(header_bytes.decode(<span class="hljs-string">'utf-8'</span>))<br><br> <span class="hljs-comment"># 3,收取报头</span><br> total_size = header_dict[<span class="hljs-string">'total_size'</span>]<br> <br> <span class="hljs-comment"># 3,根据报头信息,接收真实数据</span><br> recv_size = <span class="hljs-number">0</span><br> res = <span class="hljs-string">b''</span><br><br><span class="hljs-keyword">while</span> recv_size < total_size:<br>recv_data = phone.recv(<span class="hljs-number">1024</span>)<br>res += recv_data<br>recv_size += <span class="hljs-built_in">len</span>(recv_data)<br><br><span class="hljs-built_in">print</span>(res.decode(<span class="hljs-string">'gbk'</span>))<br><br>phone.close()<br></code></pre></td></tr></table></figure><p>FTP上传下载文件的代码(简单版)</p><p>服务端</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> struct<br><span class="hljs-keyword">import</span> json<br>sk = socket.socket()<br><span class="hljs-comment"># buffer = 4096 # 当双方的这个接收发送的大小比较大的时候,就像这个4096,就会丢数据,这</span><br>个等我查一下再告诉大家,改小了就ok的,在linux上也是ok的。<br>buffer = <span class="hljs-number">1024</span> <span class="hljs-comment">#每次接收数据的大小</span><br>sk.bind((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8090</span>))<br>sk.listen()<br><br>conn,addr = sk.accept()<br><span class="hljs-comment">#接收</span><br>head_len = conn.recv(<span class="hljs-number">4</span>)<br>head_len = struct.unpack(<span class="hljs-string">'i'</span>,head_len)[<span class="hljs-number">0</span>] <span class="hljs-comment">#解包</span><br><br>json_head = conn.recv(head_len).decode(<span class="hljs-string">'utf-8'</span>) <span class="hljs-comment">#反序列化</span><br>head = json.loads(json_head)<br>filesize = head[<span class="hljs-string">'filesize'</span>]<br><br><span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(head[<span class="hljs-string">'filename'</span>],<span class="hljs-string">'wb'</span>) <span class="hljs-keyword">as</span> f:<br><span class="hljs-keyword">while</span> filesize:<br><span class="hljs-keyword">if</span> filesize >= buffer: <span class="hljs-comment">#>=是因为如果刚好等于的情况出现也是可以的。</span><br> content = conn.recv(buffer)<br>f.write(content)<br>filesize -= buffer<br><span class="hljs-keyword">else</span>:<br>content = conn.recv(buffer)<br>f.write(content)<br><span class="hljs-keyword">break</span><br><br>conn.close()<br>sk.close()<br></code></pre></td></tr></table></figure><p>客户端</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">import</span> os<br><span class="hljs-keyword">import</span> json<br><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> struct<br>sk = socket.socket()<br>sk.connect((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">8090</span>))<br>buffer = <span class="hljs-number">1024</span> <span class="hljs-comment">#读取文件的时候,每次读取的大小</span><br>head = {<br> <span class="hljs-string">'filepath'</span>:<span class="hljs-string">r'C:\Users\Aaron\Desktop\新建文件夹'</span>, <span class="hljs-comment">#需要下载的文件路径,也就是文件所在的文件夹</span><br> <span class="hljs-string">'filename'</span>:<span class="hljs-string">'config'</span>, <span class="hljs-comment">#改成上面filepath下的一个文件</span><br> <span class="hljs-string">'filesize'</span>:<span class="hljs-literal">None</span>,<br> }<br> <br>file_path = os.path.join(head[<span class="hljs-string">'filepath'</span>],head[<span class="hljs-string">'filename'</span>])<br>filesize = os.path.getsize(file_path)<br>head[<span class="hljs-string">'filesize'</span>] = filesize<br><br><span class="hljs-comment"># json_head = json.dumps(head,ensure_ascii=False) #字典转换成字符串</span><br>json_head = json.dumps(head) <span class="hljs-comment">#字典转换成字符串</span><br>bytes_head = json_head.encode(<span class="hljs-string">'utf-8'</span>) <span class="hljs-comment">#字符串转换成bytes类型</span><br><span class="hljs-built_in">print</span>(json_head)<br><span class="hljs-built_in">print</span>(bytes_head)<br><br><span class="hljs-comment">#计算head的长度,因为接收端先接收我们自己定制的报头,对吧</span><br>head_len = <span class="hljs-built_in">len</span>(bytes_head) <span class="hljs-comment">#报头长度</span><br>pack_len = struct.pack(<span class="hljs-string">'i'</span>,head_len)<br><span class="hljs-built_in">print</span>(head_len)<br><span class="hljs-built_in">print</span>(pack_len)<br>sk.send(pack_len) <span class="hljs-comment">#先发送报头长度</span><br>sk.send(bytes_head) <span class="hljs-comment">#再发送bytes类型的报头</span><br><br><span class="hljs-comment">#即便是视频文件,也是可以按行来读取的,也可以readline,也可以for循环,但是读取出来的数据</span><br>大小就不固定了,影响效率,有可能读的比较小,也可能很大,像视频文件一般都是一行的二进制字节<br>流。<br><span class="hljs-comment">#所有我们可以用read,设定一个一次读取内容的大小,一边读一边发,一边收一边写</span><br><span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(file_path,<span class="hljs-string">'rb'</span>) <span class="hljs-keyword">as</span> f:<br><span class="hljs-keyword">while</span> filesize:<br><span class="hljs-keyword">if</span> filesize >= buffer: <span class="hljs-comment">#>=是因为如果刚好等于的情况出现也是可以的。</span><br> content = f.read(buffer) <span class="hljs-comment">#每次读取出来的内容</span><br> sk.send(content)<br> filesize -= buffer <span class="hljs-comment">#每次减去读取的大小</span><br> <span class="hljs-keyword">else</span>: <span class="hljs-comment">#那么说明剩余的不够一次读取的大小了,那么只要把剩下的读取出来发送过去就行了</span><br>content = f.read(filesize)<br>sk.send(content)<br><span class="hljs-keyword">break</span><br>sk.close()<br></code></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1>套接字的工作流程(基于TCP和 UDP两个协议)</h1>
<h2 id="TCP和UDP对比">TCP和UDP对比</h2>
<ul class="lvl-0">
<li class="lvl-2">
<p>TCP(Transmission Control Protoc</summary>
<category term="Python" scheme="https://xiaolaji.site/categories/Python/"/>
<category term="Python学习" scheme="https://xiaolaji.site/tags/Python%E5%AD%A6%E4%B9%A0/"/>
</entry>
<entry>
<title>Python的反射与双下方法</title>
<link href="https://xiaolaji.site/20221001/Python%E7%9A%84%E5%8F%8D%E5%B0%84%E4%B8%8E%E5%8F%8C%E4%B8%8B%E6%96%B9%E6%B3%95/"/>
<id>https://xiaolaji.site/20221001/Python%E7%9A%84%E5%8F%8D%E5%B0%84%E4%B8%8E%E5%8F%8C%E4%B8%8B%E6%96%B9%E6%B3%95/</id>
<published>2022-10-01T04:34:00.000Z</published>
<updated>2023-05-27T11:51:00.000Z</updated>
<content type="html"><![CDATA[<h1>反射</h1><p>python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都 可以使用反射)</p><p>四个可以实现自省的函数</p><p>下列方法适用于类和对象(一切皆对象,类本身也是一个对象)</p><p><strong>对对象的反射</strong></p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>:<br> f = <span class="hljs-string">'类的静态变量'</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,age</span>):<br> self.name=name<br> self.age=age<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">say_hi</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'hi,%s'</span>%self.name)<br><br>obj=Foo(<span class="hljs-string">'KD'</span>,<span class="hljs-number">73</span>)<br><br><span class="hljs-comment"># 检测是否含有某属性</span><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">hasattr</span>(obj,<span class="hljs-string">'name'</span>))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">hasattr</span>(obj,<span class="hljs-string">'say_hi'</span>))<br><br><span class="hljs-comment"># 获取属性</span><br>n=<span class="hljs-built_in">getattr</span>(obj,<span class="hljs-string">'name'</span>)<br><span class="hljs-built_in">print</span>(n)<br>func=<span class="hljs-built_in">getattr</span>(obj,<span class="hljs-string">'say_hi'</span>)<br>func()<br><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">getattr</span>(obj,<span class="hljs-string">'aaaaaaaa'</span>,<span class="hljs-string">'不存在啊'</span>)) <span class="hljs-comment"># 报错</span><br><br><span class="hljs-comment"># 设置属性</span><br><span class="hljs-built_in">setattr</span>(obj,<span class="hljs-string">'sb'</span>,<span class="hljs-literal">True</span>)<br><span class="hljs-built_in">setattr</span>(obj,<span class="hljs-string">'show_name'</span>,<span class="hljs-keyword">lambda</span> self:self.name+<span class="hljs-string">'sb'</span>)<br><span class="hljs-built_in">print</span>(obj.__dict__)<br><span class="hljs-built_in">print</span>(obj.show_name(obj))<br><br><span class="hljs-comment"># 删除属性</span><br><span class="hljs-built_in">delattr</span>(obj,<span class="hljs-string">'age'</span>)<br><span class="hljs-built_in">delattr</span>(obj,<span class="hljs-string">'show_name'</span>)<br><span class="hljs-comment"># delattr(obj,'show_name111') # 不存在,则报错</span><br><br><span class="hljs-built_in">print</span>(obj.__dict__)<br></code></pre></td></tr></table></figure><p><strong>对类的反射</strong></p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>(<span class="hljs-title class_ inherited__">object</span>):<br>staticField = <span class="hljs-string">"test"</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br>self.name = <span class="hljs-string">'陈松'</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">return</span> <span class="hljs-string">'func'</span><br><br><span class="hljs-meta">@staticmethod</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">bar</span>():<br><span class="hljs-keyword">return</span> <span class="hljs-string">'bar'</span><br><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">getattr</span>(Foo, <span class="hljs-string">'staticField'</span>))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">getattr</span>(Foo, <span class="hljs-string">'func'</span>))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">getattr</span>(Foo, <span class="hljs-string">'bar'</span>))<br></code></pre></td></tr></table></figure><p>当前模块的反射</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">import</span> sys<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">s1</span>():<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'s1'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">s2</span>():<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'s2'</span>)<br><br>this_module = sys.modules[__name__]<br><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">hasattr</span>(this_module, <span class="hljs-string">'s1'</span>))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">getattr</span>(this_module, <span class="hljs-string">'s2'</span>))<br></code></pre></td></tr></table></figure><p>其他模块的反射</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs py">程序目录:<br> module_test.py<br> test.py<br> <br>当前文件:<br>test.py<br></code></pre></td></tr></table></figure><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs py"><span class="hljs-keyword">import</span> module_test <span class="hljs-keyword">as</span> obj<br><br>obj.test()<br><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">hasattr</span>(obj,<span class="hljs-string">'test'</span>))<br><br><span class="hljs-built_in">getattr</span>(obj,<span class="hljs-string">'test'</span>)()<br></code></pre></td></tr></table></figure><p>举例:</p><p>使用反射前</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">login</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'欢迎来到登录页面'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">register</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'欢迎来到注册页面'</span>)<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">save</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'欢迎来到存储页面'</span>)<br><br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br>choose = <span class="hljs-built_in">input</span>(<span class="hljs-string">'>>>'</span>).strip()<br><span class="hljs-keyword">if</span> choose == <span class="hljs-string">'login'</span>:<br> obj = User()<br> obj.login()<br><br> <span class="hljs-keyword">elif</span> choose == <span class="hljs-string">'register'</span>:<br> obj = User()<br> obj.register()<br> <br><span class="hljs-keyword">elif</span> choose == <span class="hljs-string">'save'</span>:<br> obj = User()<br> obj.save()<br></code></pre></td></tr></table></figure><p>用了反射之后</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">login</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'欢迎来到登录页面'</span>)<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">register</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'欢迎来到注册页面'</span>)<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">save</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'欢迎来到存储页面'</span>)<br><br>user = User()<br><span class="hljs-keyword">while</span> <span class="hljs-number">1</span>:<br>choose = <span class="hljs-built_in">input</span>(<span class="hljs-string">'>>>'</span>).strip()<br><span class="hljs-keyword">if</span> <span class="hljs-built_in">hasattr</span>(user, choose):<br>func = <span class="hljs-built_in">getattr</span>(user, choose)<br>func()<br><span class="hljs-keyword">else</span>:<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'输入错误。。。。'</span>)<br></code></pre></td></tr></table></figure><h1>函数 vs 方法</h1><h2 id="通过打印函数-方法-名确定">通过打印函数(方法)名确定</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>():<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-built_in">print</span>(func)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-built_in">print</span>(A.func)<br>obj = A()<br><span class="hljs-built_in">print</span>(obj.func)<br></code></pre></td></tr></table></figure><h2 id="通过types模块验证">通过types模块验证</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> types <span class="hljs-keyword">import</span> FunctionType<br><span class="hljs-keyword">from</span> types <span class="hljs-keyword">import</span> MethodType<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>():<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><br>obj = A()<br><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(func,FunctionType))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(A.func,FunctionType))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(obj.func,FunctionType))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(obj.func,MethodType))<br></code></pre></td></tr></table></figure><h2 id="静态方法是函数">静态方法是函数</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> types <span class="hljs-keyword">import</span> FunctionType<br><span class="hljs-keyword">from</span> types <span class="hljs-keyword">import</span> MethodType<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-meta">@classmethod</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func1</span>(<span class="hljs-params">cls</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-meta">@staticmethod</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><br>obj = A()<br><br><span class="hljs-comment">#类方法是方法</span><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(A.func1,FunctionType))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(obj.func1,FunctionType))<br><span class="hljs-comment"># 静态方法其实是函数</span><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(A.func2,FunctionType))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(obj.func2,FunctionType))<br></code></pre></td></tr></table></figure><h2 id="函数与方法的区别">函数与方法的区别</h2><p>那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。</p><ol><li class="lvl-3"><p>函数的是显式传递数据的。如我们要指明为 len() 函数传递一些要处理数据。</p></li><li class="lvl-3"><p>函数则跟对象无关。</p></li><li class="lvl-3"><p>方法中的数据则是隐式传递的。</p></li><li class="lvl-3"><p>方法可以操作类内部的数据。</p></li><li class="lvl-4"><p>方法跟对象是关联的。如我们在用strip()方法是,是不是都是要通过str对象调用,比如我们有字符串s,然后<code>s.strip()</code>这样调用。是的,strip()方法属于str对象。</p></li></ol><p>我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。</p><p>在其他语言中,如Java中只有方法,C中只有函数,C++么,则取决于是否在类中</p><h1>双下方法</h1><h2 id="len"><code>__len__</code></h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__len__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">return</span> <span class="hljs-number">666</span><br><br>b = B()<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">len</span>(b)) <span class="hljs-comment"># len 一个对象就会触发 __len__方法。</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br>self.a = <span class="hljs-number">1</span><br>self.b = <span class="hljs-number">2</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__len__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">return</span> <span class="hljs-built_in">len</span>(self.__dict__)<br>a = A()<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">len</span>(a))<br></code></pre></td></tr></table></figure><h2 id="hash"><code>__hash__</code></h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br> self.a = <span class="hljs-number">1</span><br> self.b = <span class="hljs-number">2</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__hash__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">return</span> <span class="hljs-built_in">hash</span>(<span class="hljs-built_in">str</span>(self.a)+<span class="hljs-built_in">str</span>(self.b))<br>a = A()<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">hash</span>(a))<br></code></pre></td></tr></table></figure><h2 id="str"><code>__str__</code></h2><p>如果一个类中定义了 <code>__str__</code> 方法,那么在打印 对象 时,默认输出该方法的返回值。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__str__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">return</span> <span class="hljs-string">'陈松'</span><br>a = A()<br><span class="hljs-built_in">print</span>(a)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s'</span> % a)<br></code></pre></td></tr></table></figure><h2 id="repr"><code>__repr__</code></h2><p>如果一个类中定义了 <code>__repr__</code> 方法,那么在repr(对象) 时,默认输出该方法的返回值。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__repr__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">return</span> <span class="hljs-string">'陈松'</span><br>a = A()<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">repr</span>(a))<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%r'</span>%a)<br></code></pre></td></tr></table></figure><h2 id="call"><code>__call__</code></h2><p>对象后面加括号,触发执行。</p><p>注:构造方法new的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后 加括号触发的,即:对象() 或者 类()()</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'__init__'</span>)<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, *args, **kwargs</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'__call__'</span>)<br><br>obj = Foo() <span class="hljs-comment"># 执行 __init__</span><br>obj() <span class="hljs-comment"># 执行 __call__</span><br></code></pre></td></tr></table></figure><h2 id="eq"><code>__eq__</code></h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br> self.a = <span class="hljs-number">1</span><br> self.b = <span class="hljs-number">2</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__eq__</span>(<span class="hljs-params">self,obj</span>):<br><span class="hljs-keyword">if</span> self.a == obj.a <span class="hljs-keyword">and</span> self.b == obj.b:<br><span class="hljs-keyword">return</span> <span class="hljs-literal">True</span><br>a = A()<br>b = A()<br><span class="hljs-built_in">print</span>(a == b)<br></code></pre></td></tr></table></figure><h2 id="del"><code>__del__</code></h2><p>析构方法,当对象在内存中被释放时,自动触发执行。</p><p>注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放, 因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触 发执行的。</p><h2 id="new"><code>__new__</code></h2><ol><li class="lvl-3"><p><code>__new__()</code> 方法是在类准备将自身实例化时调用。</p></li><li class="lvl-3"><p><code>__new__()</code> 方法始终都是类的静态方法,即使没有被加上静态方法装饰器</p></li><li class="lvl-3"><p>通常来说,新式类开始实例化时, <code>__new__()</code> 方法会返回cls(cls指代当前类)的实例,然后该类 的 <code>__init__()</code> 方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传 入 <code>__new__()</code> 方法中接收的位置参数和命名参数。</p></li></ol><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br> self.x = <span class="hljs-number">1</span><br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'in init function'</span>)<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__new__</span>(<span class="hljs-params">cls, *args, **kwargs</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'in new function'</span>)<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">object</span>.__new__(A, *args, **kwargs)<br> <br>a = A()<br><span class="hljs-built_in">print</span>(a.x)<br></code></pre></td></tr></table></figure><p>单例模式</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br>__instance = <span class="hljs-literal">None</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__new__</span>(<span class="hljs-params">cls, *args, **kwargs</span>):<br><span class="hljs-keyword">if</span> cls.__instance <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:<br>obj = <span class="hljs-built_in">object</span>.__new__(cls)<br>cls.__instance = obj<br><span class="hljs-keyword">return</span> cls.__instance<br><br>a=A()<br>b=A()<br><span class="hljs-built_in">print</span>(a==b)<br></code></pre></td></tr></table></figure><p>单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。</p><p><strong>【采用单例模式动机、原因】</strong></p><p>对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。 如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。</p><p><strong>【单例模式优缺点】</strong></p><p><strong>【优点】</strong></p><p>一、实例控制</p><p>单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。</p><p>二、灵活性</p><p>因为类控制了实例化过程,所以类可以灵活更改实例化过程。</p><p><strong>【缺点】</strong></p><p>一、开销</p><p>虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。</p><p>二、可能的开发混淆</p><p>使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对 象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。</p><p>三、对象生存期</p><p>不能解决删除单个对象的问题。在提供内存管理的语言中(<a href="http://xn--6kqwxn6r1rb.NET">例如基于.NET</a> Framework的语言),只有 单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类 可以删除对象实例,但这样会导致单例类中出现悬浮引用</p><h2 id="item-系列"><code>__item__</code>系列</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, name</span>):<br>self.name = name<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__getitem__</span>(<span class="hljs-params">self, item</span>):<br><span class="hljs-built_in">print</span>(self.__dict__[item])<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__setitem__</span>(<span class="hljs-params">self, key, value</span>):<br>self.__dict__[key] = value<br><span class="hljs-built_in">print</span>(<span class="hljs-string">f'<span class="hljs-subst">{key}</span>赋值<span class="hljs-subst">{value}</span>成功'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__delitem__</span>(<span class="hljs-params">self, key</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'del obj[key]时,我执行'</span>)<br>self.__dict__.pop(key)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__delattr__</span>(<span class="hljs-params">self, item</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'del obj.key时,我执行'</span>)<br>self.__dict__.pop(item)<br> <span class="hljs-comment"># def __setattr__(self, key, value):</span><br><span class="hljs-comment"># print(f'当设置{key}={value}对象的时候执行')</span><br><span class="hljs-comment"># def __getattr__(self, item):</span><br><span class="hljs-comment"># print("当获取变量的时候执行我")</span><br>f1 = Foo(<span class="hljs-string">'sb'</span>)<br>f1.age=<span class="hljs-number">19</span><br>f1[<span class="hljs-string">'age'</span>] = <span class="hljs-number">18</span><br>f1[<span class="hljs-string">'age1'</span>] = <span class="hljs-number">19</span><br><span class="hljs-keyword">del</span> f1.age1<br><span class="hljs-keyword">del</span> f1[<span class="hljs-string">'age'</span>]<br>f1[<span class="hljs-string">'name'</span>] = <span class="hljs-string">'mingzi'</span><br><span class="hljs-built_in">print</span>(f1.__dict__)<br></code></pre></td></tr></table></figure><h2 id="上下文管理器相关">上下文管理器相关</h2><p><code>__enter__</code> <code>__exit__</code></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, text</span>):<br>self.text = text<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__enter__</span>(<span class="hljs-params">self</span>): <span class="hljs-comment"># 开启上下文管理器对象时触发此方法</span><br>self.text = self.text + <span class="hljs-string">'您来啦'</span><br><span class="hljs-keyword">return</span> self <span class="hljs-comment"># 将实例化的对象返回f1</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__exit__</span>(<span class="hljs-params">self, exc_type, exc_val, exc_tb</span>): <span class="hljs-comment"># 执行完上下文管理器对象f1时触发此方法</span><br>self.text = self.text + <span class="hljs-string">'这就走啦'</span><br><br><span class="hljs-keyword">with</span> A(<span class="hljs-string">'大爷'</span>) <span class="hljs-keyword">as</span> f1:<br><span class="hljs-built_in">print</span>(f1.text)<br><span class="hljs-built_in">print</span>(f1.text)<br></code></pre></td></tr></table></figure><p>自定义文件管理器</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Diycontextor</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, name, mode</span>):<br> self.name = name<br> self.mode = mode<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__enter__</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"Hi enter here!!"</span>)<br> self.filehander = <span class="hljs-built_in">open</span>(self.name, self.mode)<br> <span class="hljs-keyword">return</span> self.filehander<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__exit__</span>(<span class="hljs-params">self,*args</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"Hi exit here"</span>)<br> self.filehander.close()<br><br><span class="hljs-keyword">with</span> Diycontextor(<span class="hljs-string">'config'</span>, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> f:<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> f:<br><span class="hljs-built_in">print</span>(i.strip())<br></code></pre></td></tr></table></figure><p>案例</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">StarkConfig</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, num</span>):<br>self.num = num<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">run</span>(<span class="hljs-params">self</span>):<br>self()<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, *args, **kwargs</span>):<br><span class="hljs-built_in">print</span>(self.num)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">RoleConfig</span>(<span class="hljs-title class_ inherited__">StarkConfig</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, *args, **kwargs</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-number">345</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__getitem__</span>(<span class="hljs-params">self, item</span>):<br><span class="hljs-keyword">return</span> self.num[item]<br><br>v1 = RoleConfig(<span class="hljs-string">'abcedf'</span>)<br>v2 = StarkConfig(<span class="hljs-string">'2333'</span>)<br><span class="hljs-built_in">print</span>(v1[<span class="hljs-number">3</span>])<br><span class="hljs-comment"># print(v2[2])</span><br>v1.run()<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">UserInfo</span>:<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Department</span>:<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">StarkConfig</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, num</span>):<br>self.num = num<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">changelist</span>(<span class="hljs-params">self, request</span>):<br><span class="hljs-built_in">print</span>(self.num, request)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">run</span>(<span class="hljs-params">self</span>):<br>self.changelist(<span class="hljs-number">999</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">RoleConfig</span>(<span class="hljs-title class_ inherited__">StarkConfig</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">changelist</span>(<span class="hljs-params">self, request</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-number">666</span>, self.num)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">AdminSite</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br>self._registry = {}<br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">register</span>(<span class="hljs-params">self, k, v</span>):<br>self._registry[k] = v<br> <br>site = AdminSite()<br>site.register(UserInfo, StarkConfig)<br><span class="hljs-comment"># 1</span><br>obj = site._registry[UserInfo]()<br><br><span class="hljs-comment"># 2</span><br><span class="hljs-comment"># obj = site._registry[UserInfo](100)</span><br>obj.run()<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">UserInfo</span>:<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Department</span>:<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">StarkConfig</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,num</span>):<br>self.num = num<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">changelist</span>(<span class="hljs-params">self,request</span>):<br><span class="hljs-built_in">print</span>(self.num,request)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">run</span>(<span class="hljs-params">self</span>):<br>self.changelist(<span class="hljs-number">999</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">RoleConfig</span>(<span class="hljs-title class_ inherited__">StarkConfig</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">changelist</span>(<span class="hljs-params">self,request</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-number">666</span>,self.num)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">AdminSite</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br>self._registry = {}<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">register</span>(<span class="hljs-params">self,k,v</span>):<br>self._registry[k] = v(k)<br><br>site = AdminSite()<br>site.register(UserInfo,StarkConfig)<br>site.register(Department,RoleConfig)<br><br><span class="hljs-keyword">for</span> k,row <span class="hljs-keyword">in</span> site._registry.items():<br>row.run()<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br>list_display = []<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">get_list</span>(<span class="hljs-params">self</span>):<br>self.list_display.insert(<span class="hljs-number">0</span>, <span class="hljs-number">33</span>)<br><span class="hljs-keyword">return</span> self.list_display<br><br>s1 = A()<br><span class="hljs-built_in">print</span>(s1.get_list())<br><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br>list_display = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br>self.list_display = []<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">get_list</span>(<span class="hljs-params">self</span>):<br> self.list_display.insert(<span class="hljs-number">0</span>, <span class="hljs-number">33</span>)<br> <span class="hljs-keyword">return</span> self.list_display<br> <br>s1 = A()<br><span class="hljs-built_in">print</span>(s1.get_list())<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br>list_display = []<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">get_list</span>(<span class="hljs-params">self</span>):<br>self.list_display.insert(<span class="hljs-number">0</span>,<span class="hljs-number">33</span>)<br><span class="hljs-keyword">return</span> self.list_display<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>(<span class="hljs-title class_ inherited__">A</span>):<br>list_display = [<span class="hljs-number">11</span>,<span class="hljs-number">22</span>]<br><br>s1 = A()<br>s2 = B()<br><span class="hljs-built_in">print</span>(s1.get_list())<br><span class="hljs-built_in">print</span>(s2.get_list())<br></code></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1>反射</h1>
<p>python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都 可以使用反射)</p>
<p>四个可以实现自省的函数</p>
<p>下列方法适用于类和对象(一切皆对象,类本身也是一个对象)</p>
<p><st</summary>
<category term="Python" scheme="https://xiaolaji.site/categories/Python/"/>
<category term="Python学习" scheme="https://xiaolaji.site/tags/Python%E5%AD%A6%E4%B9%A0/"/>
</entry>
<entry>
<title>Python中类的成员</title>
<link href="https://xiaolaji.site/20221001/Python%E4%B8%AD%E7%B1%BB%E7%9A%84%E6%88%90%E5%91%98/"/>
<id>https://xiaolaji.site/20221001/Python%E4%B8%AD%E7%B1%BB%E7%9A%84%E6%88%90%E5%91%98/</id>
<published>2022-10-01T04:33:00.000Z</published>
<updated>2023-05-27T12:06:50.000Z</updated>
<content type="html"><![CDATA[<h1>细分类的组成成员</h1><p>之前咱们讲过类大致分两块区域</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br>name = <span class="hljs-string">'KD'</span><br><br><span class="hljs-comment"># 第一部分:静态字段(静态变量)部分(这一部分调用了类自己本身,表示了类自己的自身属性)</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-comment"># 第二部分:方法部分(这一部分表示了类可以实施的方法,可以 自己或其他进行操作)</span><br></code></pre></td></tr></table></figure><p>每个区域详细划分</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<span class="hljs-comment">#在方法名前面带__的属于私有 </span><br><br> company_name = <span class="hljs-string">'KD'</span> <span class="hljs-comment"># 静态变量(静态字段)</span><br> __iphone = <span class="hljs-string">'132333xxxx'</span> <span class="hljs-comment"># 私有静态变量(私有静态字段)</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,age</span>): <span class="hljs-comment">#特殊方法(在类的定有里,有部分的固定的字段方法)</span><br> self.name = name <span class="hljs-comment">#对象属性(普通字段)</span><br> self.__age = age <span class="hljs-comment"># 私有对象属性(私有普通字段)</span><br><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">func1</span>(<span class="hljs-params">self</span>): <span class="hljs-comment"># 普通方法</span><br> <span class="hljs-keyword">pass</span><br><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__func</span>(<span class="hljs-params">self</span>): <span class="hljs-comment">#私有方法</span><br> <br> <br> <span class="hljs-built_in">print</span>(<span class="hljs-number">666</span>)<br><br><span class="hljs-meta"> @classmethod </span><span class="hljs-comment"># 类方法</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">class_func</span>(<span class="hljs-params">cls</span>):<br> <span class="hljs-string">""" 定义类方法,至少有一个cls参数 """</span><br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'类方法'</span>)<br><br><span class="hljs-meta">@staticmethod </span><span class="hljs-comment">#静态方法</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">static_func</span>():<br><span class="hljs-string">""" 定义静态方法 ,无默认参数"""</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">'静态方法'</span>)<br><span class="hljs-meta"> @property </span><span class="hljs-comment"># 属性</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">prop</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-keyword">pass</span><br></code></pre></td></tr></table></figure><p>类的私有成员</p><p>对于每一个类的成员而言都有两种形式:</p><ul class="lvl-0"><li class="lvl-2"><p>公有成员,在任何地方都能访问</p></li><li class="lvl-2"><p>私有成员,只有在类的内部才能方法</p></li></ul><p><strong>私有成员和公有成员的访问限制不同</strong>:</p><p>静态字段(静态属性</p><ul class="lvl-0"><li class="lvl-2"><p>公有静态字段:类可以访问;类内部可以访问;派生类中可以访问</p></li><li class="lvl-2"><p>私有静态字段:仅类内部可以访问;</p></li></ul><p>公有静态字段访问范围示例</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span>:<br><br>name = <span class="hljs-string">"公有静态字段"</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span> (C.name)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span>(<span class="hljs-title class_ inherited__">C</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">show</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span> (C.name)<br><br><span class="hljs-built_in">print</span>(C.name) <span class="hljs-comment"># 类访问</span><br><br>obj = C()<br>obj.func() <span class="hljs-comment"># 类内部可以访问</span><br><br>obj_son = D()<br>obj_son.show() <span class="hljs-comment"># 派生类中可以访问</span><br></code></pre></td></tr></table></figure><p>私有静态字段访问示例</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span>:<br>__name = <span class="hljs-string">"私有静态字段"</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span> (C.__name)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span>(<span class="hljs-title class_ inherited__">C</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">show</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span> (C.__name)<br><br><span class="hljs-built_in">print</span>(C.__name) <span class="hljs-comment"># 不可在外部访问</span><br><br>obj = C()<br><span class="hljs-built_in">print</span>(C.__name) <span class="hljs-comment"># 不可在外部访问</span><br>obj.func() <span class="hljs-comment"># 类内部可以访问</span><br><br>obj_son = D()<br>obj_son.show() <span class="hljs-comment">#不可在派生类中可以访问</span><br></code></pre></td></tr></table></figure><p>普通字段(对象属性)</p><p>公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问</p><p>私有普通字段:仅类内部可以访问;</p><p>公有普通字段示例</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br>self.foo = <span class="hljs-string">"公有字段"</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.foo) <span class="hljs-comment"># 类内部访问</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span>(<span class="hljs-title class_ inherited__">C</span>):<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">show</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.foo) <span class="hljs-comment"># 派生类中访问</span><br><br>obj = C()<br><br>obj.foo <span class="hljs-comment"># 通过对象访问</span><br>obj.func() <span class="hljs-comment"># 类内部访问</span><br><br>obj_son = D();<br>obj_son.show() <span class="hljs-comment"># 派生类中访问</span><br></code></pre></td></tr></table></figure><p>私有普通字段示例</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br>self.__foo = <span class="hljs-string">"私有字段"</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span> self.foo <span class="hljs-comment"># 类内部访问</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span>(<span class="hljs-title class_ inherited__">C</span>):<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">show</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span> self.foo # 派生类中访问<br><br>obj = C()<br><br>obj.__foo <span class="hljs-comment"># 通过对象访问 ==> 错误</span><br>obj.func() <span class="hljs-comment"># 类内部访问 ==> 正确</span><br><br>obj_son = D();<br>obj_son.show() <span class="hljs-comment"># 派生类中访问 ==> 错误</span><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br>self.__foo = <span class="hljs-string">"私有字段"</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.__foo) <span class="hljs-comment"># 类内部访问</span><br> <br><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span>(<span class="hljs-title class_ inherited__">C</span>):<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">show</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.__foo) <span class="hljs-comment"># 派生类中访问</span><br><br>obj = C()<br><br><span class="hljs-built_in">print</span>(obj.__foo) <span class="hljs-comment"># 通过对象访问 ==> 错误</span><br>obj.func() <span class="hljs-comment"># 类内部访问 ==> 正确</span><br><br>obj_son = D()<br>obj_son.show() <span class="hljs-comment"># 派生类中访问 ==> 错误 </span><br></code></pre></td></tr></table></figure><p>方法:</p><ul class="lvl-0"><li class="lvl-2"><p>公有方法:对象可以访问;类内部可以访问;派生类中可以访问</p></li><li class="lvl-2"><p>私有方法:仅类内部可以访问;</p></li></ul><p>共有方法示例</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">add</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in C'</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span>(<span class="hljs-title class_ inherited__">C</span>):<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">show</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in D'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br>self.show()<br><br>obj = D()<br>obj.show() <span class="hljs-comment"># 通过对象访问</span><br>obj.func() <span class="hljs-comment"># 类内部访问</span><br>obj.add() <span class="hljs-comment"># 派生类中访问</span><br></code></pre></td></tr></table></figure><p>私有方法示例</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__add</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in C'</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span>(<span class="hljs-title class_ inherited__">C</span>):<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__show</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in D'</span>)<br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):<br>self.__show()<br><br>obj = D()<br>obj.__show() <span class="hljs-comment"># 通过不能对象访问</span><br>obj.func() <span class="hljs-comment"># 类内部可以访问</span><br>obj.__add() <span class="hljs-comment"># 派生类中不能访问</span><br></code></pre></td></tr></table></figure><p>总结</p><p>对于这些私有成员来说,他们只能在类的内部使用,不能再类的外部以及派生类中使用.</p><p><strong>ps:非要访问私有成员的话,可以通过 对象._类__属性名,但是绝对不允许!!!</strong></p><p>为什么可以通过.类__私有成员名访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普 通字段,私有方法)它会将其保存在内存时自动在前面加上类名.</p><h1>类的其他成员</h1><p>这里的其他成员主要就是类方法:</p><p>方法包括:普通方法、静态方法和类方法,三种方法在<strong>内存中都归属于类</strong>,区别在于调用方式不同。</p><p><strong>实例方法</strong></p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs crystal">定义:第一个参数必须是实例对象,该参数名一般约定为“<span class="hljs-keyword">self</span>”,通过它来传递实例的属性和方法(也可以传类的属性和方法);<br><br>调用:只能由实例对象调用。<br></code></pre></td></tr></table></figure><p>类方法</p><figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs aspectj">定义:使用装饰器<span class="hljs-meta">@classmethod</span>。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);<br><br>调用:实例对象和类对象都可以调用。<br></code></pre></td></tr></table></figure><p>静态方法</p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs crystal">定义:使用装饰器<span class="hljs-variable">@staticmethod</span>。参数随意,没有“<span class="hljs-keyword">self</span>”和“cls”参数,但是方法体中不能使用类或<br>实例的任何属性和方法;<br><br>调用:实例对象和类对象都可以调用。<br></code></pre></td></tr></table></figure><p>双下方法(后面会讲到)</p><p>定义:双下方法是特殊方法,他是解释器提供的 由双下划线加方法名加双下划线 方法名的具有特殊意 义的方法,双下方法主要是python源码程序员使用的,我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。 调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方 法,例如:<code>init</code></p><h2 id="类方法">类方法</h2><p>使用装饰器@<code>classmethod</code>。</p><p>原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法,且这个方法在逻辑上采用类本身 作为对象来调用更合理,那么这个方法就可以定义为类方法。另外,如果需要继承,也可以定义为类方 法。</p><p>如下场景:</p><p>假设我有一个学生类和一个班级类,想要实现的功能为:</p><p>执行班级人数增加的操作、获得班级的总人数;</p><p>学生类继承自班级类,每实例化一个学生,班级人数都能增加;</p><p>最后,我想定义一些学生,获得班级中的总人数。</p><p>**思考:**这个问题用类方法做比较合适,为什么?因为我实例化的是学生,但是如果我从学生这一个实例 中获得班级总人数,在逻辑上显然是不合理的。同时,如果想要获得班级总人数,如果生成一个班级的 实例也是没有必要的。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span>:<br>__num = <span class="hljs-number">0</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, name, age</span>):<br>self.name = name<br>self.age = age<br>Student.addNum() <span class="hljs-comment"># 写在__new__方法中比较合适,但是现在还没有学,暂且放到这里</span><br><br><span class="hljs-meta">@classmethod</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">addNum</span>(<span class="hljs-params">cls</span>):<br>cls.__num += <span class="hljs-number">1</span><br><br><span class="hljs-meta">@classmethod</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">getNum</span>(<span class="hljs-params">cls</span>):<br><span class="hljs-keyword">return</span> cls.__num<br><br>Student(<span class="hljs-string">'KD'</span>, <span class="hljs-number">18</span>)<br>Student(<span class="hljs-string">'KK'</span>, <span class="hljs-number">36</span>)<br>Student(<span class="hljs-string">'DD'</span>, <span class="hljs-number">73</span>)<br><span class="hljs-built_in">print</span>(Student.getNum())<br></code></pre></td></tr></table></figure><h2 id="静态方法">静态方法</h2><p>使用装饰器<code>@staticmethod</code>。</p><p>静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和 类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方 法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护。</p><p>譬如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> time<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">TimeTest</span>(<span class="hljs-title class_ inherited__">object</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, hour, minute, second</span>):<br>self.hour = hour<br>self.minute = minute<br>self.second = second<br><br><span class="hljs-meta">@staticmethod</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">showTime</span>():<br><span class="hljs-keyword">return</span> time.strftime(<span class="hljs-string">"%H:%M:%S"</span>, time.localtime())<br><br><span class="hljs-built_in">print</span>(TimeTest.showTime())<br>t = TimeTest(<span class="hljs-number">2</span>, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>)<br>nowTime = t.showTime()<br><span class="hljs-built_in">print</span>(nowTime)<br></code></pre></td></tr></table></figure><h2 id="方法综合案例">方法综合案例</h2><p>需求</p><ol><li class="lvl-3"><p>设计一个 Game 类</p></li><li class="lvl-3"><p>属性:</p><p>定义一个 <strong>类属性</strong> top_score 记录游戏的 历史最高分</p><p>定义一个 <strong>实例属性</strong> player_name 记录 当前游戏的玩家姓名</p></li><li class="lvl-3"><p>方法:</p><p>静态方法 show_help 显示游戏帮助信息</p><p>类方法 show_top_score 显示历史最高分</p><p>实例方法 start_game 开始当前玩家的游戏</p></li><li class="lvl-3"><p>主程序步骤</p><p>1.查看帮助信息</p><p>2.查看历史最高分</p><p>3.创建游戏对象,开始游戏</p></li></ol><p><img src="image-20220711121734992.png" alt="示意图"></p><h3 id="案例小结">案例小结</h3><ol><li class="lvl-3"><p>实例方法—— 方法内部需要访问实例属性</p><pre><code class="hljs"> 实例方法 内部可以使用 类名. 访问类属性</code></pre></li><li class="lvl-3"><p>类方法 —— 方法内部 只 需要访问 类属性</p></li><li class="lvl-3"><p>静态方法 —— 方法内部,不需要访问 实例属性 和 类属性</p></li></ol><p><strong>提问</strong></p><p>应该定义 <strong>实例方法</strong></p><p>因为,<strong>类只有一个</strong>,在 <strong>实例方法</strong> 内部可以使用 <strong>类名</strong>. 访问类属性</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Game</span>(<span class="hljs-title class_ inherited__">object</span>):<br><br><span class="hljs-comment"># 游戏最高分,类属性</span><br>top_score = <span class="hljs-number">0</span><br><br><span class="hljs-meta">@staticmethod</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">show_help</span>():<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"帮助信息:让僵尸走进房间"</span>)<br><br><span class="hljs-meta">@classmethod</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">show_top_score</span>(<span class="hljs-params">cls</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"游戏最高分是 %d"</span> % cls.top_score)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, player_name</span>):<br>self.player_name = player_name<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">start_game</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"[%s] 开始游戏..."</span> % self.player_name)<br><br> <span class="hljs-comment"># 使用类名.修改历史最高分</span><br> Game.top_score = <span class="hljs-number">999</span><br><br><span class="hljs-comment"># 1. 查看游戏帮助</span><br>Game.show_help()<br><br><span class="hljs-comment"># 2. 查看游戏最高分</span><br>Game.show_top_score()<br><br><span class="hljs-comment"># 3. 创建游戏对象,开始游戏</span><br>game = Game(<span class="hljs-string">"小明"</span>)<br><br>game.start_game()<br><br><span class="hljs-comment"># 4. 游戏结束,查看游戏最高分</span><br>Game.show_top_score()<br></code></pre></td></tr></table></figure><h2 id="属性">属性</h2><p>property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值</p><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs mipsasm">例一:<span class="hljs-keyword">BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个</span><br><span class="hljs-keyword"></span>属性,更便于理解)<br><br>成人的<span class="hljs-keyword">BMI数值:</span><br><span class="hljs-keyword"></span>过轻:低于<span class="hljs-number">18</span>.<span class="hljs-number">5</span><br>正常:<span class="hljs-number">18</span>.<span class="hljs-number">5</span><span class="hljs-number">-23</span>.<span class="hljs-number">9</span><br>过重:<span class="hljs-number">24</span><span class="hljs-number">-27</span><br>肥胖:<span class="hljs-number">28</span><span class="hljs-number">-32</span><br>非常肥胖, 高于<span class="hljs-number">32</span><br> 体质指数(<span class="hljs-keyword">BMI)=体重(kg)÷身高^2(m)</span><br><span class="hljs-keyword"></span> EX:<span class="hljs-number">70</span>kg÷(<span class="hljs-number">1</span>.<span class="hljs-number">75</span>×<span class="hljs-number">1</span>.<span class="hljs-number">75</span>)=<span class="hljs-number">22</span>.<span class="hljs-number">86</span><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">People</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,weight,height</span>):<br> self.name=name<br> self.weight=weight<br> self.height=height<br><span class="hljs-meta">@property</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">bmi</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">return</span> self.weight / (self.height**<span class="hljs-number">2</span>)<br><br>p1=People(<span class="hljs-string">'陈松'</span>,<span class="hljs-number">75</span>,<span class="hljs-number">1.85</span>)<br><span class="hljs-built_in">print</span>(p1.bmi)<br></code></pre></td></tr></table></figure><p>将一个类的函数定义成特性以后,<a href="http://xn--obj-hb0eo1az7dv0fiuvvgvox8aned324g.name">对象再去使用的时候obj.name</a>,根本无法察觉自己的name是执行了一 个函数然后计算出来的,这种特性的使用方式遵循了<strong>统一访问的原则</strong></p><p>由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同 一个属性:获取、修改、删除</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>:<br><span class="hljs-meta">@property</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">AAA</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'get的时候运行我啊'</span>)<br><br><span class="hljs-meta"> @AAA.setter</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">AAA</span>(<span class="hljs-params">self,value</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'set的时候运行我啊'</span>)<br><br><span class="hljs-meta"> @AAA.deleter</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">AAA</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'delete的时候运行我啊'</span>)<br> <br><span class="hljs-comment">#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter</span><br>f1=Foo()<br>f1.AAA<br>f1.AAA=<span class="hljs-string">'aaa'</span><br><span class="hljs-keyword">del</span> f1.AAA<br></code></pre></td></tr></table></figure><p>或者</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>:<br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_AAA</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'get的时候运行我啊'</span>)<br><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">set_AAA</span>(<span class="hljs-params">self,value</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">'set的时候运行我啊'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">delete_AAA</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'delete的时候运行我啊'</span>)<br>AAA=<span class="hljs-built_in">property</span>(get_AAA,set_AAA,delete_AAA) <span class="hljs-comment">#内置property三个参数与</span><br>get,<span class="hljs-built_in">set</span>,delete一一对应<br><br>f1=Foo()<br>f1.AAA<br>f1.AAA=<span class="hljs-string">'aaa'</span><br><span class="hljs-keyword">del</span> f1.AAA<br></code></pre></td></tr></table></figure><p>商品的例子</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Goods</span>(<span class="hljs-title class_ inherited__">object</span>):<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-comment"># 原价</span><br> self.original_price = <span class="hljs-number">100</span><br> <span class="hljs-comment"># 折扣</span><br> self.discount = <span class="hljs-number">0.8</span><br><br><span class="hljs-meta"> @property</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">price</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-comment"># 实际价格 = 原价 * 折扣</span><br> new_price = self.original_price * self.discount<br> <span class="hljs-keyword">return</span> new_price<br><br><span class="hljs-meta"> @price.setter</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">price</span>(<span class="hljs-params">self, value</span>):<br> self.original_price = value<br><br><span class="hljs-meta"> @price.deleter</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">price</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-keyword">del</span> self.original_price<br><br>obj = Goods()<br><span class="hljs-built_in">print</span>(obj.price) <span class="hljs-comment"># 获取商品价格</span><br>obj.price = <span class="hljs-number">200</span> <span class="hljs-comment"># 修改商品原价</span><br><span class="hljs-built_in">print</span>(obj.price)<br><span class="hljs-keyword">del</span> obj.price <span class="hljs-comment"># 删除商品原价</span><br></code></pre></td></tr></table></figure><h1>isinstace 与 issubclass</h1><p>isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>(<span class="hljs-title class_ inherited__">A</span>):<br><span class="hljs-keyword">pass</span><br><br>obj = B()<br><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(obj,B))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(obj,A))<br></code></pre></td></tr></table></figure><p><strong>issubclass(a,b):</strong> 判断a类是否是b类(或者b的派生类)的派生类</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>(<span class="hljs-title class_ inherited__">A</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span>(<span class="hljs-title class_ inherited__">B</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">issubclass</span>(B,A))<br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">issubclass</span>(C,A))<br></code></pre></td></tr></table></figure><p>思考:那么 list str tuple dict等这些类与 Iterable类 的关系是什么?</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> collections <span class="hljs-keyword">import</span> Iterable<br><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>([<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>], <span class="hljs-built_in">list</span>)) <span class="hljs-comment"># True</span><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>([<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>], Iterable)) <span class="hljs-comment"># True</span><br><span class="hljs-built_in">print</span>(<span class="hljs-built_in">issubclass</span>(<span class="hljs-built_in">list</span>,Iterable)) <span class="hljs-comment"># True</span><br><br><span class="hljs-comment"># 由上面的例子可得,这些可迭代的数据类型,list str tuple dict等 都是 Iterable的子类。</span><br></code></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1>细分类的组成成员</h1>
<p>之前咱们讲过类大致分两块区域</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><</summary>
<category term="Python" scheme="https://xiaolaji.site/categories/Python/"/>
<category term="Python学习" scheme="https://xiaolaji.site/tags/Python%E5%AD%A6%E4%B9%A0/"/>
</entry>
<entry>
<title>Python中的封装与多态</title>
<link href="https://xiaolaji.site/20221001/Python%E4%B8%AD%E7%9A%84%E5%B0%81%E8%A3%85%E4%B8%8E%E5%A4%9A%E6%80%81/"/>
<id>https://xiaolaji.site/20221001/Python%E4%B8%AD%E7%9A%84%E5%B0%81%E8%A3%85%E4%B8%8E%E5%A4%9A%E6%80%81/</id>
<published>2022-10-01T04:29:00.000Z</published>
<updated>2023-05-27T14:38:52.000Z</updated>
<content type="html"><![CDATA[<h1>封装</h1><ol><li class="lvl-3"><strong>封装</strong> 是面向对象编程的一大特点</li><li class="lvl-3">面向对象编程的 <strong>第一步</strong> —— 将 <strong>属性</strong> 和 <strong>方法 封装</strong> 到一个抽象的 <strong>类</strong> 中</li><li class="lvl-3"><strong>外界</strong> 使用 <strong>类</strong> 创建 <strong>对象</strong>,然后 <strong>让对象调用方法</strong></li><li class="lvl-3"><strong>对象方法的细节</strong> 都被 <strong>封装</strong> 在 <strong>类的内部</strong></li></ol><p>第一步:将内容封装到某处</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,age</span>):<br> self.name = name<br> self.age = age<br> <br>obj1 = Foo(<span class="hljs-string">'chensong'</span>,<span class="hljs-number">18</span>)<br>obj2 = Foo(<span class="hljs-string">'aaron'</span>,<span class="hljs-number">16</span>)<br></code></pre></td></tr></table></figure><p>第二步:从某处调用被封装的内容</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,age</span>):<br>self.name = name<br>self.age = age<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">detail</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.name)<br><span class="hljs-built_in">print</span>(self.age)<br><br>obj1 = Foo(<span class="hljs-string">'chensong'</span>,<span class="hljs-number">18</span>)<br>obj2 = Foo(<span class="hljs-string">'aaron'</span>,<span class="hljs-number">16</span>)<br><br><span class="hljs-built_in">print</span>(obj1.name)<br><span class="hljs-built_in">print</span>(obj2.age)<br><span class="hljs-comment"># 通过对象直接调用被封装的内容</span><br><br>obj1.detail()<br>obj2.detail()<br><span class="hljs-comment"># 通过self间接调用被封装的内容</span><br></code></pre></td></tr></table></figure><h2 id="案例一,-摆放家具">案例一, 摆放家具</h2><p><strong>需求</strong></p><ol><li class="lvl-3"><p>房子(House)有户型、总面积和家具名称列表</p><p></p><ul class="lvl-2"><li class="lvl-5"><p>新房子没有任何的家具</p></li></ul></li><li class="lvl-3"><p>家具(HouseItem)有名字和占地面积,其中</p><pre><code class="hljs"> 席梦思(bed) 占地 4 平米 衣柜(chest) 占地 2 平米 餐桌(table) 占地 1.5 平米</code></pre></li><li class="lvl-3"><p>将以上三件 家具 添加 到 房子 中</p></li><li class="lvl-3"><p>打印房子时,要求输出:<strong>户型、总面积、剩余面积、家具名称列表</strong></p></li></ol><p><img src="image-20220710130733553-1685188728096-19.png" alt="实例图"></p><p><strong>剩余面积</strong></p><ol><li class="lvl-3"><p>在创建房子对象时,定义一个 剩余面积的属性,初始值和总面积相等</p></li><li class="lvl-3"><p>当调用 add_item 方法,向房间 添加家具 时,让 剩余面积 -= 家具面积</p></li></ol><p>**思考:**应该先开发哪一个类?</p><p><strong>答案 —— 家具类</strong></p><ol><li class="lvl-3"><p>家具简单</p></li><li class="lvl-3"><p>房子要使用到家具,被使用的类,通常应该先开发</p></li></ol><p>创建家具</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">HouseItem</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, name, area</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> :param name: 家具名称</span><br><span class="hljs-string"> :param area: 占地面积</span><br><span class="hljs-string"> """</span><br> self.name = name<br> self.area = area<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__str__</span>(<span class="hljs-params">self</span>):<br><span class="hljs-keyword">return</span> <span class="hljs-string">"[%s] 占地面积 %.2f"</span> % (self.name, self.area)<br><br><span class="hljs-comment"># 1. 创建家具</span><br>bed = HouseItem(<span class="hljs-string">"席梦思"</span>, <span class="hljs-number">4</span>)<br>chest = HouseItem(<span class="hljs-string">"衣柜"</span>, <span class="hljs-number">2</span>)<br>table = HouseItem(<span class="hljs-string">"餐桌"</span>, <span class="hljs-number">1.5</span>)<br><br><span class="hljs-built_in">print</span>(bed)<br><span class="hljs-built_in">print</span>(chest)<br><span class="hljs-built_in">print</span>(table<br></code></pre></td></tr></table></figure><p>创建房间</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">House</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, house_type, area</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> </span><br><span class="hljs-string"> :param house_type: 户型</span><br><span class="hljs-string"> :param area: 总面积</span><br><span class="hljs-string"> """</span><br> self.house_type = house_type<br> self.area = area<br> <span class="hljs-comment"># 剩余面积默认和总面积一致</span><br> self.free_area = area<br> <span class="hljs-comment"># 默认没有任何的家具</span><br> self.item_list = []<br> <br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__str__</span>(<span class="hljs-params">self</span>):<br><br> <span class="hljs-comment"># Python 能够自动的将一对括号内部的代码连接在一起</span><br> <span class="hljs-keyword">return</span> (<span class="hljs-string">"户型:%s\n总面积:%.2f[剩余:%.2f]\n家具:%s"</span>% (self.house_type, self.area,self.free_area, self.item_list))<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">add_item</span>(<span class="hljs-params">self, item</span>):<br><br><span class="hljs-built_in">print</span>(<span class="hljs-string">"要添加 %s"</span> % item)<br><br>...<br><br><span class="hljs-comment"># 2. 创建房子对象</span><br>my_home = House(<span class="hljs-string">"两室一厅"</span>, <span class="hljs-number">60</span>)<br><br>my_home.add_item(bed)<br>my_home.add_item(chest)<br>my_home.add_item(table)<br><br><span class="hljs-built_in">print</span>(my_home)<br></code></pre></td></tr></table></figure><p>添加家具</p><ul class="lvl-0"><li class="lvl-2"><p>主程序只负责创建 房子 对象和 家具 对象</p></li><li class="lvl-2"><p>让房子 对象调用 add_item 方法 将家具添加到房子中</p></li><li class="lvl-2"><p>面积计算、剩余面积、家具列表等处理都被封装到房子类的内部</p></li></ul><h2 id="案例二、士兵突击">案例二、士兵突击</h2><p><strong>需求</strong></p><ol><li class="lvl-3"><p><strong>士兵</strong> <strong>许三多</strong> 有一把 <strong>AK47</strong></p></li><li class="lvl-3"><p><strong>士兵</strong> 可以 <strong>开火</strong></p></li><li class="lvl-3"><p><strong>枪</strong> 能够 <strong>发射</strong> 子弹</p></li><li class="lvl-3"><p><strong>枪</strong> 装填 <strong>装填子弹</strong> —— <strong>增加子弹数量</strong></p></li></ol><p><img src="image-20220711092746156-1685188728097-21.png" alt="示例图"></p><p><strong>开发枪类</strong></p><ul class="lvl-0"><li class="lvl-2"><p>shoot 方法需求</p><ol><li class="lvl-5"><p>判断是否有子弹,没有子弹无法射击</p></li><li class="lvl-5"><p>使用 print 提示射击,并且输出子弹数量</p></li></ol></li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Gun</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, model</span>):<br><br><span class="hljs-comment"># 枪的型号</span><br>self.model = model<br><span class="hljs-comment"># 子弹数量</span><br>self.bullet_count = <span class="hljs-number">0</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">add_bullet</span>(<span class="hljs-params">self, count</span>):<br><br>self.bullet_count += count<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">shoot</span>(<span class="hljs-params">self</span>):<br><br><span class="hljs-comment"># 判断是否还有子弹</span><br><span class="hljs-keyword">if</span> self.bullet_count <= <span class="hljs-number">0</span>:<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"没有子弹了..."</span>)<br><span class="hljs-keyword">return</span><br><br> <span class="hljs-comment"># 发射一颗子弹</span><br> self.bullet_count -= <span class="hljs-number">1</span><br> <br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"%s 发射子弹[%d]...突突突"</span> % (self.model, self.bullet_count))<br><br><span class="hljs-comment"># 创建枪对象</span><br>ak47 = Gun(<span class="hljs-string">"ak47"</span>)<br>ak47.add_bullet(<span class="hljs-number">50</span>)<br>ak47.shoot()<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>开发士兵类</p></li></ul><blockquote><p>假设:每一个新兵 都 <strong>没有枪</strong></p></blockquote><p><strong>定义没有初始值的属性</strong></p><p>在定义属性时,如果 <strong>不知道设置什么初始值</strong>,可以设置为 None</p><ul class="lvl-0"><li class="lvl-2"><p>None 关键字 表示 什么都没有</p></li><li class="lvl-2"><p>表示一个 空对象,没有方法和属性,是一个特殊的常量</p></li><li class="lvl-2"><p>可以将 None 赋值给任何一个变量</p></li></ul><p>fire 方法需求</p><ul class="lvl-0"><li class="lvl-2"><p>判断是否有枪,没有枪没法冲锋</p></li><li class="lvl-2"><p>喊一声口号</p></li><li class="lvl-2"><p>装填子弹</p></li><li class="lvl-2"><p>射击</p></li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Soldier</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, name,gun</span>):<br><br> <span class="hljs-comment"># 姓名</span><br> self.name = name<br> <span class="hljs-comment"># 枪,士兵初始没有枪 None 关键字表示什么都没有</span><br> self.gun = <span class="hljs-literal">None</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">fire</span>(<span class="hljs-params">self</span>):<br> <br> <span class="hljs-comment"># 1. 判断士兵是否有枪</span><br> <span class="hljs-keyword">if</span> self.gun <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"[%s] 还没有枪..."</span> % self.name)<br><br> <span class="hljs-keyword">return</span><br><br> <span class="hljs-comment"># 2. 高喊口号</span><br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"冲啊...[%s]"</span> % self.name)<br><br> <span class="hljs-comment"># 3. 让枪装填子弹</span><br> self.gun.add_bullet(<span class="hljs-number">50</span>)<br><br> <span class="hljs-comment"># 4. 让枪发射子弹</span><br> self.gun.shoot()<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python">xusanduo=Soldier(<span class="hljs-string">'许三多'</span>)<br>xusanduo.fire()<br>ak47=Gun(<span class="hljs-string">'ak47'</span>)<br>xusanduo.gun=ak47<br>xusanduo.fire()<br>xusanduo.gun.shoot()<br>xusanduo.gun.shoot()<br>xusanduo.gun.shoot()<br>xusanduo.gun.shoot()<br>xusanduo.gun.shoot()<br>xusanduo.gun.shoot()<br>xusanduo.gun.shoot()<br>xusanduo.gun.shoot()<br>xusanduo.gun.add_bullet(<span class="hljs-number">50</span>)<br>xusanduo.gun.shoot()<br>xusanduo.gun.shoot()<br></code></pre></td></tr></table></figure><h1>多态</h1><p>(多态的含义其实就是子类去继承大部分的功能,但是对于继承过来的功能可以进行改写,来达到相对于父类更加多的功能)</p><p><strong>多态</strong> 不同的 <strong>子类对象</strong> 调用相同的 <strong>父类方法</strong>,产生不同的执行结果</p><ul class="lvl-0"><li class="lvl-2"><p><strong>多态</strong> 可以 <strong>增加代码的灵活度</strong></p></li><li class="lvl-2"><p>以 <strong>继承</strong> 和 <strong>重写父类方法</strong> 为前提</p></li><li class="lvl-2"><p>是调用方法的技巧,<strong>不会影响到类的内部设计</strong></p></li></ul><p><img src="image-20220711093856993-1685188728097-23.png" alt="关系表示图"></p><h2 id="案例,哮天犬">案例,哮天犬</h2><p><strong>需求</strong></p><ol><li class="lvl-3"><p>在 Dog 类中封装方法 game</p><p>普通狗只是简单的玩耍</p></li><li class="lvl-3"><p>定义 XiaoTianDog 继承自 Dog ,并且重写 game 方法</p><p>哮天犬需要在天上玩耍</p></li><li class="lvl-3"><p>定义 Person 类,并且封装一个和狗玩 的方法</p><p>在方法内部,直接让 <strong>狗对象</strong> 调用 game 方法</p></li></ol><p><img src="image-20220711094103117-1685188728097-25.png" alt="示意图"></p><p><strong>案例小结</strong></p><ul class="lvl-0"><li class="lvl-2"><p>Person 类中只需要让狗对象调用 game 方法,而不关心具体是什么狗</p></li><li class="lvl-2"><p>game 方法是在 Dog 父类中定义的</p></li><li class="lvl-2"><p>在程序执行时,传入不同的 狗对象 实参,就会产生不同的执行效果</p></li></ul><blockquote><p>多态 更容易编写出出通用的代码,做出通用的编程,以适应需求的不断变化!</p></blockquote><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Dog</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, name</span>):<br>self.name = name<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">game</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"%s 蹦蹦跳跳的玩耍..."</span> % self.name)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">XiaoTianDog</span>(<span class="hljs-title class_ inherited__">Dog</span>):<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">game</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"%s 飞到天上去玩耍..."</span> % self.name)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span>:<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, name</span>):<br>self.name = name<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">game_with_dog</span>(<span class="hljs-params">self, dog</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"%s 和 %s 快乐的玩耍..."</span> % (self.name, dog.name))<br><br><span class="hljs-comment"># 让狗玩耍</span><br>dog.game()<br><br><span class="hljs-comment"># 1. 创建一个狗对象</span><br>wangcai = Dog(<span class="hljs-string">"旺财"</span>)<br>xiaotianquan = XiaoTianDog(<span class="hljs-string">"飞天旺财"</span>)<br><br><span class="hljs-comment"># 2. 创建一个小明对象</span><br>xiaoming = Person(<span class="hljs-string">"小明"</span>)<br><br><span class="hljs-comment"># 3. 让小明调用和狗玩的方法</span><br>xiaoming.game_with_dog(wangcai)<br>xiaoming.game_with_dog(xiaotianquan)<br></code></pre></td></tr></table></figure><p>python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。</p><p>对于代码上的解释其实很简答:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in A f1'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in A f2'</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in B f1'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in B f2'</span>)<br><br>obj = A()<br>obj.f1()<br>obj.f2()<br><br>obj2 = B()<br>obj2.f1()<br>obj2.f2()<br><span class="hljs-comment"># A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。</span><br><span class="hljs-comment"># 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。</span><br><br><span class="hljs-comment"># 这样的例子比比皆是:str tuple list 都有 index方法,这就是统一了规范。</span><br><span class="hljs-comment"># str bytes 等等 这就是互称为鸭子类型。</span><br></code></pre></td></tr></table></figure><h1>类的约束</h1><p>(将具有相同的用途的类,可以在定义某个功能的时候在不同的类中将一样的功能进行相同命名,这样在外部进行调用的时候,可以直接使用相同的函数进行一次性调用,这样将选择权交给用户,更为的灵活,详见下面的支付案例)</p><p>写一个支付功能</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">QQpay</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用qq支付%s元'</span> % money)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Alipay</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用阿里支付%s元'</span> % money)<br><br>a = Alipay()<br>a.pay(<span class="hljs-number">100</span>)<br><br>b = QQpay()<br>b.pay(<span class="hljs-number">200</span>)<br></code></pre></td></tr></table></figure><p>统一一下付款方式</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">QQpay</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用qq支付%s元'</span> % money)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Alipay</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用阿里支付%s元'</span> % money)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">obj,money</span>):<br>obj.pay(money)<br><br>a = Alipay()<br>b = QQpay()<br><br>pay(a,<span class="hljs-number">100</span>)<br>pay(b,<span class="hljs-number">200</span>)<br></code></pre></td></tr></table></figure><p>如果后期添加微信支付,但是没有统一标准,换个程序员就可能写成这样</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">QQpay</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用qq支付%s元'</span> % money)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Alipay</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用阿里支付%s元'</span> % money)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Wechatpay</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">fuqian</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用微信支付%s元'</span> % money)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">obj,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"==============="</span>)<br>obj.pay(money)<br><br>a = Alipay()<br>b = QQpay()<br><br>pay(a,<span class="hljs-number">100</span>)<br>pay(b,<span class="hljs-number">200</span>)<br><br>c = Wechatpay()<br>c.fuqian(<span class="hljs-number">300</span>)<br></code></pre></td></tr></table></figure><p>解释:由于WeChat使用的内部付款方式不是与其他两种相同的pay模式,所以无法在外部一次性进行选择,会减少代码的可读性,没有灵活性</p><p><strong>所以此时我们要用到对类的约束,对类的约束有两种:</strong></p><ol><li class="lvl-3"><p>提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有 的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.</p></li><li class="lvl-3"><p>使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也 可以起到约束的效果.</p></li></ol><p>先用第一种方法解决问题</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#此处通过,首先在所有的函数的父类内部定义一个pay方法,要求子类必须对这个父类方法进行修改,否则就会进行当初程序员自己定义的一个报错,同时开始提示,如:打印“你没有去定义pay方法”</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Payment</span>:<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。</span><br><span class="hljs-string"> """</span><br> <br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-keyword">raise</span> Exception(<span class="hljs-string">"你没有实现pay方法"</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">QQpay</span>(<span class="hljs-title class_ inherited__">Payment</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用qq支付%s元'</span> % money)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Alipay</span>(<span class="hljs-title class_ inherited__">Payment</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用阿里支付%s元'</span> % money)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Wechatpay</span>(<span class="hljs-title class_ inherited__">Payment</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">fuqian</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用微信支付%s元'</span> % money)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">obj,money</span>):<br>obj.pay(money)<br>a = Alipay()<br>b = QQpay()<br>c = Wechatpay()<br>pay(a,<span class="hljs-number">100</span>)<br>pay(b,<span class="hljs-number">200</span>)<br>pay(c,<span class="hljs-number">300</span>)<br></code></pre></td></tr></table></figure><p>引入抽象类的概念处理(不建议)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> abc <span class="hljs-keyword">import</span> ABCMeta,abstractmethod<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Payment</span>(metaclass=ABCMeta): <span class="hljs-comment"># 抽象类 接口类 规范和约束 metaclass指定的是一个元类</span><br><span class="hljs-meta"> @abstractmethod</span><span class="hljs-comment">#在这里加入一个修饰,在这个修饰下面放入需要的函数,这样可以实现与上面一样要求必须定义的功能,如果不进行定义,回引起IndentationError的报错,但是不会像上一方法那样直接进行打印父方法中的东西</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self</span>):<span class="hljs-keyword">pass</span> <span class="hljs-comment"># 抽象方法</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Alipay</span>(<span class="hljs-title class_ inherited__">Payment</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用支付宝支付了%s元'</span>%money)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">QQpay</span>(<span class="hljs-title class_ inherited__">Payment</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">self,money</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'使用qq支付了%s元'</span>%money)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Wechatpay</span>(<span class="hljs-title class_ inherited__">Payment</span>):<br><span class="hljs-comment"># def pay(self,money):</span><br><span class="hljs-comment"># print('使用微信支付了%s元'%money)</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">pay</span>(<span class="hljs-params">a,money</span>):<br>a.pay(money)<br><br>a = Alipay()<br>a.pay(<span class="hljs-number">100</span>)<br>pay(a,<span class="hljs-number">100</span>) <span class="hljs-comment"># 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能</span><br>q = QQpay()<br>q.pay(<span class="hljs-number">100</span>)<br>pay(q,<span class="hljs-number">100</span>)<br>w = Wechatpay() <span class="hljs-comment"># 到实例化对象的时候就会报错</span><br>pay(w,<span class="hljs-number">100</span>)<br><br><span class="hljs-comment"># 抽象类和接口类做的事情 :建立规范</span><br><span class="hljs-comment"># 制定一个类的metaclass是ABCMeta,</span><br><span class="hljs-comment"># 那么这个类就变成了一个抽象类(接口类)</span><br><span class="hljs-comment"># 这个类的主要功能就是建立一个规范</span><br></code></pre></td></tr></table></figure><p>总结: 约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种:</p><ol><li class="lvl-3"><p>使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c#. 所以使⽤频率还是很少的</p></li><li class="lvl-3"><p>使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError. 这样比较专业, ⽽且错误比较明 确.(推荐</p></li></ol><h1>super()深入了解</h1><p>super是严格按照类的继承顺序**(mro)**执行!!!</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in A f1'</span>)<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in A f2'</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>(<span class="hljs-title class_ inherited__">A</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">super</span>().f2()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in A Foo'</span>)<br><br>obj = Foo()<br>obj.f1()<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in A'</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>(<span class="hljs-title class_ inherited__">A</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">super</span>().f1()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in Foo'</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Bar</span>(<span class="hljs-title class_ inherited__">A</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in Bar'</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Info</span>(Foo,Bar):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">super</span>().f1()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'in Info f1'</span>)<br><br>obj = Info()<br>obj.f1()<br><br><span class="hljs-built_in">print</span>(Info.mro())<br></code></pre></td></tr></table></figure><p>super方法可以在继承后,儿子可以去调用父亲的方法使用super方法即可</p><p>这个就是super方法的好处,可以让继承后的直接调用继承的内部方法</p>]]></content>
<summary type="html"><h1>封装</h1>
<ol>
<li class="lvl-3"><strong>封装</strong> 是面向对象编程的一大特点</li>
<li class="lvl-3">面向对象编程的 <strong>第一步</strong> —— 将 <strong>属性</str</summary>
<category term="Python" scheme="https://xiaolaji.site/categories/Python/"/>
<category term="Python学习" scheme="https://xiaolaji.site/tags/Python%E5%AD%A6%E4%B9%A0/"/>
</entry>
<entry>
<title>Python中的继承</title>
<link href="https://xiaolaji.site/20221001/Python%E4%B8%AD%E7%9A%84%E7%BB%A7%E6%89%BF/"/>
<id>https://xiaolaji.site/20221001/Python%E4%B8%AD%E7%9A%84%E7%BB%A7%E6%89%BF/</id>
<published>2022-10-01T04:20:00.000Z</published>
<updated>2023-05-27T12:09:04.000Z</updated>
<content type="html"><![CDATA[<h1>面向对象的继承</h1><p><strong>面向对象三大特性</strong></p><p><strong>封装</strong> 根据 <strong>职责</strong> 将 <strong>属性</strong> 和 <strong>方法 封装</strong> 到一个抽象的 <strong>类</strong> 中</p><p><strong>继承 实现代码的重用</strong>,相同的代码不需要重复的编写</p><p><strong>多态</strong> 不同的对象调用相同的方法,产生不同的执行结果,<strong>增加代码的灵活度</strong></p><p>不用继承创建对象</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age</span>):<br> self.name = name<br> self.age = age<br> self.sex = sex<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Cat</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age</span>):<br> self.name = name<br> self.age = age<br> self.sex = sex<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Dog</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age</span>):<br> self.name = name<br> self.age = age<br> self.sex = sex<br></code></pre></td></tr></table></figure><p>使用继承的方式</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Aniaml</span>(<span class="hljs-title class_ inherited__">object</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age</span>):<br> self.name = name<br> self.age = age<br> self.sex = sex<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Cat</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br> <span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Dog</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br></code></pre></td></tr></table></figure><p>**继承的概念:**<strong>子类</strong> 拥有 <strong>父类</strong> 的所有 <strong>方法 和 属性</strong></p><p><img src="image-20220709204526823.png" alt="是否使用继承进行对比"></p><p>继承的优点也是显而易见的:</p><ol><li class="lvl-3"><p>增加了类的耦合性(耦合性不宜多,宜精)。</p></li><li class="lvl-3"><p>减少了重复代码。</p></li><li class="lvl-3"><p>使得代码更加规范化,合理化。</p></li></ol><h1>继承的分类</h1><p>上面的那个例子,涉及到的专业术语:</p><ul class="lvl-0"><li class="lvl-2"><p>Dog 类是 Animal 类的子类, Animal 类是 Dog 类的父类, Dog 类从 Animal 类继承</p></li><li class="lvl-2"><p>Dog 类是 Animal 类的派生类, Animal 类是 Dog 类的基类, Dog 类从 Animal 类派生</p></li></ul><p>继承:可以分<strong>单继承</strong>,<strong>多继承</strong>。</p><p>python3x版本中只有一种类:</p><p>python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object</p><h2 id="单继承">单继承</h2><h3 id="类名,对象执行父类方法">类名,对象执行父类方法</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Aniaml</span>(<span class="hljs-title class_ inherited__">object</span>):<br>type_name = <span class="hljs-string">'动物类'</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age</span>):<br> self.name = name<br> self.age = age<br> self.sex = sex<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'吃'</span>,self)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br> <span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Cat</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Dog</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-built_in">print</span>(Person.type_name)<br>Person.eat(<span class="hljs-string">'东西'</span>)<br>p1 = Person(<span class="hljs-string">'aaron'</span>,<span class="hljs-string">'男'</span>,<span class="hljs-number">18</span>)<br><span class="hljs-built_in">print</span>(p1.__dict__)<br><span class="hljs-built_in">print</span>(p1.type_name)<br>p1.type_name = <span class="hljs-string">'666'</span><br><span class="hljs-built_in">print</span>(p1)<br>p1.eat()<br></code></pre></td></tr></table></figure><h3 id="执行顺序">执行顺序</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Aniaml</span>(<span class="hljs-title class_ inherited__">object</span>):<br>type_name = <span class="hljs-string">'动物类'</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age</span>):<br> self.name = name<br> self.age = age<br> self.sex = sex<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'吃'</span>,self)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 用筷子吃饭'</span>%self.name)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Cat</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Dog</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br><br>p1 = Person(<span class="hljs-string">'eagle'</span>,<span class="hljs-string">'男'</span>,<span class="hljs-number">18</span>)<br>p1.eat()<br></code></pre></td></tr></table></figure><h2 id="同时执行类以及父类方法">同时执行类以及父类方法</h2><p>方法一:如果想执行父类的func方法,这个方法并且子类中引用,那么就在子类的方法中写上:父 类.func(对象,其他参数)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Aniaml</span>(<span class="hljs-title class_ inherited__">object</span>):<br> type_name = <span class="hljs-string">'动物类'</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age</span>):<br> self.name = name<br> self.age = age<br> self.sex = sex<br> <br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'吃东西'</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age,mind</span>):<br>Aniaml.__init__(self,name,sex,age)<br>self.mind = mind<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>(<span class="hljs-params">self</span>):<br>Aniaml.eat(<span class="hljs-number">111</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃饭'</span>%self.name)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Cat</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Dog</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br><br>p1 = Person(<span class="hljs-string">'aaron'</span>,<span class="hljs-string">'男'</span>,<span class="hljs-number">18</span>,<span class="hljs-string">'想吃东西'</span>)<br>p1.eat()<br><br></code></pre></td></tr></table></figure><p>方法二:利用super,super().func(参数)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Aniaml</span>(<span class="hljs-title class_ inherited__">object</span>):<br> type_name = <span class="hljs-string">'动物类'</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age</span>):<br> self.name = name<br> self.age = age<br> self.sex = sex<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'吃东西'</span>)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name,sex,age,mind</span>):<br><span class="hljs-comment"># super(Person,self).__init__(name,sex,age)</span><br><span class="hljs-built_in">super</span>().__init__(name,sex,age)<br>self.mind = mind<br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">eat</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">super</span>().eat()<br><span class="hljs-built_in">print</span>(<span class="hljs-string">'%s 吃饭'</span>%self.name)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Cat</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Dog</span>(<span class="hljs-title class_ inherited__">Aniaml</span>):<br><span class="hljs-keyword">pass</span><br><br>p1 = Person(<span class="hljs-string">'aaron'</span>,<span class="hljs-string">'男'</span>,<span class="hljs-number">18</span>,<span class="hljs-string">'想吃东西'</span>)<br>p1.eat()<br></code></pre></td></tr></table></figure><p>单继承练习题</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,num</span>):<br>self.num = num<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.num)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>(<span class="hljs-title class_ inherited__">Base</span>):<br><span class="hljs-keyword">pass</span><br><br>obj = Foo(<span class="hljs-number">123</span>)<br>obj.func1()<br><span class="hljs-comment"># 运⾏的是Base中的func1</span><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,num</span>):<br>self.num = num<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.num)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>(<span class="hljs-title class_ inherited__">Base</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"Foo.func1"</span>,self.num)<br><br>obj = Foo(<span class="hljs-number">123</span>)<br>obj.func1()<br><span class="hljs-comment"># 运⾏的是Foo中的func1</span><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, num</span>):<br>self.num = num<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.num)<br>self.func2()<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"Base.func2"</span>)<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>(<span class="hljs-title class_ inherited__">Base</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"Foo.func2"</span>)<br><br>obj = Foo(<span class="hljs-number">123</span>)<br>obj.func1()<br><span class="hljs-comment"># func1是Base中的 func2是⼦类中的</span><br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, num</span>):<br>self.num = num<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.num)<br>self.func2()<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-number">111</span>, self.num)<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>(<span class="hljs-title class_ inherited__">Base</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-number">222</span>, self.num)<br><br>lst = [Base(<span class="hljs-number">1</span>), Base(<span class="hljs-number">2</span>), Foo(<span class="hljs-number">3</span>)]<br><span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> lst:<br>obj.func2()<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, num</span>):<br>self.num = num<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func1</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(self.num)<br>self.func2()<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-number">111</span>, self.num)<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>(<span class="hljs-title class_ inherited__">Base</span>):<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">func2</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-number">222</span>, self.num)<br><br>lst = [Base(<span class="hljs-number">1</span>), Base(<span class="hljs-number">2</span>), Foo(<span class="hljs-number">3</span>)]<br><span class="hljs-keyword">for</span> obj <span class="hljs-keyword">in</span> lst:<br>obj.func1()<br></code></pre></td></tr></table></figure><h2 id="方法的重写">方法的重写</h2><ul class="lvl-0"><li class="lvl-2"><p>如果在开发中,<strong>父类的方法实现</strong> 和 <strong>子类的方法实现</strong>,<strong>完全不同</strong></p></li><li class="lvl-2"><p>就可以使用 <strong>覆盖</strong> 的方式,<strong>在子类中 重新编写</strong> 父类的方法实现</p></li></ul><blockquote><p>具体的实现方式,就相当于在 <strong>子类中</strong> 定义了一个 <strong>和父类同名的方法并且实现</strong></p></blockquote><p>重写之后,在运行时,<strong>只会调用</strong> 子类中重写的方法,而不再会调用 <strong>父类封装的方法</strong></p><h2 id="对父类方法进行-扩展">对父类方法进行 扩展</h2><ul class="lvl-0"><li class="lvl-2"><p>如果在开发中,子类的方法实现中包含父类的方法实现</p><ul class="lvl-2"><li class="lvl-4">父类原本封装的方法实现 是 子类方法的一部分</li></ul></li><li class="lvl-2"><p>就可以使用扩展的方式</p></li></ul><ol><li class="lvl-3"><p><strong>在子类中 重写</strong> 父类的方法</p></li><li class="lvl-3"><p>在需要的位置使用 <code>super().父类方法</code> 来调用父类方法的执行</p></li><li class="lvl-3"><p>代码其他的位置针对子类的需求,编写 <strong>子类特有的代码实现</strong></p></li></ol><p>关于 super</p><ol><li class="lvl-3"><p>在 Python 中 super 是一个 特殊的类</p></li><li class="lvl-3"><p>super() 就是使用 super 类创建出来的对象</p></li><li class="lvl-3"><p>最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现</p></li></ol><p>调用父类方法的另外一种方式(知道)</p><blockquote><p>在 Python 2.x 时,如果需要调用父类的方法,还可以使用以下方式:</p></blockquote><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs crystal">父类名.方法(<span class="hljs-keyword">self</span>)<br></code></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>这种方式,目前在 Python 3.x 还支持这种方式</p></li><li class="lvl-2"><p>这种方法 不推荐使用,因为一旦 父类发生变化,方法调用位置的 类名 同样需要修改</p></li></ul><p>提示</p><ul class="lvl-0"><li class="lvl-2"><p>在开发时, 父类名 和 super() 两种方式不要混用</p></li><li class="lvl-2"><p>如果使用当前子类名调用方法,会形成递归调用,出现死循环</p></li></ul><h2 id="父类的-私有属性-和-私有方法">父类的 私有属性 和 私有方法</h2><ul class="lvl-0"><li class="lvl-2"><p>子类对象 不能 在自己的方法内部,直接 访问 父类的 私有属性 或 私有方法</p></li><li class="lvl-2"><p>子类对象 可以通过 父类 的 公有方法 间接 访问到 私有属性 或 私有方法</p></li></ul><ol><li class="lvl-3"><p>子类对象 不能 在自己的方法内部,直接 访问 父类的 私有属性 或 私有方法</p></li><li class="lvl-3"><p>子类对象 可以通过 父类 的 公有方法 间接 访问到 私有属性 或 私有方法</p></li></ol><blockquote><p>私有属性、方法 是对象的隐私,不对外公开,外界 以及 子类 都不能直接访问</p><p>私有属性、方法 通常用于做一些内部的事情</p></blockquote><p><img src="image-20220709211548852.png" alt="示意图"></p><ul class="lvl-0"><li class="lvl-2"><p>B 的对象不能直接访问 __num2 属性</p></li><li class="lvl-2"><p>B 的对象不能在 demo 方法内访问 __num2 属性</p></li><li class="lvl-2"><p>B 的对象可以在 demo 方法内,调用父类的 test 方法</p></li><li class="lvl-2"><p>父类的 test 方法内部,能够访问 __num2 属性和 __test 方法</p></li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,num1,num2</span>):<br> self.num1=num1<br> self.__num2=num2<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">test</span>(<span class="hljs-params">self</span>):<br> self.__test()<br> <span class="hljs-built_in">print</span>(self.__num2)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"父类公有方法"</span>)<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">__test</span>(<span class="hljs-params">self</span>):<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"父类私有方法"</span>)<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>(<span class="hljs-title class_ inherited__">A</span>):<br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">demo</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"子类"</span>)<br>b1 =B(<span class="hljs-number">10</span>,<span class="hljs-number">20</span>)<br><span class="hljs-built_in">print</span>(b1.num1)<br><span class="hljs-comment"># print(b1.__num2)</span><br>b1.test()<br><span class="hljs-comment"># b1.__test()</span><br><span class="hljs-built_in">print</span>(b1.__dict__)<br><span class="hljs-built_in">print</span>(b1._A__num2) <span class="hljs-comment"># 不推荐使用</span><br>b1._A__test() <span class="hljs-comment">#不推荐使用</span><br><br></code></pre></td></tr></table></figure><h1>多继承</h1><p><strong>概念</strong></p><p><strong>子类</strong> 可以拥有 <strong>多个父类</strong>,并且具有 <strong>所有父类</strong> 的 <strong>属性</strong> 和 <strong>方法</strong></p><p>例如:<strong>孩子</strong> 会继承自己 <strong>父亲</strong> 和 <strong>母亲</strong> 的 <strong>特性</strong></p><p><img src="/image-20220710085319316.png" alt="image-20220710085319316"></p><p><strong>语法</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">子类名</span>(父类名<span class="hljs-number">1</span>, 父类名<span class="hljs-number">2.</span>..)<br><span class="hljs-keyword">pass</span><br></code></pre></td></tr></table></figure><p><strong>问题的提出</strong></p><p>如果 <strong>不同的父类</strong> 中存在 <strong>同名的方法</strong>,<strong>子类对象</strong> 在调用方法时,会调用 <strong>哪一个父类中</strong>的方法呢?</p><p>提示:<strong>开发时,应该尽量避免这种容易产生混淆的情况!</strong> —— 如果 <strong>父类之间</strong> 存在 <strong>同名的属性或者方法</strong>,应该 <strong>尽量避免</strong>使用多继承</p><p><img src="image-20220710085552103.png" alt="关系图"></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">ShenXian</span>: <span class="hljs-comment"># 神仙</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">fei</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"神仙都会⻜"</span>)<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">chitao</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"吃蟠桃"</span>)<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Monkey</span>: <span class="hljs-comment"># 猴</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">chitao</span>(<span class="hljs-params">self</span>):<br><span class="hljs-built_in">print</span>(<span class="hljs-string">"猴⼦喜欢吃桃⼦"</span>)<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">SunWukong</span>(ShenXian, Monkey): <span class="hljs-comment"># 孙悟空是神仙, 同时也是⼀只猴 先继承哪个就先执行哪个类的同名方法</span><br><span class="hljs-keyword">pass</span><br><br>sxz = SunWukong() <span class="hljs-comment"># 孙悟空</span><br>sxz.chitao() <span class="hljs-comment"># 会吃桃⼦</span><br>sxz.fei() <span class="hljs-comment"># 会⻜</span><br><br><span class="hljs-built_in">print</span>(SunWukong.__mro__)<br></code></pre></td></tr></table></figure><h2 id="经典类的多继承">经典类的多继承</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>(<span class="hljs-title class_ inherited__">A</span>):<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span>(<span class="hljs-title class_ inherited__">A</span>):<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span>(B, C):<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">E</span>:<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">F</span>(D, E):<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">G</span>(F, D):<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">H</span>:<br><span class="hljs-keyword">pass</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span>(H, G):<br><span class="hljs-keyword">pass</span><br></code></pre></td></tr></table></figure><p>画图</p><p><img src="image-20220710085843154.png" alt="关系图"></p><p>在经典类中采⽤的是深度优先,遍历⽅案. 什么是深度优先. 就是⼀条路走到头. 然后再回来. 继续找下⼀ 个.</p><p>类的MRO(method resolution order): Foo-> H -> G -> F -> E -> D -> B -> A -> C.</p><h2 id="新式类的多继承">新式类的多继承</h2><h3 id="mro序列">mro序列</h3><p>MRO是一个有序列表L,在类被创建时就计算出来。</p><p>通用计算公式为:</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs stylus"><span class="hljs-function"><span class="hljs-title">mro</span><span class="hljs-params">(Child(Base1,Base2)</span></span>) = <span class="hljs-selector-attr">[ Child ]</span> + <span class="hljs-built_in">merge</span>( <span class="hljs-built_in">mro</span>(Base1), <span class="hljs-built_in">mro</span>(Base2), <span class="hljs-selector-attr">[Base1, Base2]</span> )(其中Child继承自Base1, Base2)<br></code></pre></td></tr></table></figure><p>如果继承至一个基类:class B(A)</p><p>这时B的mro序列为</p><figure class="highlight asciidoc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs asciidoc">mro( B ) = mro( B(A) )<br><span class="hljs-section">= [B] + merge( mro(A) + [A] )</span><br><span class="hljs-section">= [B] + merge( [A] + [A] )</span><br><span class="hljs-section">= [B,A]</span><br></code></pre></td></tr></table></figure><p>如果继承至多个基类:class B(A1, A2, A3 …)</p><p>这时B的mro序列</p><figure class="highlight asciidoc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs asciidoc">mro(B) = mro( B(A1, A2, A3 …) )<br><span class="hljs-section">= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )</span><br><span class="hljs-section">= ...</span><br></code></pre></td></tr></table></figure><p>计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。</p><h3 id="表头和表尾">表头和表尾</h3><p>表头:列表的第一个元素</p><p>表尾:列表中表头以外的元素集合(可以为空)</p><p>示例:列表:[A, B, C] 表头是A,表尾是B和C</p><h3 id="列表之间的-操作">列表之间的+操作</h3><p>[A] + [B] = [A, B]</p><p>merge操作示例:</p><p>如计算merge( [E,O], [C,E,F,O], [C] )</p><p>有三个列表 : ① ② ③</p><figure class="highlight mathematica"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs mathematica"><span class="hljs-number">1</span> <span class="hljs-variable">merge</span>不为空,取出第一个列表列表①的表头<span class="hljs-built_in">E</span>,进行判断<br>各个列表的表尾分别是<span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span>,<span class="hljs-built_in">E</span>在这些表尾的集合中,因而跳过当前当前列表<br><span class="hljs-number">2</span> 取出列表②的表头<span class="hljs-built_in">C</span>,进行判断<br><span class="hljs-built_in">C</span>不在各个列表的集合中,因而将<span class="hljs-built_in">C</span>拿出到<span class="hljs-variable">merge</span>外,并从所有表头删除<br><span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">)</span> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-punctuation">)</span><br><span class="hljs-number">3</span> 进行下一次新的<span class="hljs-variable">merge</span>操作 <span class="hljs-operator">......</span><br><span class="hljs-operator">---------------------</span><br></code></pre></td></tr></table></figure><p><img src="image-20220710090525745.png" alt="关系图"></p><p>计算mro(A)方式:</p><figure class="highlight mathematica"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs mathematica"><span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-variable">A</span><span class="hljs-punctuation">)</span> <span class="hljs-operator">=</span> <span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span> <span class="hljs-variable">A</span><span class="hljs-punctuation">(</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span><br><br>原式<span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">A</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-variable">B</span><span class="hljs-punctuation">)</span><span class="hljs-operator">,</span><span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">)</span><span class="hljs-operator">,</span><span class="hljs-punctuation">[</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">]</span> <span class="hljs-punctuation">)</span><br><br><span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-variable">B</span><span class="hljs-punctuation">)</span> <span class="hljs-operator">=</span> <span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span> <span class="hljs-variable">B</span><span class="hljs-punctuation">(</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">B</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-built_in">D</span><span class="hljs-punctuation">)</span><span class="hljs-operator">,</span> <span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-built_in">E</span><span class="hljs-punctuation">)</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-punctuation">]</span> <span class="hljs-punctuation">)</span> <span class="hljs-type">#</span> 多继承<br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">B</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-punctuation">]</span> <span class="hljs-punctuation">)</span> <span class="hljs-type">#</span> 单继承<span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-built_in">D</span><span class="hljs-punctuation">(</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">)</span><span class="hljs-punctuation">)</span><span class="hljs-operator">=</span><span class="hljs-punctuation">[</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">D</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-punctuation">]</span> <span class="hljs-punctuation">)</span> <span class="hljs-type">#</span> 拿出并删除<span class="hljs-built_in">D</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span><span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><br> <br><span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">)</span> <span class="hljs-operator">=</span> <span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span> <span class="hljs-built_in">C</span><span class="hljs-punctuation">(</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-built_in">E</span><span class="hljs-punctuation">)</span><span class="hljs-operator">,</span> <span class="hljs-variable">mro</span><span class="hljs-punctuation">(</span><span class="hljs-variable">F</span><span class="hljs-punctuation">)</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-punctuation">]</span> <span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-punctuation">]</span> <span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">F</span><span class="hljs-punctuation">]</span> <span class="hljs-punctuation">)</span> <span class="hljs-type">#</span> 跳过<span class="hljs-built_in">O</span>,拿出并删除<br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span><span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><br> <br>原式<span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">A</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">A</span><span class="hljs-operator">,</span><span class="hljs-variable">B</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">A</span><span class="hljs-operator">,</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">D</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">)</span> <span class="hljs-type">#</span> 跳过<span class="hljs-built_in">E</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">A</span><span class="hljs-operator">,</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">C</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span><span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">A</span><span class="hljs-operator">,</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span><span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">)</span> <span class="hljs-type">#</span> 跳过<span class="hljs-built_in">O</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">A</span><span class="hljs-operator">,</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-punctuation">]</span> <span class="hljs-operator">+</span> <span class="hljs-variable">merge</span><span class="hljs-punctuation">(</span><span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-operator">,</span> <span class="hljs-punctuation">[</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">)</span><br> <span class="hljs-operator">=</span> <span class="hljs-punctuation">[</span><span class="hljs-variable">A</span><span class="hljs-operator">,</span><span class="hljs-variable">B</span><span class="hljs-operator">,</span><span class="hljs-built_in">D</span><span class="hljs-operator">,</span><span class="hljs-built_in">C</span><span class="hljs-operator">,</span><span class="hljs-built_in">E</span><span class="hljs-operator">,</span><span class="hljs-variable">F</span><span class="hljs-operator">,</span><span class="hljs-built_in">O</span><span class="hljs-punctuation">]</span><br></code></pre></td></tr></table></figure><p><strong>python面向对象的三大特性:继承,封装,多态</strong></p><ol><li class="lvl-3"><p><strong>封装:</strong> 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜B的函数. 那这个也可以被称为封 装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装.</p></li><li class="lvl-3"><p><strong>继承:</strong> ⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容. 说⽩了, ⼉⼦可以随便⽤爹的东⻄. 但是朋友们, ⼀定要认清楚⼀个事情. 必须先有爹, 后有⼉⼦. 顺序不能乱, 在python中实现继承非常 简单. 在声明类的时候, 在类名后⾯添加⼀个⼩括号,就可以完成继承关系. 那么什么情况可以使⽤继 承呢? 单纯的从代码层⾯上来看. 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取 ⼀个⽗类, 这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的 好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中 出现了x是⼀种y. 这时, y是⼀种泛化的概念. x比y更加具体. 那这时x就是y的⼦类. 比如. 猫是⼀种动 物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的"动"这个属性. 再比如, ⽩骨 精是⼀个妖怪. 妖怪天⽣就有⼀个比较不好的功能叫"吃⼈", ⽩骨精⼀出⽣就知道如何"吃⼈". 此时 ⽩骨精继承妖怪.</p></li><li class="lvl-3"><p><strong>多态:</strong> 同⼀个对象, 多种形态. 这个在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没 有具体的说. 比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = “hello”, 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态。</p></li></ol>]]></content>
<summary type="html"><h1>面向对象的继承</h1>
<p><strong>面向对象三大特性</strong></p>
<p><strong>封装</strong> 根据 <strong>职责</strong> 将 <strong>属性</strong> 和 <strong>方法 封装</stron</summary>
<category term="Python" scheme="https://xiaolaji.site/categories/Python/"/>
<category term="Python学习" scheme="https://xiaolaji.site/tags/Python%E5%AD%A6%E4%B9%A0/"/>
</entry>
</feed>