-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
372 lines (319 loc) · 64.3 KB
/
atom.xml
File metadata and controls
372 lines (319 loc) · 64.3 KB
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Anniywell</title>
<link href="/atom.xml" rel="self"/>
<link href="https://anniywell.github.io/"/>
<updated>2017-06-23T06:50:47.148Z</updated>
<id>https://anniywell.github.io/</id>
<author>
<name>Anniywell</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Windows软件清单</title>
<link href="https://anniywell.github.io/2017/06/23/Windows%E8%BD%AF%E4%BB%B6%E6%B8%85%E5%8D%95/"/>
<id>https://anniywell.github.io/2017/06/23/Windows软件清单/</id>
<published>2017-06-23T06:17:09.000Z</published>
<updated>2017-06-23T06:50:47.148Z</updated>
<content type="html"><![CDATA[<h2 id="日常"><a href="#日常" class="headerlink" title="日常"></a>日常</h2><h3 id="浏览器"><a href="#浏览器" class="headerlink" title="浏览器"></a>浏览器</h3><p><a href="https://www.mozilla.org/en-US/firefox/all/" target="_blank" rel="external">Firefox国际版</a><br><a href="https://www.google.cn/chrome/browser/desktop/index.html" target="_blank" rel="external">Chrome</a><br><a href="https://vivaldi.com/download/" target="_blank" rel="external">Vivaldi</a></p>
<h3 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h3><p><a href="">迅雷极速版</a></p>
<h3 id="压缩归档"><a href="#压缩归档" class="headerlink" title="压缩归档"></a>压缩归档</h3><p><a href="http://www.7-zip.org/" target="_blank" rel="external">7-Zip</a></p>
<h3 id="编辑阅读"><a href="#编辑阅读" class="headerlink" title="编辑阅读"></a>编辑阅读</h3><p><a href="http://ep.wps.cn/product/wps-office-download.html" target="_blank" rel="external">WPS专业增强版</a><br><a href="https://www.sumatrapdfreader.org/download-free-pdf-viewer.html" target="_blank" rel="external">SumatraPDF</a></p>
<a id="more"></a>
<h3 id="输入法"><a href="#输入法" class="headerlink" title="输入法"></a>输入法</h3><p><a href="">搜狗拼音</a><br><a href="">Bing拼音</a><br><a href="">Google拼音</a></p>
<h3 id="音视频"><a href="#音视频" class="headerlink" title="音视频"></a>音视频</h3><p><a href="http://www.foobar2000.org/download" target="_blank" rel="external">foobar2000</a><br><a href="http://potplayer.daum.net/?lang=zh_CN" target="_blank" rel="external">PotPlayer</a></p>
<h3 id="截图"><a href="#截图" class="headerlink" title="截图"></a>截图</h3><p><a href="https://getsharex.com/" target="_blank" rel="external">ShareX</a></p>
<h3 id="邮件"><a href="#邮件" class="headerlink" title="邮件"></a>邮件</h3><p><a href="http://www.foxmail.com/" target="_blank" rel="external">Foxmail</a><br><a href="https://www.mozilla.org/zh-CN/thunderbird/" target="_blank" rel="external">Thunderbird</a><br><a href="https://www.microsoft.com/zh-cn/outlook-com/" target="_blank" rel="external">Outlook</a></p>
<h2 id="开发"><a href="#开发" class="headerlink" title="开发"></a>开发</h2><h3 id="编辑器"><a href="#编辑器" class="headerlink" title="编辑器"></a>编辑器</h3><p><a href="https://code.visualstudio.com/" target="_blank" rel="external">Visual Studio Code</a><br><a href="https://atom.io/" target="_blank" rel="external">Atom</a><br><a href="http://www.sublimetext.com/3" target="_blank" rel="external">Sublime Text 3</a></p>
<h3 id="IDE"><a href="#IDE" class="headerlink" title="IDE"></a>IDE</h3><p><a href="http://www.itellyou.cn/?esbwbc=caz8f2" target="_blank" rel="external">Visual Studio</a><br><a href="http://www.jetbrains.com/" target="_blank" rel="external">JetBrains全家桶</a><br><a href="http://mirrors.ustc.edu.cn/qtproject/official_releases/qtcreator/" target="_blank" rel="external">Qt Creator</a></p>
<h3 id="Markdown"><a href="#Markdown" class="headerlink" title="Markdown"></a>Markdown</h3><p><a href="http://pad.haroopress.com/user.html#download" target="_blank" rel="external">Haroopad</a></p>
<h3 id="VCS"><a href="#VCS" class="headerlink" title="VCS"></a>VCS</h3><p><a href="https://git-scm.com/" target="_blank" rel="external">git</a><br><a href="http://subversion.apache.org/" target="_blank" rel="external">svn</a><br><a href="https://www.sourcetreeapp.com/" target="_blank" rel="external">SourceTree</a><br><a href="http://www.syntevo.com/smartgit/download" target="_blank" rel="external">SmartGit</a><br><a href="https://tortoisesvn.net/downloads.html" target="_blank" rel="external">TortoiseSVN</a><br><a href="https://tortoisegit.org/download/" target="_blank" rel="external">TortoiseGit</a></p>
<h3 id="文件对比"><a href="#文件对比" class="headerlink" title="文件对比"></a>文件对比</h3><p><a href="http://www.scootersoftware.com/download.php" target="_blank" rel="external">Beyond Compare</a></p>
<h3 id="终端增强"><a href="#终端增强" class="headerlink" title="终端增强"></a>终端增强</h3><p><a href="http://cmder.net/" target="_blank" rel="external">cmder</a></p>
<h3 id="文件搜索"><a href="#文件搜索" class="headerlink" title="文件搜索"></a>文件搜索</h3><p><a href="http://www.listary.com/download" target="_blank" rel="external">Listary</a><br><a href="http://www.getwox.com/" target="_blank" rel="external">Wox</a></p>
<h3 id="文件管理"><a href="#文件管理" class="headerlink" title="文件管理"></a>文件管理</h3><p><a href="http://www.ghisler.com/" target="_blank" rel="external">Total Commander</a><br><a href="http://cn.ejie.me/" target="_blank" rel="external">Clover</a></p>
<h3 id="剪贴板"><a href="#剪贴板" class="headerlink" title="剪贴板"></a>剪贴板</h3><p><a href="http://ditto-cp.sourceforge.net/" target="_blank" rel="external">Ditto</a></p>
<h3 id="强制解锁"><a href="#强制解锁" class="headerlink" title="强制解锁"></a>强制解锁</h3><p><a href="">Unlocker</a></p>
<h3 id="网络抓包"><a href="#网络抓包" class="headerlink" title="网络抓包"></a>网络抓包</h3><p><a href="https://www.wireshark.org/download.html" target="_blank" rel="external">Wireshark</a><br><a href="http://www.telerik.com/fiddler" target="_blank" rel="external">Fiddler</a></p>
<h3 id="编译工具"><a href="#编译工具" class="headerlink" title="编译工具"></a>编译工具</h3><p><a href="http://www.msys2.org/" target="_blank" rel="external">MSYS2</a><br><a href="http://www.mingw.org/" target="_blank" rel="external">Mingw</a><br><a href="http://www.mingw-w64.org/doku.php/" target="_blank" rel="external">Mingw-w64</a><br><a href="http://www.cygwin.com/" target="_blank" rel="external">Cygwin</a><br><a href="https://cmake.org/" target="_blank" rel="external">CMake</a><br><a href="">GYP</a><br><a href="">Ninja</a><br><a href="https://www.microsoft.com/en-us/download/details.aspx?id=48159" target="_blank" rel="external">Microsoft Build Tools</a></p>
<h3 id="开发工具"><a href="#开发工具" class="headerlink" title="开发工具"></a>开发工具</h3><p><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html" target="_blank" rel="external">JDK</a><br><a href="https://www.python.org/downloads/" target="_blank" rel="external">Python</a><br><a href="https://nodejs.org/en/download/" target="_blank" rel="external">Node.js</a></p>
<h3 id="虚拟机"><a href="#虚拟机" class="headerlink" title="虚拟机"></a>虚拟机</h3><p><a href="https://www.virtualbox.org/" target="_blank" rel="external">VirtualBox</a><br><a href="https://www.genymotion.com/" target="_blank" rel="external">Genymotion</a></p>
<h3 id="代码阅读"><a href="#代码阅读" class="headerlink" title="代码阅读"></a>代码阅读</h3><p><a href="https://www.sourceinsight.com/" target="_blank" rel="external">Source Insight</a><br><a href="https://www.slickedit.com/" target="_blank" rel="external">SlickEdit</a><br><a href="https://scitools.com/" target="_blank" rel="external">Understand</a></p>
<h3 id="数据库访问"><a href="#数据库访问" class="headerlink" title="数据库访问"></a>数据库访问</h3><p><a href="https://www.navicat.com/en/products" target="_blank" rel="external">Navicat</a></p>
<h3 id="UML建模"><a href="#UML建模" class="headerlink" title="UML建模"></a>UML建模</h3><p><a href="">Enterprise Architect</a><br><a href="http://staruml.io/" target="_blank" rel="external">StarUML</a></p>
<h3 id="科学上网"><a href="#科学上网" class="headerlink" title="科学上网"></a>科学上网</h3><p><a href="https://laod.cn/hosts/" target="_blank" rel="external">Hosts</a><br><a href="https://github.com/getlantern/forum/issues/833" target="_blank" rel="external">lantern</a></p>
]]></content>
<summary type="html">
<h2 id="日常"><a href="#日常" class="headerlink" title="日常"></a>日常</h2><h3 id="浏览器"><a href="#浏览器" class="headerlink" title="浏览器"></a>浏览器</h3><p><a href="https://www.mozilla.org/en-US/firefox/all/" target="_blank" rel="external">Firefox国际版</a><br><a href="https://www.google.cn/chrome/browser/desktop/index.html" target="_blank" rel="external">Chrome</a><br><a href="https://vivaldi.com/download/" target="_blank" rel="external">Vivaldi</a></p>
<h3 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h3><p><a href="">迅雷极速版</a></p>
<h3 id="压缩归档"><a href="#压缩归档" class="headerlink" title="压缩归档"></a>压缩归档</h3><p><a href="http://www.7-zip.org/" target="_blank" rel="external">7-Zip</a></p>
<h3 id="编辑阅读"><a href="#编辑阅读" class="headerlink" title="编辑阅读"></a>编辑阅读</h3><p><a href="http://ep.wps.cn/product/wps-office-download.html" target="_blank" rel="external">WPS专业增强版</a><br><a href="https://www.sumatrapdfreader.org/download-free-pdf-viewer.html" target="_blank" rel="external">SumatraPDF</a></p>
</summary>
<category term="Software" scheme="https://anniywell.github.io/categories/Software/"/>
<category term="Software" scheme="https://anniywell.github.io/tags/Software/"/>
</entry>
<entry>
<title>Python协程</title>
<link href="https://anniywell.github.io/2017/06/23/Python%E5%8D%8F%E7%A8%8B/"/>
<id>https://anniywell.github.io/2017/06/23/Python协程/</id>
<published>2017-06-23T06:08:15.000Z</published>
<updated>2017-06-23T06:50:32.549Z</updated>
<content type="html"><![CDATA[<h2 id="协程简介"><a href="#协程简介" class="headerlink" title="协程简介"></a>协程简介</h2><p>协程,即协作式程序,又称微线程、纤程,英文名Coroutine。</p>
<p>其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态。协程可以在运行期间的某个点上暂停执行,并在恢复运行时从暂停的点上继续执行。<br>协程已经被证明是一种非常有用的程序组件,不仅被python、lua、ruby等脚本语言广泛采用,而且被新一代面向多核的编程语言如golang rust-lang等采用作为并发的基本单位。<br>协程可以被认为是一种用户空间线程,与传统的线程相比,有2个主要的优点:</p>
<ul>
<li>与线程不同,协程是自己主动让出CPU,并交付他期望的下一个协程运行,而不是在任何时候都有可能被系统调度打断。因此协程的使用更加清晰易懂,并且多数情况下不需要锁机制。</li>
<li>与线程相比,协程的切换由程序控制,发生在用户空间而非内核空间,因此切换的代价非常小。</li>
</ul>
<p>总结起来是一句话:协程可以认为是一种用户态线程,与系统提供的线程不同点是,它需要主动让出CPU时间,而不是由系统进行调度,即控制权在程序员手上。</p>
<h2 id="Python协程史"><a href="#Python协程史" class="headerlink" title="Python协程史"></a>Python协程史</h2><ul>
<li>Python 2.2 中的生成器让代码执行过程可以暂停 (yield)</li>
<li>Python 2.5 中可以将值返回给暂停的生成器,这使得 Python 中协程的概念成为可能 (send)</li>
<li>Python 3.3 中的 yield from,使得重构生成器与将它们串联起来都很简单 (yield from)</li>
<li>Python 3.4 以后通过标准库 asyncio 获得了事件循环的特性 (asyncio)</li>
<li>Python 3.5 使用async/await语法引入对协程的显式支持 (async/await)</li>
<li>Python 3.6 增强asyncio,支持异步生成器、异步解析式</li>
</ul>
<a id="more"></a>
<h2 id="yield"><a href="#yield" class="headerlink" title="yield"></a>yield</h2><p>为了理解什么是 yield, 你必须理解什么是生成器(generator)。</p>
<p>关于生成器我的理解是是:生成器保存的是算法,需要时再计算(惰性计算)</p>
<p>创建生成器有两种方式:</p>
<p>第一种方法:把一个列表生成式的[]改成(),就创建了一个generator:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">l = [x * x <span class="keyword">for</span> x <span class="keyword">in</span> range(<span class="number">10</span>)] <span class="comment"># l [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]</span></div><div class="line">g = (x * x <span class="keyword">for</span> x <span class="keyword">in</span> range(<span class="number">10</span>)) <span class="comment"># g <generator object <genexpr> at 0x1022ef630></span></div></pre></td></tr></table></figure>
<p>第二种方式:在函数中使用yield关键字,函数就变成了一个generator。</p>
<p>函数里有了yield后,执行到yield就会停住,当需要再往下算时才会再往下算。所以生成器函数即使是有无限循环也没关系,它需要算到多少就会算多少,不需要就不往下算。</p>
<p>例如你想要自己实现一个 range() 函数,你可以用立即计算的方式创建一个整数列表:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">eager_range</span><span class="params">(up_to)</span>:</span></div><div class="line"> <span class="string">"""Create a list of integers, from 0 to up_to, exclusive."""</span></div><div class="line"> sequence = []</div><div class="line"> index = <span class="number">0</span></div><div class="line"> <span class="keyword">while</span> index < up_to:</div><div class="line"> sequence.append(index)</div><div class="line"> index += <span class="number">1</span></div><div class="line"> <span class="keyword">return</span> sequence</div><div class="line"></div><div class="line">l = eager_range(<span class="number">1000000</span>)</div></pre></td></tr></table></figure>
<p>然而这里存在的问题是,如果你想创建从0到1,000,000这样一个很大的序列,你不得不创建能容纳1,000,000个整数的列表。<br>但是当加入了生成器之后,你可以不用创建完整的序列,你只需要能够每次保存一个整数的内存即可。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">lazy_range</span><span class="params">(up_to)</span>:</span></div><div class="line"> <span class="string">"""Generator to return the sequence of integers from 0 to up_to, exclusive."""</span></div><div class="line"> index = <span class="number">0</span></div><div class="line"> <span class="keyword">while</span> index < up_to:</div><div class="line"> <span class="keyword">yield</span> index</div><div class="line"> index += <span class="number">1</span></div><div class="line"></div><div class="line">g = lazy_range(<span class="number">1000000</span>) <span class="comment"># <generator object lazy_range at 0x040A25D0></span></div><div class="line">next(g)</div><div class="line">...</div><div class="line">...</div><div class="line">...</div><div class="line">next(g)</div><div class="line">Traceback (most recent call last):</div><div class="line"> File <span class="string">"<stdin>"</span>, line <span class="number">1</span>, <span class="keyword">in</span> <module></div><div class="line">StopIteration</div></pre></td></tr></table></figure>
<p>让函数遇到 yield 表达式时暂停执行 – 虽然在 Python 2.5 以前它只是一条语句 – 并且能够在后面重新执行,这对于减少内存使用、生成无限序列非常有用。</p>
<p>你有可能已经发现,生成器完全就是关于迭代器的。有一种更好的方式生成迭代器当然很好(尤其是当你可以给一个生成器对象添加 <strong>iter</strong>() 方法时),<br>但是人们知道,如果可以利用生成器“暂停”的部分,添加“将东西发送回生成器”的功能,那么 Python 突然就有了协程的概念(当然这里的协程仅限于 Python 中的概念;Python 中真实的协程在后面才会讨论)。<br>将东西发送回暂停了的生成器这一特性通过 PEP 342添加到了 Python 2.5。<br>与其它特性一起,PEP 342 为生成器引入了 send() 方法。这让我们不仅可以暂停生成器,而且能够传递值到生成器暂停的地方。<br>还是以我们的 range() 为例,你可以让序列向前或向后跳过几个值:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">jumping_range</span><span class="params">(up_to)</span>:</span></div><div class="line"> <span class="string">"""Generator for the sequence of integers from 0 to up_to, exclusive.</span></div><div class="line"> Sending a value into the generator will shift the sequence by that amount.</div><div class="line"> """</div><div class="line"> index = <span class="number">0</span></div><div class="line"> <span class="keyword">while</span> index < up_to:</div><div class="line"> jump = <span class="keyword">yield</span> index</div><div class="line"> <span class="keyword">if</span> jump <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line"> jump = <span class="number">1</span></div><div class="line"> index += jump</div><div class="line"></div><div class="line">iterator = jumping_range(<span class="number">5</span>)</div><div class="line">print(next(iterator)) <span class="comment"># 0</span></div><div class="line">print(iterator.send(<span class="number">2</span>)) <span class="comment"># 2</span></div><div class="line">print(next(iterator)) <span class="comment"># 3</span></div><div class="line">print(iterator.send(<span class="number">-1</span>)) <span class="comment"># 2</span></div><div class="line"><span class="keyword">for</span> x <span class="keyword">in</span> iterator:</div><div class="line"> print(x) <span class="comment"># 3, 4</span></div></pre></td></tr></table></figure>
<p>其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。</p>
<p>因此,我们可以看做next(g) == g.send(None)</p>
<p>需要注意的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错,因为没有yield语句来接收这个值。</p>
<h2 id="yield-from"><a href="#yield-from" class="headerlink" title="yield from"></a>yield from</h2><p>在PEP 380 为 Python 3.3 添加了 yield from之前,生成器都没有变动。<br>严格来说,这一特性让你能够从迭代器(生成器刚好也是迭代器)中返回任何值,从而可以干净利索的方式重构生成器。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">yield</span> <span class="keyword">from</span> iterator</div><div class="line"><span class="comment"># (本质上)相当于:</span></div><div class="line"><span class="keyword">for</span> x <span class="keyword">in</span> iterator:</div><div class="line"> <span class="keyword">yield</span> x</div></pre></td></tr></table></figure>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">lazy_range</span><span class="params">(up_to)</span>:</span></div><div class="line"> <span class="string">"""Generator to return the sequence of integers from 0 to up_to, exclusive."""</span></div><div class="line"> index = <span class="number">0</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">gratuitous_refactor</span><span class="params">()</span>:</span></div><div class="line"> <span class="keyword">while</span> index < up_to:</div><div class="line"> <span class="keyword">yield</span> index</div><div class="line"> index += <span class="number">1</span></div><div class="line"> <span class="keyword">yield</span> <span class="keyword">from</span> gratuitous_refactor()</div></pre></td></tr></table></figure>
<p>yield from 通过让重构变得简单,也让你能够将生成器串联起来,使返回值可以在调用栈中上下浮动,而不需对编码进行过多改动。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">bottom</span><span class="params">()</span>:</span></div><div class="line"> <span class="string">"""Returning the yield lets the value that goes up the call stack to come right back down"""</span></div><div class="line"> <span class="keyword">return</span> (<span class="keyword">yield</span> <span class="number">42</span>)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">middle</span><span class="params">()</span>:</span></div><div class="line"> <span class="keyword">return</span> (<span class="keyword">yield</span> <span class="keyword">from</span> bottom())</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">top</span><span class="params">()</span>:</span></div><div class="line"> <span class="keyword">return</span> (<span class="keyword">yield</span> <span class="keyword">from</span> middle())</div><div class="line"></div><div class="line"><span class="comment"># Get the generator.</span></div><div class="line">gen = top()</div><div class="line">value = next(gen)</div><div class="line">print(value) <span class="comment"># Prints '42'.</span></div><div class="line"><span class="keyword">try</span>:</div><div class="line"> value = gen.send(value * <span class="number">2</span>)</div><div class="line"><span class="keyword">except</span> StopIteration <span class="keyword">as</span> exc:</div><div class="line"> value = exc.value</div><div class="line">print(value) <span class="comment"># Prints '84'.</span></div></pre></td></tr></table></figure>
<h2 id="asyncio"><a href="#asyncio" class="headerlink" title="asyncio"></a>asyncio</h2><p>asyncio是一个基于事件循环的异步I/O库,Python3.4将其引入标准库,Python3.3可通过pip安装</p>
<p>asyncio包括的内容很多很复杂,这里只会做基本的两点:协同程序和事件循环。</p>
<p>协程的基本概念前面已经讲过,这里先来说一下事件循环</p>
<p>通俗来说,事件循环 “是一种等待程序分配事件或消息的编程架构”,其提供一种循环机制,让你可以“在A发生时,执行B”。基本上来说事件循环就是监听当有什么发生时,同时事件循环也关心这件事并执行相应的代码,本质上是以队列的方式来重新分配时间片。</p>
<p>在asyncio中事件循环扮演的是个调度器的角色,被用来安排协同程序的执行。</p>
<p>PEP 342中通过asyncio.coroutine装饰的函数为协程,这里的协程是和asyncio及其事件循环一起使用的。</p>
<p>这赋予了 Python 第一个对于协程的明确定义,也就是基于生成器的协程</p>
<p>这意味着突然之间所有实现了协程接口的生成器,即便它们并不是要以协程方式应用,都符合这一定义。为了修正这一点,asyncio 要求所有要用作协程的生成器必须由asyncio.coroutine修饰。</p>
<p>使用以下语法声明生成器协程:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@asyncio.coroutine</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">generator_coroutine</span><span class="params">()</span>:</span></div><div class="line"> <span class="keyword">pass</span></div><div class="line"></div><div class="line">a = generator_coroutine()</div><div class="line">print(a) <span class="comment"># <generator object coro at 0x040F0B48></span></div></pre></td></tr></table></figure>
<p>yield from在asyncio模块中得以发扬光大。通过yield from,我们可以用asyncio.sleep将协程控制权交给事件循环,然后挂起当前协程;之后,由事件循环决定何时唤醒asyncio.sleep,接着向后执行代码。<br>先看示例代码:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> asyncio</div><div class="line"></div><div class="line"><span class="meta">@asyncio.coroutine</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">countdown</span><span class="params">(number, n)</span>:</span></div><div class="line"> <span class="keyword">while</span> n > <span class="number">0</span>:</div><div class="line"> print(<span class="string">'T-minus'</span>, n, <span class="string">'({})'</span>.format(number))</div><div class="line"> <span class="keyword">yield</span> <span class="keyword">from</span> asyncio.sleep(<span class="number">1</span>)</div><div class="line"> n -= <span class="number">1</span></div><div class="line"></div><div class="line">loop = asyncio.get_event_loop()</div><div class="line">tasks = [</div><div class="line"> asyncio.ensure_future(countdown(<span class="string">"A"</span>, <span class="number">2</span>)),</div><div class="line"> asyncio.ensure_future(countdown(<span class="string">"B"</span>, <span class="number">3</span>))]</div><div class="line">loop.run_until_complete(asyncio.wait(tasks))</div><div class="line">loop.close()</div></pre></td></tr></table></figure>
<p>在解释上面例子之前,需要先简单了解一下asyncio.Future</p>
<p>Future可以理解为延迟结果的抽象,在其他语言中也称作Promise.<br>你可以对任何asyncio.Future对象使用 yield from,从而将其传递给事件循环,暂停协程的执行来等待某些事情的发生( future 对象并不重要,只是asyncio细节的实现)。<br>一旦 future 对象获取了事件循环,它会一直在那里监听,直到完成它需要做的一切。<br>当 future 完成自己的任务之后,事件循环会察觉到,暂停并等待在那里的协程会通过send()方法获取future对象的返回值并开始继续执行。</p>
<p>以上面的代码为例, 事件循环启动每一个 countdown() 协程,一直执行到遇见其中一个协程的 yield from 和 asyncio.sleep() 。这样会返回一个 asyncio.Future对象并将其传递给事件循环,同时暂停这一协程的执行。事件循环会监控这一future对象,直到倒计时1秒钟之后(同时也会检查其它正在监控的对象,比如像其它协程)。1秒钟的时间一到,事件循环会选择刚刚传递了future对象并暂停了的 countdown() 协程,将future对象的结果返回给协程,然后协程可以继续执行。这一过程会一直持续到所有的 countdown() 协程执行完毕,事件循环也被清空。稍后我会给你展示一个完整的例子,用来说明协程/事件循环之类的这些东西究竟是如何运作的,但是首先我想要解释一下async和await。</p>
<p>关于asyncio这里只做了简单的介绍,它其实包括以下内容,大家可以去查看<a href="https://docs.python.org/3/library/asyncio.html?highlight=asyncio#module-asyncio" target="_blank" rel="external">官方文档</a>:</p>
<ul>
<li>事件循环</li>
<li>任务和协程</li>
<li>传输和协议</li>
<li>基于协程的流</li>
<li>子进程</li>
<li>同步原语</li>
<li>队列</li>
</ul>
<h2 id="async与await"><a href="#async与await" class="headerlink" title="async与await"></a>async与await</h2><p>PEP 492引入async/await语法,中明确了协程类型(原生协程),用于区别于基于生成器的协程</p>
<p>在以前,我们可以用生成器实现协程(PEP 342),后来又对其进行了改进,引入了yield from语法(PEP 380)。但仍有一些缺点:</p>
<ol>
<li>协程和普通生成器使用相同的语法,所以很容易把它们搞混,初学者更是如此。</li>
<li>一个函数是否是一个协程,取决于它里面是否出现了yield或yield from语句。这并不明显,容易在重构函数的时候搞乱,导致出错。</li>
<li>异步调用被yield语法限制了,我们不能获得、使用更多的语法特性,比如with和for。</li>
</ol>
<p>这个PEP把协程从生成器独立出来,成为Python的一个原生事物。这会消除协程和生成器之间的混淆,方便编写不依赖特定库的协程代码。</p>
<p>使用以下语法声明原生协程:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">def</span> <span class="title">native_coroutine</span><span class="params">()</span>:</span></div><div class="line"> <span class="keyword">pass</span></div><div class="line"></div><div class="line">a = native_coroutine()</div><div class="line">print(a) <span class="comment"># <coroutine object a at 0x000000000567EFC0></span></div></pre></td></tr></table></figure>
<p>原生协程语法的关键点:</p>
<ul>
<li>async def函数必定是协程,即使里面不含有await语句。</li>
<li>如果在async函数里面使用yield或yield from语句,会引发SyntaxError异常。</li>
<li>协程在调用时会返回一个coroutine对象</li>
<li>协程不再抛出StopIteration异常,而是替代为RuntimeError</li>
<li>当协程进行垃圾回收时,一个从未被await的协程会抛出RuntimeWarning异常</li>
</ul>
<p><strong>await</strong>表达式</p>
<p>下面新的await表达式用于获取协程执行结果:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">def</span> <span class="title">read_data</span><span class="params">(db)</span>:</span></div><div class="line"> data = <span class="keyword">await</span> db.fetch(<span class="string">'SELECT ...'</span>)</div><div class="line"> <span class="keyword">pass</span></div></pre></td></tr></table></figure>
<p>await与yield from相似,挂起read_data协程的执行直到db.fetch这个awaitable对象完成并返回结果数据。</p>
<p>原生协程与生成器协程的区别与联系</p>
<ul>
<li>原生协程对象不实现<strong>iter</strong>和<strong>next</strong>方法。因此,他们不能够通过iter(),list(),tuple()和其他一些内置函数进行迭代。他们也不能用于for…in循环。在原生协程中尝试使用<strong>iter</strong>或者__next会触发TypeError异常。</li>
<li>未被装饰的生成器不能够yield from一个原生协程:这样会引发TypeError。</li>
<li>基于生成器的协程(asyncio代码必须使用@asyncio.coroutine)可以yield from一个原生协程。</li>
<li>对原生协程对象和原生协程函数调用inspect.isgenerator()和inspect.isgeneratorfunction()会返回False。</li>
<li>协程内部基于生成器,原生协程与生成器协程共享实现过程。类似于生成器对象,原生协程包含throw(),send()和close()方法。</li>
</ul>
<h2 id="异步生成器与异步解析式"><a href="#异步生成器与异步解析式" class="headerlink" title="异步生成器与异步解析式"></a>异步生成器与异步解析式</h2><p>PEP 492 引入支持原生协程和async /await的语法到Python 3.5。 在Python 3.5实现里的一个值得注意的局限性就在于它不可能使用await和yield在同一个函数体中。<br>而在Python 3.6中,这个限制已解除,这使得定义异步生成器成为可能:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">def</span> <span class="title">ticker</span><span class="params">(delay, to)</span>:</span></div><div class="line"> <span class="string">"""Yield numbers from 0 to *to* every *delay* seconds."""</span></div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(to):</div><div class="line"> <span class="keyword">yield</span> i</div><div class="line"> <span class="keyword">await</span> asyncio.sleep(delay)</div></pre></td></tr></table></figure>
<p>PEP 530 添加了对async for在list、set、dict解析式以及generator表达式中的使用支持:</p>
<pre><code>result = [i async for i in aiter() if i % 2]
</code></pre><p>此外,所有解析式都支持“await”表达式:</p>
<pre><code>result = [await fun() for fun in funcs if await condition()]
</code></pre><h2 id="gevent"><a href="#gevent" class="headerlink" title="gevent"></a>gevent</h2><p>gevent是一个基于协同的Python网络库,它使用greenlet在libev事件循环之上提供高级同步API。</p>
<p>主要特性:</p>
<ul>
<li>基于libev的快速事件循环</li>
<li>基于greenlet的轻量级执行单元</li>
<li>重用python标准api(event,queue)</li>
<li>协同的socket和ssl模块</li>
<li>使用标准库和第三方模块写标准阻塞socket(gevent.monkey)</li>
<li>通过线程池或c-ares执行的DNS查询。</li>
<li>内置TCP/UDP/HTTP服务器</li>
<li>支持子进程(gevent.subprocess)</li>
<li>支持线程池</li>
</ul>
<p>下面简单介绍gevent的使用</p>
<p><img src="http://xlambda.com/gevent-tutorial/flow.gif" alt="gevent-flow"></p>
<p>gevent.spawn(function, <em>args, **kwargs)<br>创建一个新的Greenlet对象并安排它运行function(</em>args,**kwargs)</p>
<p>注意:这时function还没有启动,它的运行依赖于gevent的事件循环,只有启动事件循环,它才会被调度</p>
<p>gevent.sleep(seconds=0)</p>
<p>将当前的greenlet睡眠seconds秒</p>
<p>使用gevent.sleep相当于切换上下文,让出执行权</p>
<p>gevent.joinall</p>
<p>等待多个greenlet执行结束</p>
<p>有时需要知道greenlet运行的状态,在greenlet中有一些标志, 让你可以监视它的线程内部状态:</p>
<ul>
<li>started – Boolean, 指示此Greenlet是否已经启动</li>
<li>ready() – Boolean, 指示此Greenlet是否已经停止</li>
<li>successful() – Boolean, 指示此Greenlet是否已经停止而且没抛异常</li>
<li>value – 任意值, 此Greenlet代码返回的值</li>
<li>exception – 异常, 此Greenlet内抛出的未捕获异常</li>
</ul>
<p>更多<a href="http://www.gevent.org/gevent.html#module-gevent" target="_blank" rel="external">gevent api</a>介绍</p>
<h2 id="参考文档"><a href="#参考文档" class="headerlink" title="参考文档"></a>参考文档</h2><ul>
<li><a href="https://docs.python.org/3/library/asyncio.html" target="_blank" rel="external">Python官方文档</a></li>
<li><a href="https://www.python.org/dev/peps/pep-0255/" target="_blank" rel="external">PEP 255 – Simple Generators</a></li>
<li><a href="https://www.python.org/dev/peps/pep-0342/" target="_blank" rel="external">PEP 342 – Coroutines via Enhanced Generators</a></li>
<li><a href="https://www.python.org/dev/peps/pep-0380/" target="_blank" rel="external">PEP 380 – Syntax for Delegating to a Subgenerator</a></li>
<li><a href="https://www.python.org/dev/peps/pep-3156/" target="_blank" rel="external">PEP 3156 – Asynchronous IO Support Rebooted: the “asyncio” Module</a></li>
<li><a href="https://www.python.org/dev/peps/pep-0492/" target="_blank" rel="external">PEP 492 – Coroutines with async and await syntax</a></li>
<li><a href="http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000" target="_blank" rel="external">廖雪峰Python教程</a></li>
<li><a href="https://www.python.org/dev/peps/pep-0525/" target="_blank" rel="external">PEP 525</a></li>
<li><a href="https://www.python.org/dev/peps/pep-0530/" target="_blank" rel="external">PEP 530</a></li>
<li><a href="https://github.com/SimonXming/my-blog/issues/23" target="_blank" rel="external">Python 3.5协程原理</a></li>
<li><a href="http://www.gevent.org/contents.html" target="_blank" rel="external">gevent官方文档</a></li>
<li><a href="http://sdiehl.github.io/gevent-tutorial/" target="_blank" rel="external">gevent教程</a></li>
</ul>
]]></content>
<summary type="html">
<h2 id="协程简介"><a href="#协程简介" class="headerlink" title="协程简介"></a>协程简介</h2><p>协程,即协作式程序,又称微线程、纤程,英文名Coroutine。</p>
<p>其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态。协程可以在运行期间的某个点上暂停执行,并在恢复运行时从暂停的点上继续执行。<br>协程已经被证明是一种非常有用的程序组件,不仅被python、lua、ruby等脚本语言广泛采用,而且被新一代面向多核的编程语言如golang rust-lang等采用作为并发的基本单位。<br>协程可以被认为是一种用户空间线程,与传统的线程相比,有2个主要的优点:</p>
<ul>
<li>与线程不同,协程是自己主动让出CPU,并交付他期望的下一个协程运行,而不是在任何时候都有可能被系统调度打断。因此协程的使用更加清晰易懂,并且多数情况下不需要锁机制。</li>
<li>与线程相比,协程的切换由程序控制,发生在用户空间而非内核空间,因此切换的代价非常小。</li>
</ul>
<p>总结起来是一句话:协程可以认为是一种用户态线程,与系统提供的线程不同点是,它需要主动让出CPU时间,而不是由系统进行调度,即控制权在程序员手上。</p>
<h2 id="Python协程史"><a href="#Python协程史" class="headerlink" title="Python协程史"></a>Python协程史</h2><ul>
<li>Python 2.2 中的生成器让代码执行过程可以暂停 (yield)</li>
<li>Python 2.5 中可以将值返回给暂停的生成器,这使得 Python 中协程的概念成为可能 (send)</li>
<li>Python 3.3 中的 yield from,使得重构生成器与将它们串联起来都很简单 (yield from)</li>
<li>Python 3.4 以后通过标准库 asyncio 获得了事件循环的特性 (asyncio)</li>
<li>Python 3.5 使用async/await语法引入对协程的显式支持 (async/await)</li>
<li>Python 3.6 增强asyncio,支持异步生成器、异步解析式</li>
</ul>
</summary>
<category term="Python" scheme="https://anniywell.github.io/categories/Python/"/>
<category term="Python" scheme="https://anniywell.github.io/tags/Python/"/>
<category term="协程" scheme="https://anniywell.github.io/tags/%E5%8D%8F%E7%A8%8B/"/>
</entry>
<entry>
<title>浅析Python元类及应用</title>
<link href="https://anniywell.github.io/2017/06/16/%E6%B5%85%E6%9E%90Python%E5%85%83%E7%B1%BB%E5%8F%8A%E5%BA%94%E7%94%A8/"/>
<id>https://anniywell.github.io/2017/06/16/浅析Python元类及应用/</id>
<published>2017-06-16T07:28:36.000Z</published>
<updated>2017-06-16T10:19:59.113Z</updated>
<content type="html"><![CDATA[<h2 id="写这篇文章的缘由"><a href="#写这篇文章的缘由" class="headerlink" title="写这篇文章的缘由"></a>写这篇文章的缘由</h2><p>前几天去一家公司面试,面试的岗位是Python后台开发,面试中被问到了一道题,考虑很久想不到答案,顾回来查阅资料在此总结一下。<br>题目的描述是这样的:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">SQLAlchemy中Model中定义类成员时,如何做到声明顺序与数据库表的列顺序一致</div><div class="line">提示:普通类成员是存储在__dict__,而dict本身是无序的</div></pre></td></tr></table></figure></p>
<p>通过阅读SQLAlchemy源码得知,其内部实现是使用元类编程来完成的,元类编程是Python的一种高级黑暗魔法,经常听其大名,并没有进入深入了解,借此机会稍微总结一下。</p>
<h2 id="元编程"><a href="#元编程" class="headerlink" title="元编程"></a>元编程</h2><p>元编程我个人理解是:<strong>用代码生成(操纵)代码</strong>的编程手法。<br>Python中元编程的几种手段:</p>
<ul>
<li>预定义方法</li>
<li>函数赋值</li>
<li>descriptor</li>
<li>eval</li>
<li>元类</li>
</ul>
<p>上面的几种方式相对于元类来说简单一些,这里暂时先不讲了,以后有时间再去补充<br><a id="more"></a></p>
<h2 id="元类"><a href="#元类" class="headerlink" title="元类"></a>元类</h2><h3 id="类也是对象"><a href="#类也是对象" class="headerlink" title="类也是对象"></a>类也是对象</h3><p>在Python中一切皆对象,同样“类”也是对象<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="meta">>>> </span><span class="class"><span class="keyword">class</span> <span class="title">OneClass</span>:</span></div><div class="line"><span class="meta">... </span> <span class="keyword">pass</span></div><div class="line">...</div><div class="line"><span class="meta">>>> </span>OneClass</div><div class="line"><<span class="class"><span class="keyword">class</span> '<span class="title">__main__</span>.<span class="title">OneClass</span>'></span></div></pre></td></tr></table></figure></p>
<p>当你在定义一个class时,会在内存中一个对象,对象的名字就是类的名字。<br><strong>这个对象(类)自身拥有创建对象(类实例)的能力,而这就是为什么它是一个类的原因</strong></p>
<h3 id="动态的创建类"><a href="#动态的创建类" class="headerlink" title="动态的创建类"></a>动态的创建类</h3><p>最简单的动态创建方式是将类的定义写在逻辑判断中,不同条件生成不同的类,但这还不够动态,你仍然需要自己去编写整个类的代码。如果想要更动态的创建方式,那我们先来了解一个Python的内建函数<strong>type</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">class type(object): # 当传入一个参数时,返回该对象的类型</div><div class="line">class type(name, bases, dict) # 创建新类型,name-类名,bases-父类元组,dict-属性字典</div></pre></td></tr></table></figure></p>
<p>了解到这里,我们就可以用type动态创建class了,比如:<br><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">>>> A = type('A', (), {})</div><div class="line">>>> A</div><div class="line"><class '__main__.A'></div><div class="line">>>> B = type('B', (), {'b': True})</div><div class="line">>>> B</div><div class="line"><class '__main__.B'></div><div class="line">>>> C = type('C', (B,), {'c': False})</div><div class="line">>>> C</div><div class="line"><class '__main__.C'></div><div class="line">>>> c = C()</div><div class="line">>>> c.b</div><div class="line">True</div><div class="line">>>> c.c</div><div class="line">False</div><div class="line">>>></div></pre></td></tr></table></figure></p>
<p>现在我们终于接触到元类了,上面使用的type就是元类,type就是Python在背后用来创建所有类的元类。为了证明这一点我们可以使用<strong>class</strong>来验证一下:<br><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">>>> class AA:</div><div class="line">... pass</div><div class="line">...</div><div class="line">>>> def func():</div><div class="line">... pass</div><div class="line">...</div><div class="line">>>> var = 3</div><div class="line">>>> AA.__class__</div><div class="line"><class 'type'></div><div class="line">>>> AA.__class__.__class__</div><div class="line"><class 'type'></div><div class="line">>>> func.__class__</div><div class="line"><class 'function'></div><div class="line">>>> func.__class__.__class__</div><div class="line"><class 'type'></div><div class="line">>>> var.__class__</div><div class="line"><class 'int'></div><div class="line">>>> var.__class__.__class__</div><div class="line"><class 'type'></div></pre></td></tr></table></figure></p>
<h3 id="自定义元类"><a href="#自定义元类" class="headerlink" title="自定义元类"></a>自定义元类</h3><p>除了使用Python内建的type元类外,我们还可以使用metaclass来控制类的创建行为,如:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ListMetaclass</span><span class="params">(type)</span>:</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__new__</span><span class="params">(cls, name, bases, attrs)</span>:</span></div><div class="line"> attrs[<span class="string">'add'</span>] = <span class="keyword">lambda</span> self, value: self.append(value)</div><div class="line"> <span class="keyword">return</span> type.__new__(cls, name, bases, attrs)</div><div class="line"></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyList</span><span class="params">(list, metaclass=ListMetaclass)</span>:</span></div><div class="line"> <span class="keyword">pass</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="meta">>>> </span>L = MyList()</div><div class="line"><span class="meta">>>> </span>L.add(<span class="number">1</span>)</div><div class="line">>> L</div><div class="line">[<span class="number">1</span>]</div></pre></td></tr></table></figure></p>
<p>回归开篇的那道题目,实现大致是这样的:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> collections <span class="keyword">import</span> OrderedDict</div><div class="line"></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">OrderedClass</span><span class="params">(type)</span>:</span></div><div class="line"><span class="meta"> @classmethod</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__prepare__</span><span class="params">(mcs, name, bases)</span>:</span></div><div class="line"> <span class="keyword">return</span> OrderedDict()</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__new__</span><span class="params">(cls, name, bases, classdict)</span>:</span></div><div class="line"> result = type.__new__(cls, name, bases, dict(classdict))</div><div class="line"> result.__fields__ = list(classdict.keys())</div><div class="line"> <span class="keyword">return</span> result</div><div class="line"></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Column</span>:</span></div><div class="line"> <span class="keyword">pass</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyClass</span><span class="params">(metaclass=OrderedClass)</span>:</span></div><div class="line"> mycol2 = Column()</div><div class="line"> mycol3 = Column()</div><div class="line"> zut = Column()</div><div class="line"> cool = Column()</div><div class="line"> menfin = Column()</div><div class="line"> a = Column()</div><div class="line"></div><div class="line"></div><div class="line">print(MyClass.__fields__)</div></pre></td></tr></table></figure></p>
<p>在元类中使用<strong>prepare</strong>返回有序字典来存储类成员定义,在元类中创建类,并将有序的属性名赋值给类的<strong>fields</strong>,通过访问<strong>fields</strong>得到与定义顺序相同的属性名称。<br>想了解更多可以看一下<a href="https://www.python.org/dev/peps/pep-3115/" target="_blank" rel="external">PEP 3115 – Metaclasses in Python 3000</a><br>另外,关于类属性定义顺序问题,在Python3.6已经改成默认有序了,详情参考<a href="https://www.python.org/dev/peps/pep-0520/" target="_blank" rel="external">PEP 520 – Preserving Class Attribute Definition Order</a></p>
<h2 id="究竟为什么要使用元类?"><a href="#究竟为什么要使用元类?" class="headerlink" title="究竟为什么要使用元类?"></a>究竟为什么要使用元类?</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters</div></pre></td></tr></table></figure>
<p>元类的主要用途是创建API,一个典型的应用就是数据库的ORM,通过一个class来映射成一张table,通过一个对象来映射成一行数据,将原本复杂的代码变的很简介,这些很多都是元类的功劳。</p>
]]></content>
<summary type="html">
<h2 id="写这篇文章的缘由"><a href="#写这篇文章的缘由" class="headerlink" title="写这篇文章的缘由"></a>写这篇文章的缘由</h2><p>前几天去一家公司面试,面试的岗位是Python后台开发,面试中被问到了一道题,考虑很久想不到答案,顾回来查阅资料在此总结一下。<br>题目的描述是这样的:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">SQLAlchemy中Model中定义类成员时,如何做到声明顺序与数据库表的列顺序一致</div><div class="line">提示:普通类成员是存储在__dict__,而dict本身是无序的</div></pre></td></tr></table></figure></p>
<p>通过阅读SQLAlchemy源码得知,其内部实现是使用元类编程来完成的,元类编程是Python的一种高级黑暗魔法,经常听其大名,并没有进入深入了解,借此机会稍微总结一下。</p>
<h2 id="元编程"><a href="#元编程" class="headerlink" title="元编程"></a>元编程</h2><p>元编程我个人理解是:<strong>用代码生成(操纵)代码</strong>的编程手法。<br>Python中元编程的几种手段:</p>
<ul>
<li>预定义方法</li>
<li>函数赋值</li>
<li>descriptor</li>
<li>eval</li>
<li>元类</li>
</ul>
<p>上面的几种方式相对于元类来说简单一些,这里暂时先不讲了,以后有时间再去补充<br>
</summary>
<category term="Python" scheme="https://anniywell.github.io/categories/Python/"/>
<category term="Python" scheme="https://anniywell.github.io/tags/Python/"/>
<category term="元编程" scheme="https://anniywell.github.io/tags/%E5%85%83%E7%BC%96%E7%A8%8B/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="https://anniywell.github.io/2017/06/16/hello-world/"/>
<id>https://anniywell.github.io/2017/06/16/hello-world/</id>
<published>2017-06-16T00:38:45.178Z</published>
<updated>2017-06-16T03:22:09.875Z</updated>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo new <span class="string">"My New Post"</span></div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a><br><a id="more"></a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo server</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="external">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo generate</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="external">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo deploy</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="external">Deployment</a></p>
]]></content>
<summary type="html">
<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo new <span class="string">"My New Post"</span></div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a><br>
</summary>
</entry>
<entry>
<title>My blog</title>
<link href="https://anniywell.github.io/2017/06/16/My-blog/"/>
<id>https://anniywell.github.io/2017/06/16/My-blog/</id>
<published>2017-06-15T16:59:11.000Z</published>
<updated>2017-06-16T03:21:10.923Z</updated>
<content type="html"><![CDATA[<h2 id="关于博客"><a href="#关于博客" class="headerlink" title="关于博客"></a>关于博客</h2><p>此blog是基于hexo-theme-even修改而来,目前已经托管到我个人的github仓库中,后面会持续更新。</p>
<h2 id="博客内容"><a href="#博客内容" class="headerlink" title="博客内容"></a>博客内容</h2><p>以技术学习与分享为主,主要关注:</p>
<ol>
<li>Web全栈</li>
<li>JavaScript</li>
<li>Node.js</li>
<li>Python3</li>
<li>Swift</li>
<li><hr>
</li>
</ol>
]]></content>
<summary type="html">
<h2 id="关于博客"><a href="#关于博客" class="headerlink" title="关于博客"></a>关于博客</h2><p>此blog是基于hexo-theme-even修改而来,目前已经托管到我个人的github仓库中,后面会持续更新。</p>
</summary>
<category term="Hexo" scheme="https://anniywell.github.io/categories/Hexo/"/>
<category term="hexo" scheme="https://anniywell.github.io/tags/hexo/"/>
<category term="blog" scheme="https://anniywell.github.io/tags/blog/"/>
</entry>
</feed>