-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
951 lines (786 loc) · 172 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
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Eason's Blog</title>
<link href="/atom.xml" rel="self"/>
<link href="http://superway117.github.io/"/>
<updated>2018-09-17T04:42:10.661Z</updated>
<id>http://superway117.github.io/</id>
<author>
<name>Eason Pan</name>
<email>[email protected]</email>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>mongoose findOneAndUpdate</title>
<link href="http://superway117.github.io/2017/03/15/findOneAndUpdate/"/>
<id>http://superway117.github.io/2017/03/15/findOneAndUpdate/</id>
<published>2017-03-15T01:09:44.000Z</published>
<updated>2018-09-17T04:42:10.661Z</updated>
<content type="html"><![CDATA[<p><code>mongoose</code> <code>findOneAndUpdate</code>的用法</p>
<p>Mongoose supports this natively with <a href="http://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate" target="_blank" rel="external">findOneAndUpdate</a> , it calls MongoDB <a href="https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/" target="_blank" rel="external">findAndModify</a>.</p>
<h2 id="参数"><a href="#参数" class="headerlink" title="参数"></a>参数</h2><p><code>upsert</code></p>
<p>if true, it creates the object if it doesn’t exist. defaults to false.</p>
<p><code>new</code></p>
<p>if true, returns the modified document rather than the original. The findAndModify() method ignores the new option for remove operations. The default is false.</p>
<h2 id="update-操作"><a href="#update-操作" class="headerlink" title="update 操作"></a>update 操作</h2><p><a href="https://docs.mongodb.com/manual/reference/operator/update/#id1" target="_blank" rel="external">mongodb update</a></p>
<p><code>$setOnInsert</code></p>
<p>Sets the value of a field if an update results in an insert of a document. Has no effect on update operations that modify existing documents.</p>
<p>也就是说新增才会写</p>
<p><code>mongoose</code>里面用<code>setDefaultsOnInsert</code></p>
<p><a href="http://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate" target="_blank" rel="external">setDefaultsOnInsert</a>: if this and upsert are true, mongoose will apply the defaults specified in the model’s schema if a new document is created. This option only works on MongoDB >= 2.4 because it relies on MongoDB’s $setOnInsert operator.</p>
<p>如果要用这个选项的,需要的model的地方配置默认值</p>
<p><code>$set</code></p>
<p>Sets the value of a field in a document.</p>
<h2 id="Sample"><a href="#Sample" class="headerlink" title="Sample"></a>Sample</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">Model.findByIdAndUpdate(id, { $set: { name: 'jason borne' }}, options, callback)</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p><code>mongoose</code> <code>findOneAndUpdate</code>的用法</p>
<p>Mongoose supports this natively with <a href="http://mongoosejs.com/docs/ap
</summary>
<category term="mongodb" scheme="http://superway117.github.io/tags/mongodb/"/>
</entry>
<entry>
<title>Adminlte Usage</title>
<link href="http://superway117.github.io/2017/03/08/adminlte-usage/"/>
<id>http://superway117.github.io/2017/03/08/adminlte-usage/</id>
<published>2017-03-08T01:40:09.000Z</published>
<updated>2018-09-17T04:42:59.994Z</updated>
<content type="html"><![CDATA[<h1 id="sidebar"><a href="#sidebar" class="headerlink" title="sidebar"></a>sidebar</h1><p><code>sidebar-mini</code>: sidebar只显示图片,不设置它,就是图片文字都显示</p>
<figure class="highlight plain"><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"><body class="hold-transition skin-blue sidebar-mini"></div><div class="line"></body></div><div class="line">`</div></pre></td></tr></table></figure>
<p><code>sidebar-collapse</code>: sidebar初始是收缩状态</p>
<figure class="highlight plain"><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"><body class="hold-transition skin-blue sidebar-collapse"></div><div class="line"></body></div><div class="line">`</div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<h1 id="sidebar"><a href="#sidebar" class="headerlink" title="sidebar"></a>sidebar</h1><p><code>sidebar-mini</code>: sidebar只显示图片,不设置它,就是图片文
</summary>
<category term="css" scheme="http://superway117.github.io/tags/css/"/>
</entry>
<entry>
<title>如何在ng-repeat里面,每隔3个元素换行</title>
<link href="http://superway117.github.io/2017/03/02/angular_row_4/"/>
<id>http://superway117.github.io/2017/03/02/angular_row_4/</id>
<published>2017-03-02T04:27:14.000Z</published>
<updated>2018-09-17T04:42:45.410Z</updated>
<content type="html"><![CDATA[<p>problem:</p>
<p>如何在ng-repeat里面,每隔3个元素换行</p>
<p>solution:</p>
<figure class="highlight plain"><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"><div class="row"></div><div class="line"> <div ng-repeat="product in products"></div><div class="line"> <div class="clearfix" ng-if="$index % 3 == 0"></div></div><div class="line"> <div class="col-sm-4"></div><div class="line"> <h2>{{product.title}}</h2></div><div class="line"> </div></div><div class="line"> </div></div><div class="line"></div></div></pre></td></tr></table></figure>
<h2 id="reference"><a href="#reference" class="headerlink" title="reference"></a>reference</h2><p><a href="http://stackoverflow.com/questions/27211799/angular-ng-repeat-add-bootstrap-row-every-3-or-4-cols" target="_blank" rel="external">stackoverflow</a></p>
]]></content>
<summary type="html">
<p>problem:</p>
<p>如何在ng-repeat里面,每隔3个元素换行</p>
<p>solution:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div clas
</summary>
<category term="angularjs" scheme="http://superway117.github.io/tags/angularjs/"/>
</entry>
<entry>
<title>flex-layout</title>
<link href="http://superway117.github.io/2017/02/23/flex_layout/"/>
<id>http://superway117.github.io/2017/02/23/flex_layout/</id>
<published>2017-02-23T15:40:49.000Z</published>
<updated>2017-02-23T16:21:53.819Z</updated>
<content type="html"><![CDATA[<h2 id="reference"><a href="#reference" class="headerlink" title="reference"></a>reference</h2><p>flexboxfroggy</p>
<ul>
<li><a href="https://github.com/thomaspark/flexboxfroggy" target="_blank" rel="external">github</a></li>
<li><a href="http://flexboxfroggy.com/" target="_blank" rel="external">game</a></li>
</ul>
<p>阮一峰</p>
<ul>
<li><a href="http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool" target="_blank" rel="external">Flex 布局教程:语法篇</a></li>
<li><a href="http://www.ruanyifeng.com/blog/2015/07/flex-examples.html" target="_blank" rel="external">Flex 布局教程:实例篇</a></li>
<li><a href="http://codepen.io/LandonSchropp/pen/KpzzGo" target="_blank" rel="external">demo</a></li>
</ul>
<p>张鑫旭</p>
<ul>
<li><a href="http://www.zhangxinxu.com/wordpress/2010/12/css-box-flex%E5%B1%9E%E6%80%A7%EF%BC%8C%E7%84%B6%E5%90%8E%E5%BC%B9%E6%80%A7%E7%9B%92%E5%AD%90%E6%A8%A1%E5%9E%8B%E7%AE%80%E4%BB%8B/" target="_blank" rel="external">CSS box-flex属性,然后弹性盒子模型简介</a></li>
</ul>
<p>xiaoxiangzi</p>
<ul>
<li><a href="http://www.xiaoxiangzi.com/Programme/CSS/2540.html" target="_blank" rel="external">CSS3 Flexbox可视化指南</a></li>
</ul>
]]></content>
<summary type="html">
<h2 id="reference"><a href="#reference" class="headerlink" title="reference"></a>reference</h2><p>flexboxfroggy</p>
<ul>
<li><a href="https:
</summary>
<category term="css" scheme="http://superway117.github.io/tags/css/"/>
</entry>
<entry>
<title>Python numpy Index</title>
<link href="http://superway117.github.io/2017/01/16/py_numpy_index/"/>
<id>http://superway117.github.io/2017/01/16/py_numpy_index/</id>
<published>2017-01-16T02:32:09.000Z</published>
<updated>2017-01-16T03:14:28.848Z</updated>
<content type="html"><![CDATA[<p>In Python, x[(exp1, exp2, …, expN)] is equivalent to x[exp1, exp2, …, expN]; the latter is just syntactic sugar for the former.</p>
<p>numpy.newaxis</p>
<p>The newaxis object can be used in all slicing operations to create an axis of length one. :const: newaxis is an alias for ‘None’, and ‘None’ can be used in place of this with the same result.</p>
<p><a href="https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#numpy.newaxis" target="_blank" rel="external">numpy.newaxis</a></p>
<h2 id="Basic-Slicing-and-Indexing"><a href="#Basic-Slicing-and-Indexing" class="headerlink" title="Basic Slicing and Indexing"></a>Basic Slicing and Indexing</h2><p><code>格式</code></p>
<blockquote>
<blockquote>
<blockquote>
<p>Basic slicing occurs when obj is a slice object (constructed by start:stop:step notation inside of brackets), an integer, or a tuple of slice objects and integers. </p>
</blockquote>
</blockquote>
</blockquote>
<p>也就是说<code>slice</code>,<code>integer</code>,<code>tuple of slice objects and integers</code>, 这样的index我们称为<code>Basic Slicing</code></p>
<h2 id="Advanced-Indexing"><a href="#Advanced-Indexing" class="headerlink" title="Advanced Indexing"></a>Advanced Indexing</h2>]]></content>
<summary type="html">
<p>In Python, x[(exp1, exp2, …, expN)] is equivalent to x[exp1, exp2, …, expN]; the latter is just syntactic sugar for the former.</p>
<p>nu
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python numpy shape</title>
<link href="http://superway117.github.io/2017/01/13/py_numpy_shape/"/>
<id>http://superway117.github.io/2017/01/13/py_numpy_shape/</id>
<published>2017-01-13T06:32:13.000Z</published>
<updated>2017-01-13T07:41:53.033Z</updated>
<content type="html"><![CDATA[<figure class="highlight plain"><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">In [52]: x3 = np.random.randint(10, size=(3, 4, 5))</div><div class="line"></div><div class="line">In [53]: x3</div><div class="line">Out[53]:</div><div class="line">array([[[1, 7, 4, 7, 5],</div><div class="line"> [3, 5, 9, 4, 3],</div><div class="line"> [6, 9, 4, 1, 4],</div><div class="line"> [2, 0, 8, 9, 4]],</div><div class="line"></div><div class="line"> [[8, 6, 8, 7, 6],</div><div class="line"> [1, 7, 8, 7, 1],</div><div class="line"> [4, 8, 6, 5, 7],</div><div class="line"> [9, 0, 2, 7, 9]],</div><div class="line"></div><div class="line"> [[6, 6, 6, 2, 1],</div><div class="line"> [6, 5, 7, 5, 9],</div><div class="line"> [5, 0, 8, 8, 1],</div><div class="line"> [4, 7, 0, 6, 1]]])</div></pre></td></tr></table></figure>
<figure class="highlight plain"><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></pre></td><td class="code"><pre><div class="line">In [57]: x3.ndim</div><div class="line">Out[57]: 3</div><div class="line"></div><div class="line">In [58]: x3.shape</div><div class="line">Out[58]: (3L, 4L, 5L)</div><div class="line"></div><div class="line">In [59]: x3.size</div><div class="line">Out[59]: 60</div><div class="line"></div><div class="line">In [61]: x3.strides</div><div class="line">Out[61]: (80L, 20L, 4L)</div></pre></td></tr></table></figure>
<p><code>ndim</code> : the number of dimensions,也就是维度, 上面的<code>x3</code>就是一个3维数组.</p>
<p><code>shape</code>: the size of each dimension, 可以认为是数组的形状,每一维的大小.</p>
<p><code>size</code> : total size of the array, 这个<code>size</code>是指元素的个数: 3<em>4</em>5==60</p>
<p><code>strides</code>:</p>
<ul>
<li>每个轴上面相邻元素的地址差. 上面的例子(80L, 20L, 4L), 其中80==20*4,最后一个轴的元素size就是4(int).</li>
<li>numpy在数据存储上面支持C语言的方式:连续的内存存储空间,也支持Fortan的方式.默认是C语言.</li>
</ul>
<p><code>numpy.ndarray.flags</code> 描述了数组的内存layout信息. </p>
<figure class="highlight plain"><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">In [63]: x3.flags</div><div class="line">Out[63]:</div><div class="line"> C_CONTIGUOUS : True</div><div class="line"> F_CONTIGUOUS : False</div><div class="line"> OWNDATA : True</div><div class="line"> WRITEABLE : True</div><div class="line"> ALIGNED : True</div><div class="line"> UPDATEIFCOPY : False</div></pre></td></tr></table></figure>
<ul>
<li><code>C_CONTIGUOUS</code>就是C语言的存储方式</li>
<li><code>F_CONTIGUOUS</code>就是Fortan语言的存储方式</li>
<li><code>ALIGNED</code>,C语言里面要内存对其,就存在padding的问题,这个true就表示完全follow C语言做内存对其</li>
<li><code>OWNDATA</code>, 如果是view的话,这里就是false.</li>
</ul>
<h3 id="reference"><a href="#reference" class="headerlink" title="reference"></a>reference</h3><ul>
<li><a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.flags.html" target="_blank" rel="external">numpy.ndarray.flags</a></li>
</ul>
]]></content>
<summary type="html">
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</di
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python Sphinx</title>
<link href="http://superway117.github.io/2017/01/12/py_Sphinx/"/>
<id>http://superway117.github.io/2017/01/12/py_Sphinx/</id>
<published>2017-01-12T08:52:21.000Z</published>
<updated>2017-01-12T09:07:43.938Z</updated>
<content type="html"><![CDATA[<ul>
<li>Sphinx是一个静态网站生成器,可以用来做静态网站或者写文档</li>
<li>Sphinx基于reStructuredText,markdown语法,配置文件就是py文件: conf.py</li>
<li>Sphinx支持Python 2.6+, 3.3+.</li>
</ul>
<p>For full documentation visit <a href="http://www.sphinx-doc.org/en/latest" target="_blank" rel="external">sphinx-doc</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><p>Install</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pip install Sphinx</div></pre></td></tr></table></figure>
<p>Start a new project</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sphinx-quickstart</div></pre></td></tr></table></figure>
<p>执行这个命令后,会step by step的生成一个工程,同时conf.py就生成了.同时根目录下面会生成一个make.bat文件(window下面),后面我们就可以通过这个make.bat来生成页面或者发布了.</p>
<p>make.bat支持多种格式,比如html,epub,json,latex,singlehtml. 支持列表可以敲入下面的命令查看.</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">make.bat help</div></pre></td></tr></table></figure>
<p>通过下面的命令生成网页</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">make.bat html</div></pre></td></tr></table></figure>
<p>这个命令等同于</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sphinx-build -b html sourcedir builddir</div></pre></td></tr></table></figure>
<h2 id="Theme"><a href="#Theme" class="headerlink" title="Theme"></a>Theme</h2><p>在conf.py修改theme</p>
<figure class="highlight plain"><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">html_theme = "classic"</div><div class="line">html_theme_options = {</div><div class="line"> "rightsidebar": "true",</div><div class="line"> "relbarbgcolor": "black"</div><div class="line">}</div></pre></td></tr></table></figure>
<p>参考页面<a href="http://www.sphinx-doc.org/en/latest/theming.html" target="_blank" rel="external">theming</a></p>
<h4 id="sphinx-rtd-theme"><a href="#sphinx-rtd-theme" class="headerlink" title="sphinx_rtd_theme"></a>sphinx_rtd_theme</h4><p>scrapy和readthedocs都是采用的<code>sphinx_rtd_theme</code>,效果参考<a href="http://doc.scrapy.org/en/1.1/index.html" target="_blank" rel="external">scrapy doc页面</a>或者<a href="http://docs.readthedocs.io/en/latest/" target="_blank" rel="external">readthedocs</a></p>
<p>install</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pip install sphinx_rtd_theme</div></pre></td></tr></table></figure>
<p>usage</p>
<figure class="highlight plain"><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">import sphinx_rtd_theme</div><div class="line"></div><div class="line">html_theme = "sphinx_rtd_theme"</div><div class="line"></div><div class="line">html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]</div></pre></td></tr></table></figure>
<h3 id="支持Markdown"><a href="#支持Markdown" class="headerlink" title="支持Markdown"></a>支持Markdown</h3><p>支持Markdown,简单说需要2步:</p>
<ol>
<li><p>安装Markdown解析工具</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pip install recommonmark.parser</div></pre></td></tr></table></figure>
</li>
<li><p>修改conf.py告诉sphinx支持Markdown</p>
<figure class="highlight plain"><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></pre></td><td class="code"><pre><div class="line">from recommonmark.parser import CommonMarkParser</div><div class="line"></div><div class="line">默认只支持rst后缀文件</div><div class="line">source_suffix = '.rst'</div><div class="line"> 改成</div><div class="line">source_parsers = {'.md': CommonMarkParser}</div><div class="line"> source_suffix = ['.rst', '.md']</div></pre></td></tr></table></figure>
</li>
</ol>
<h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ul>
<li><p><code>scrapinghub</code> </p>
<ul>
<li>scrapinghub 文档,rst格式</li>
<li><a href="https://github.com/scrapinghub/doc.scrapinghub.com" target="_blank" rel="external">source link</a></li>
<li><a href="http://doc.scrapinghub.com/" target="_blank" rel="external">doc link</a></li>
</ul>
</li>
<li><p><code>readthedocs</code> </p>
<ul>
<li>readthedocs 文档,rst格式</li>
<li><a href="http://docs.readthedocs.io/en/latest/" target="_blank" rel="external">doc link</a></li>
</ul>
</li>
<li><p><code>scrapy</code> </p>
<ul>
<li>scrapy 文档,rst格式</li>
<li><a href="https://github.com/scrapy/scrapy/tree/master/docs" target="_blank" rel="external">source link</a></li>
<li><a href="http://doc.scrapy.org/en/1.1/" target="_blank" rel="external">doc link</a></li>
</ul>
</li>
</ul>
]]></content>
<summary type="html">
<ul>
<li>Sphinx是一个静态网站生成器,可以用来做静态网站或者写文档</li>
<li>Sphinx基于reStructuredText,markdown语法,配置文件就是py文件: conf.py</li>
<li>Sphinx支持Python 2.6+, 3.3+
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python namedtuple</title>
<link href="http://superway117.github.io/2017/01/11/py_namedtuple/"/>
<id>http://superway117.github.io/2017/01/11/py_namedtuple/</id>
<published>2017-01-10T16:43:38.000Z</published>
<updated>2017-01-11T05:40:02.924Z</updated>
<content type="html"><![CDATA[<p><code>tuple</code>只能用index来获取对应位置的值,也就是0,1,2,3 这种形式对代码可读性,可维护性都不是很好.</p>
<p>很多时候我们需要用类似<code>dict</code>的方式来取值. 这个时候就需要<code>namedtuple</code></p>
<p><code>namedtuple</code>某种意义上就是一个文本的模板,帮助你定义一个<code>tuple</code>的子类.</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Point = namedtuple(<span class="string">'Point'</span>, [<span class="string">'x'</span>, <span class="string">'y'</span>], verbose=<span class="keyword">True</span>)</div></pre></td></tr></table></figure>
<p>就相当于定义了一个类<code>Point</code></p>
<p>下面的代码关键在于 <code>__dict__ = _property(_asdict)</code>,他定义了一个<code>dict</code>,这样我们才可以实现用名字来获取值.</p>
<p>另外因为用到了<code>__slots__</code>,这个是为了节省memory, 所以大胆的用<code>namedtuple</code>,开销不是很大.</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><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Point</span><span class="params">(tuple)</span>:</span></div><div class="line"> <span class="string">'Point(x, y)'</span></div><div class="line"></div><div class="line"> __slots__ = ()</div><div class="line"></div><div class="line"> _fields = (<span class="string">'x'</span>, <span class="string">'y'</span>)</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, x, y)</span>:</span></div><div class="line"> <span class="string">'Create new instance of Point(x, y)'</span></div><div class="line"> <span class="keyword">return</span> _tuple.__new__(_cls, (x, y))</div><div class="line"></div><div class="line"><span class="meta"> @classmethod</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">_make</span><span class="params">(cls, iterable, new=tuple.__new__, len=len)</span>:</span></div><div class="line"> <span class="string">'Make a new Point object from a sequence or iterable'</span></div><div class="line"> result = new(cls, iterable)</div><div class="line"> <span class="keyword">if</span> len(result) != <span class="number">2</span>:</div><div class="line"> <span class="keyword">raise</span> TypeError(<span class="string">'Expected 2 arguments, got %d'</span> % len(result))</div><div class="line"> <span class="keyword">return</span> result</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(self)</span>:</span></div><div class="line"> <span class="string">'Return a nicely formatted representation string'</span></div><div class="line"> <span class="keyword">return</span> <span class="string">'Point(x=%r, y=%r)'</span> % self</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">_asdict</span><span class="params">(self)</span>:</span></div><div class="line"> <span class="string">'Return a new OrderedDict which maps field names to their values'</span></div><div class="line"> <span class="keyword">return</span> OrderedDict(zip(self._fields, self))</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">_replace</span><span class="params">(_self, **kwds)</span>:</span></div><div class="line"> <span class="string">'Return a new Point object replacing specified fields with new values'</span></div><div class="line"> result = _self._make(map(kwds.pop, (<span class="string">'x'</span>, <span class="string">'y'</span>), _self))</div><div class="line"> <span class="keyword">if</span> kwds:</div><div class="line"> <span class="keyword">raise</span> ValueError(<span class="string">'Got unexpected field names: %r'</span> % kwds.keys())</div><div class="line"> <span class="keyword">return</span> result</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__getnewargs__</span><span class="params">(self)</span>:</span></div><div class="line"> <span class="string">'Return self as a plain tuple. Used by copy and pickle.'</span></div><div class="line"> <span class="keyword">return</span> tuple(self)</div><div class="line"></div><div class="line"> __dict__ = _property(_asdict)</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__getstate__</span><span class="params">(self)</span>:</span></div><div class="line"> <span class="string">'Exclude the OrderedDict from pickling'</span></div><div class="line"> <span class="keyword">pass</span></div><div class="line"></div><div class="line"> x = _property(_itemgetter(<span class="number">0</span>), doc=<span class="string">'Alias for field number 0'</span>)</div><div class="line"></div><div class="line"> y = _property(_itemgetter(<span class="number">1</span>), doc=<span class="string">'Alias for field number 1'</span>)</div></pre></td></tr></table></figure>
<h2 id="usage"><a href="#usage" class="headerlink" title="usage"></a>usage</h2><figure class="highlight plain"><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></pre></td><td class="code"><pre><div class="line">Point = namedtuple('Point', ['x', 'y'], verbose=True)</div><div class="line"></div><div class="line">>>> p = Point(11, y=22) # instantiate with positional or keyword arguments</div><div class="line">>>> p[0] + p[1] # indexable like the plain tuple (11, 22)</div><div class="line">33</div><div class="line">>>> x, y = p # unpack like a regular tuple</div><div class="line">>>> x, y</div><div class="line">(11, 22)</div><div class="line">>>> p.x + p.y # fields also accessible by name</div><div class="line">33</div><div class="line">>>> p # readable __repr__ with a name=value style</div><div class="line">Point(x=11, y=22)</div></pre></td></tr></table></figure>
<p>另外注意<code>_fields</code>的用法,他直接返回了原始的<code>tuple</code></p>
<h2 id="reference"><a href="#reference" class="headerlink" title="reference"></a>reference</h2><ul>
<li><a href="https://docs.python.org/2/library/collections.html?highlight=namedtuple#collections.namedtuple" target="_blank" rel="external">collections.namedtuple</a></li>
<li>Python cookbook 1.18. Mapping Names to Sequence Elements</li>
</ul>
]]></content>
<summary type="html">
<p><code>tuple</code>只能用index来获取对应位置的值,也就是0,1,2,3 这种形式对代码可读性,可维护性都不是很好.</p>
<p>很多时候我们需要用类似<code>dict</code>的方式来取值. 这个时候就需要<code>namedtuple</
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python Private Variables</title>
<link href="http://superway117.github.io/2016/12/31/py_private_variables/"/>
<id>http://superway117.github.io/2016/12/31/py_private_variables/</id>
<published>2016-12-31T11:11:33.000Z</published>
<updated>2016-12-31T15:52:11.332Z</updated>
<content type="html"><![CDATA[<p>Python是不支持<code>Private</code>关键字的.Python通过2种形式来支持private.</p>
<h2 id="约定俗成"><a href="#约定俗成" class="headerlink" title="约定俗成"></a>约定俗成</h2><p>如果一个成员是以一个下划线开头(有且只有一个),这种情况是python里面约定俗成的私有变量. 但是注意 python语法上没有对他做任何处理, 这只是一个编码习惯.</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></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span>:</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></div><div class="line"> self._internal = <span class="number">0</span> <span class="comment"># An internal attribute</span></div><div class="line"> self.public = <span class="number">1</span> <span class="comment"># A public attribute</span></div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">public_method</span><span class="params">(self)</span>:</span></div><div class="line"> <span class="string">'''</span></div><div class="line"> A public method</div><div class="line"> '''</div><div class="line"> ...</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">_internal_method</span><span class="params">(self)</span>:</span></div></pre></td></tr></table></figure>
<h2 id="name-mangling"><a href="#name-mangling" class="headerlink" title="name mangling"></a>name mangling</h2><p>如果成员是以两个下划线开头,且结尾<strong>至多</strong>一个下划线,这种类成员python是会做一个重命名的, <code>__spam</code>,python会改出: <code>_classname__spam</code>.</p>
<p>python设计这样的东西,是为了阻止继承的类<code>oeverridden</code>这样的属性.</p>
<p>下面是从python cookbook里面copy出来的.</p>
<blockquote>
<p>At this point, you might ask what purpose<br>such name mangling serves. The answer is inheritance—such attributes cannot be<br>overridden via inheritance</p>
</blockquote>
<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><div class="line">20</div></pre></td><td class="code"><pre><div class="line">class B:</div><div class="line"> def __init__(self):</div><div class="line"> self.__private = 0 -->相当于__B_private</div><div class="line"> def __private_method(self):</div><div class="line"> </div><div class="line"> def public_method(self):</div><div class="line"> ...</div><div class="line"></div><div class="line"> self.__private_method() -->相当于__B_private_method</div><div class="line"> ...</div><div class="line"></div><div class="line"></div><div class="line">class C(B):</div><div class="line"> def __init__(self):</div><div class="line"> super().__init__()</div><div class="line"></div><div class="line"> self.__private = 1 # Does not override B.__private</div><div class="line"></div><div class="line"> # Does not override B.__private_method()</div><div class="line"> def __private_method(self): -->相当于__C_private_method</div></pre></td></tr></table></figure>
<p>下面是<code>werkzeug\local.py</code>的code. 主要注意的是<code>object.__setattr__</code>用的是转换后的名字<code>_LocalProxy__local</code></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">object.__setattr__(self, <span class="string">'_LocalProxy__local'</span>, local)</div></pre></td></tr></table></figure>
<h2 id="references"><a href="#references" class="headerlink" title="references"></a>references</h2><ul>
<li><a href="https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references" target="_blank" rel="external">Private Variables and Class-local References</a></li>
<li><a href="http://blog.csdn.net/zsuguangh/article/details/6207469" target="_blank" rel="external">关于Python的class的私有变量扎压 Python的命名机制</a></li>
<li>Python Cookbook 8.5. Encapsulating Names in a Class</li>
</ul>
]]></content>
<summary type="html">
<p>Python是不支持<code>Private</code>关键字的.Python通过2种形式来支持private.</p>
<h2 id="约定俗成"><a href="#约定俗成" class="headerlink" title="约定俗成"></a>约定俗成</h2
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>hexo draft</title>
<link href="http://superway117.github.io/2016/12/29/hexo_draft/"/>
<id>http://superway117.github.io/2016/12/29/hexo_draft/</id>
<published>2016-12-29T08:10:57.000Z</published>
<updated>2016-12-29T08:17:46.166Z</updated>
<content type="html"><![CDATA[<h2 id="如果文章写了一半-想设置成draft怎么办"><a href="#如果文章写了一半-想设置成draft怎么办" class="headerlink" title="如果文章写了一半,想设置成draft怎么办?"></a>如果文章写了一半,想设置成draft怎么办?</h2><ol>
<li>看看<code>source/_drafts</code>存在否,不存在,创建一个</li>
<li>把相关文章<code>xx.md</code>和<code>xx目录</code>扔进去就行,是mv不是cp</li>
</ol>
<h2 id="直接创建一个draft"><a href="#直接创建一个draft" class="headerlink" title="直接创建一个draft"></a>直接创建一个draft</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">hexo new draft "new draft"</div></pre></td></tr></table></figure>
<p>这个命令也就是相关文件创建在<code>source/_drafts</code>,默认是创建在<code>source/_posts</code></p>
<h2 id="强行显示draft"><a href="#强行显示draft" class="headerlink" title="强行显示draft"></a>强行显示draft</h2><p><code>__config.yml</code>里面修改:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">render_drafts: true</div></pre></td></tr></table></figure>
<p>或者启动server的时候加参数</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">hexo server --drafts</div></pre></td></tr></table></figure>
<h2 id="发布draft"><a href="#发布draft" class="headerlink" title="发布draft"></a>发布draft</h2><p>下面的命令可以发布,未验证,事实上, <code>publish</code>我从来就没用过</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">hexo publish [layout] <filename></div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h2 id="如果文章写了一半-想设置成draft怎么办"><a href="#如果文章写了一半-想设置成draft怎么办" class="headerlink" title="如果文章写了一半,想设置成draft怎么办?"></a>如果文章写了一半,想设置成draft怎么办?
</summary>
<category term="hexo" scheme="http://superway117.github.io/tags/hexo/"/>
</entry>
<entry>
<title>Python descriptor</title>
<link href="http://superway117.github.io/2016/12/23/py_descriptor/"/>
<id>http://superway117.github.io/2016/12/23/py_descriptor/</id>
<published>2016-12-23T03:12:41.000Z</published>
<updated>2016-12-23T09:17:47.770Z</updated>
<content type="html"><![CDATA[<p><code>descriptor</code>应该算的上是python的黑魔法了,不了解这个东西,很多源码估计看的头晕脑胀的.</p>
<h2 id="Definition-and-Introduction"><a href="#Definition-and-Introduction" class="headerlink" title="Definition and Introduction"></a>Definition and Introduction</h2><p>In general, a descriptor is an object attribute with “binding behavior”, one whose attribute access has been overridden by methods in the descriptor protocol. Those methods are <strong>get</strong>(), <strong>set</strong>(), and <strong>delete</strong>(). If any of those methods are defined for an object, it is said to be a descriptor.</p>
<p>对属性的访问,通常是指set,get,delete操作, 比如 <code>a.x</code>,默认情况下,会follow下面的次序访问<code>a.x</code>:</p>
<ul>
<li>查找 <code>a.__dict__['x']</code>是否存在,如果存在,直接返回,不存在下一步</li>
<li>查找 <code>type(a).__dict__['x']</code>是否存在,如果存在,直接返回,不存在下一步</li>
<li>查找 <code>base classes of type(a)</code> excluding metaclasses</li>
</ul>
<p>上面的是默认的行为, 如果<code>a.x</code>,其中<code>x</code>是一个<code>descriptor</code>(只要定义了其中一个函数就算),走的就是另外的流程</p>
<blockquote>
<p>Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods were defined. Note that descriptors are only invoked for new style objects or classes (a class is new style if it inherits from object or type).</p>
</blockquote>
<p>需要注意的是<code>descriptor</code>必须继承<code>object</code>或者<code>type</code></p>
<blockquote>
<p> Note that descriptors are only invoked for new style objects or classes (a class is new style if it inherits from object or type).</p>
<p>Descriptors are a powerful, general purpose protocol. They are the mechanism behind properties, methods, static methods, class methods, and super(). They are used throughout Python itself to implement the new style classes introduced in version 2.2. Descriptors simplify the underlying C-code and offer a flexible set of new tools for everyday Python programs.</p>
</blockquote>
<h2 id="Descriptor-Protocol"><a href="#Descriptor-Protocol" class="headerlink" title="Descriptor Protocol"></a>Descriptor Protocol</h2><p>其实就3个函数,只要定义了下面的3个函数(至少一个),这个类就认为是<code>descriptor</code></p>
<figure class="highlight plain"><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">descr.__get__(self, obj, type=None) --> value</div><div class="line"></div><div class="line">descr.__set__(self, obj, value) --> None</div><div class="line"></div><div class="line">descr.__delete__(self, obj) --> None</div></pre></td></tr></table></figure>
<p><code>descriptor</code>: 定义了protocol里面任意一个函数,就认为是一个<code>descriptor</code> </p>
<p><code>data descriptor</code>: 定义了<strong>get</strong>() and <strong>set</strong>(),就被认为是<code>data descriptor</code></p>
<p><code>read-only data descriptor</code>: define both <strong>get</strong>() and <strong>set</strong>() with the <strong>set</strong>() raising an AttributeError when called</p>
<p><code>non-data descriptors</code>: only define <strong>get</strong>() are called <code>non-data descriptors</code></p>
<h2 id="Invoking-Descriptors"><a href="#Invoking-Descriptors" class="headerlink" title="Invoking Descriptors"></a>Invoking Descriptors</h2><p>如果<code>obj.d</code>, 其中<code>d</code>定义了 <code>__get__</code>.</p>
<p>那么可以直接调用<code>__get__</code>,虽然很少这么用.<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">d.__get__(obj)</div></pre></td></tr></table></figure></p>
<p>大部分情况下这么用<code>obj.d</code>就可以了:</p>
<ul>
<li><code>obj.d</code> looks up d in the dictionary of obj: <code>obj.__dict__</code></li>
<li>如果<code>d</code>定义了<code>__get__()</code>, then <code>d.__get__(obj)</code> is invoked according to the precedence rules listed below.</li>
</ul>
<blockquote>
<p>For objects, the machinery is in object.<strong>getattribute</strong>() which transforms b.x into type(b).<strong>dict</strong>[‘x’].<strong>get</strong>(b, type(b)). The implementation works through a precedence chain that gives data descriptors priority over instance variables, instance variables priority over non-data descriptors, and assigns lowest priority to <strong>getattr</strong>() if provided. The full C implementation can be found in PyObject_GenericGetAttr() in Objects/object.c.</p>
<p>For classes, the machinery is in <code>type.__getattribute__()</code> which transforms <code>B.x</code> into <code>B.__dict__['x'].__get__(None, B)</code>. In pure Python, it looks like:</p>
</blockquote>
<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="function"><span class="keyword">def</span> <span class="title">__getattribute__</span><span class="params">(self, key)</span>:</span></div><div class="line"> <span class="string">"Emulate type_getattro() in Objects/typeobject.c"</span></div><div class="line"> v = object.__getattribute__(self, key)</div><div class="line"> <span class="keyword">if</span> hasattr(v, <span class="string">'__get__'</span>):</div><div class="line"> <span class="keyword">return</span> v.__get__(<span class="keyword">None</span>, self)</div><div class="line"> <span class="keyword">return</span> v</div></pre></td></tr></table></figure>
<p>The important points to remember are:</p>
<ul>
<li>descriptors are invoked by the <code>__getattribute__()</code> method</li>
<li>overriding <code>__getattribute__()</code> prevents automatic descriptor calls</li>
<li><code>__getattribute__()</code> is only available with new style classes and objects</li>
<li><code>object.__getattribute__()</code> and <code>type.__getattribute__()</code> make different calls to <code>__get__()</code>.</li>
<li>data descriptors always override instance dictionaries.</li>
<li>non-data descriptors may be overridden by instance dictionaries.</li>
</ul>
<h2 id="Sample"><a href="#Sample" class="headerlink" title="Sample"></a>Sample</h2><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">RevealAccess</span><span class="params">(object)</span>:</span></div><div class="line"> <span class="string">"""A data descriptor that sets and returns values</span></div><div class="line"> normally and prints a message logging their access.</div><div class="line"> """</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, initval=None, name=<span class="string">'var'</span>)</span>:</span></div><div class="line"> self.val = initval</div><div class="line"> self.name = name</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__get__</span><span class="params">(self, obj, objtype)</span>:</span></div><div class="line"> <span class="keyword">print</span> <span class="string">'Retrieving'</span>, self.name</div><div class="line"> <span class="keyword">return</span> self.val</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__set__</span><span class="params">(self, obj, val)</span>:</span></div><div class="line"> <span class="keyword">print</span> <span class="string">'Updating'</span>, self.name</div><div class="line"> self.val = val</div><div class="line"></div><div class="line"><span class="meta">>>> </span><span class="class"><span class="keyword">class</span> <span class="title">MyClass</span><span class="params">(object)</span>:</span></div><div class="line"><span class="meta">... </span> x = RevealAccess(<span class="number">10</span>, <span class="string">'var "x"'</span>)</div><div class="line"><span class="meta">... </span> y = <span class="number">5</span></div><div class="line">...</div><div class="line"><span class="meta">>>> </span>m = MyClass()</div><div class="line"><span class="meta">>>> </span>m.x</div><div class="line">Retrieving var <span class="string">"x"</span></div><div class="line"><span class="number">10</span></div><div class="line"><span class="meta">>>> </span>m.x = <span class="number">20</span></div><div class="line">Updating var <span class="string">"x"</span></div><div class="line"><span class="meta">>>> </span>m.x</div><div class="line">Retrieving var <span class="string">"x"</span></div><div class="line"><span class="number">20</span></div><div class="line"><span class="meta">>>> </span>m.y</div><div class="line"><span class="number">5</span></div></pre></td></tr></table></figure>
<h2 id="Properties"><a href="#Properties" class="headerlink" title="Properties"></a>Properties</h2><p>原来<code>Property</code>也是一个<code>descriptor</code></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><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Property</span><span class="params">(object)</span>:</span></div><div class="line"> <span class="string">"Emulate PyProperty_Type() in Objects/descrobject.c"</span></div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, fget=None, fset=None, fdel=None, doc=None)</span>:</span></div><div class="line"> self.fget = fget</div><div class="line"> self.fset = fset</div><div class="line"> self.fdel = fdel</div><div class="line"> <span class="keyword">if</span> doc <span class="keyword">is</span> <span class="keyword">None</span> <span class="keyword">and</span> fget <span class="keyword">is</span> <span class="keyword">not</span> <span class="keyword">None</span>:</div><div class="line"> doc = fget.__doc__</div><div class="line"> self.__doc__ = doc</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__get__</span><span class="params">(self, obj, objtype=None)</span>:</span></div><div class="line"> <span class="keyword">if</span> obj <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line"> <span class="keyword">return</span> self</div><div class="line"> <span class="keyword">if</span> self.fget <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line"> <span class="keyword">raise</span> AttributeError(<span class="string">"unreadable attribute"</span>)</div><div class="line"> <span class="keyword">return</span> self.fget(obj)</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__set__</span><span class="params">(self, obj, value)</span>:</span></div><div class="line"> <span class="keyword">if</span> self.fset <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line"> <span class="keyword">raise</span> AttributeError(<span class="string">"can't set attribute"</span>)</div><div class="line"> self.fset(obj, value)</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__delete__</span><span class="params">(self, obj)</span>:</span></div><div class="line"> <span class="keyword">if</span> self.fdel <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line"> <span class="keyword">raise</span> AttributeError(<span class="string">"can't delete attribute"</span>)</div><div class="line"> self.fdel(obj)</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">getter</span><span class="params">(self, fget)</span>:</span></div><div class="line"> <span class="keyword">return</span> type(self)(fget, self.fset, self.fdel, self.__doc__)</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">setter</span><span class="params">(self, fset)</span>:</span></div><div class="line"> <span class="keyword">return</span> type(self)(self.fget, fset, self.fdel, self.__doc__)</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">deleter</span><span class="params">(self, fdel)</span>:</span></div><div class="line"> <span class="keyword">return</span> type(self)(self.fget, self.fset, fdel, self.__doc__)</div></pre></td></tr></table></figure>
<h2 id="references"><a href="#references" class="headerlink" title="references"></a>references</h2><p>下面的这篇文档值得多看几次.</p>
<ul>
<li><a href="https://docs.python.org/2/howto/descriptor.html?highlight=descriptor" target="_blank" rel="external">Descriptor HowTo Guide</a></li>
</ul>
]]></content>
<summary type="html">
<p><code>descriptor</code>应该算的上是python的黑魔法了,不了解这个东西,很多源码估计看的头晕脑胀的.</p>
<h2 id="Definition-and-Introduction"><a href="#Definition-and-Introdu
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python excepthook</title>
<link href="http://superway117.github.io/2016/12/23/py_excepthook/"/>
<id>http://superway117.github.io/2016/12/23/py_excepthook/</id>
<published>2016-12-22T20:58:10.000Z</published>
<updated>2016-12-22T21:47:22.951Z</updated>
<content type="html"><![CDATA[<p>Python解释器默认定义了一个<code>excepthook</code>,发生异常退出的时候,会执行这个函数.然而我们可以重新定义这个hook函数,来实现更好的调试.</p>
<p>重新定义hook,也就是重新给<code>sys.excepthook</code>赋值.</p>
<h2 id="use-case"><a href="#use-case" class="headerlink" title="use case"></a>use case</h2><h3 id="出现异常打开ipython"><a href="#出现异常打开ipython" class="headerlink" title="出现异常打开ipython"></a>出现异常打开ipython</h3><p>从<code>scrapy</code>里面copy出来的, <code>scrapy</code>里面用下面的方式把ipython当做他的shell</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><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="keyword">import</span> sys</div><div class="line"></div><div class="line"><span class="keyword">try</span>:</div><div class="line"> <span class="keyword">from</span> IPython.terminal.embed <span class="keyword">import</span> InteractiveShellEmbed</div><div class="line"> <span class="keyword">from</span> IPython.terminal.ipapp <span class="keyword">import</span> load_default_config</div><div class="line"><span class="keyword">except</span> ImportError:</div><div class="line"> <span class="keyword">from</span> IPython.frontend.terminal.embed <span class="keyword">import</span> InteractiveShellEmbed</div><div class="line"> <span class="keyword">from</span> IPython.frontend.terminal.ipapp <span class="keyword">import</span> load_default_config</div><div class="line"></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Hook</span>:</span></div><div class="line"> <span class="string">"""A hook to replace sys.excepthook that open ipython</span></div><div class="line"> def __call__(self, etype, evalue, etb):</div><div class="line"> self.handle((etype, evalue, etb))</div><div class="line"> def handle(self, info=None):</div><div class="line"> config = load_default_config()</div><div class="line"> shell = InteractiveShellEmbed()</div><div class="line"> shell()</div><div class="line"></div><div class="line">handler = Hook().handle</div><div class="line">def enable()</div><div class="line"> sys.excepthook = Hook()</div></pre></td></tr></table></figure>
<h3 id="ultratb-ColorTB"><a href="#ultratb-ColorTB" class="headerlink" title="ultratb.ColorTB"></a>ultratb.ColorTB</h3><blockquote>
<p>I’ve always found it a bit hard to visually parse tracebacks in Python. The ColorTB class is a solution to that problem. It colors the different parts of a traceback in a manner similar to what you would expect from a syntax-highlighting text editor.</p>
</blockquote>
<p><a href="http://ipython.readthedocs.io/en/stable/api/generated/IPython.core.ultratb.html" target="_blank" rel="external">IPython.core.ultratb</a></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"><span class="keyword">import</span> sys,ultratb</div><div class="line">sys.excepthook = ultratb.ColorTB()</div></pre></td></tr></table></figure>
<h3 id="ultratb-VerboseTB"><a href="#ultratb-VerboseTB" class="headerlink" title="ultratb.VerboseTB"></a>ultratb.VerboseTB</h3><blockquote>
<p>I’ve also included a port of Ka-Ping Yee’s “cgitb.py” that produces all kinds of useful info when a traceback occurs. Ping originally had it spit out HTML and intended it for CGI programmers, but why should they have all the fun? I altered it to spit out colored text to the terminal. It’s a bit overwhelming, but kind of neat, and maybe useful for long-running programs that you believe are bug-free. If a crash does occur in that type of program you want details. Give it a shot–you’ll love it or you’ll hate it.</p>
</blockquote>
<p><a href="http://ipython.readthedocs.io/en/stable/api/generated/IPython.core.ultratb.html" target="_blank" rel="external">IPython.core.ultratb</a></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"><span class="keyword">import</span> sys,ultratb</div><div class="line">sys.excepthook = ultratb.VerboseTB()</div></pre></td></tr></table></figure>
<h3 id="cgitb"><a href="#cgitb" class="headerlink" title="cgitb"></a>cgitb</h3><p>用来输出exception到html/text.</p>
<p>源码:</p>
<blockquote>
<p>Python-2.7.11\Lib\cgitb.py</p>
</blockquote>
<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"><span class="keyword">import</span> cgitb</div><div class="line">cgitb.enable()</div></pre></td></tr></table></figure>
<p>enable可以带参数:<br><figure class="highlight plain"><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">display - if true, tracebacks are displayed in the web browser</div><div class="line">logdir - if set, tracebacks are written to files in this directory</div><div class="line">context - number of lines of source code to show for each stack frame</div><div class="line">format - 'text' or 'html' controls the output format</div></pre></td></tr></table></figure></p>
<p>enable原型</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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">enable</span><span class="params">(display=<span class="number">1</span>, logdir=None, context=<span class="number">5</span>, format=<span class="string">"html"</span>)</span>:</span></div><div class="line"> <span class="string">"""Install an exception handler that formats tracebacks as HTML.</span></div><div class="line"></div><div class="line"> The optional argument 'display' can be set to 0 to suppress sending the</div><div class="line"> traceback to the browser, and 'logdir' can be set to a directory to cause</div><div class="line"> tracebacks to be written to files there."""</div><div class="line"> sys.excepthook = Hook(display=display, logdir=logdir,</div><div class="line"> context=context, format=format)</div></pre></td></tr></table></figure>
<h2 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h2><blockquote>
<p>Python-2.7.11\Python\pythonrun.c</p>
</blockquote>
<p>pythonrun.c 里面程序退出前,总是会调用下<code>PyErr_Print</code></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></pre></td><td class="code"><pre><div class="line">void</div><div class="line">PyErr_Print(void)</div><div class="line">{</div><div class="line"> PyErr_PrintEx(<span class="number">1</span>);</div><div class="line">}</div><div class="line">void</div><div class="line">PyErr_PrintEx(int set_sys_last_vars)</div><div class="line">{</div><div class="line"> xxxx</div><div class="line"> hook = PySys_GetObject(<span class="string">"excepthook"</span>);</div><div class="line"> <span class="keyword">if</span> (hook && hook != Py_None) {</div><div class="line"> PyObject *result = PyEval_CallObject(hook, args);</div></pre></td></tr></table></figure>
<p>上面的代码简单的理解就是,从<code>sys</code>模块里面找到<code>excepthook</code>,然后执行他.</p>
<p>python默认的<code>excepthook</code>实现在<code>sys</code></p>
<blockquote>
<p>Python-2.7.11\Python\sysmodule.c</p>
</blockquote>
<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></pre></td><td class="code"><pre><div class="line"></div><div class="line">static PyObject *</div><div class="line">sys_excepthook(PyObject* self, PyObject* args)</div><div class="line">{</div><div class="line"> PyObject *exc, *value, *tb;</div><div class="line"> <span class="keyword">if</span> (!PyArg_UnpackTuple(args, <span class="string">"excepthook"</span>, <span class="number">3</span>, <span class="number">3</span>, &exc, &value, &tb))</div><div class="line"> <span class="keyword">return</span> NULL;</div><div class="line"> PyErr_Display(exc, value, tb);</div><div class="line"> Py_INCREF(Py_None);</div><div class="line"> <span class="keyword">return</span> Py_None;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>注册给<code>sys</code>是这样的:</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">static PyMethodDef sys_methods[] = {</div><div class="line"> {<span class="string">"excepthook"</span>, sys_excepthook, METH_VARARGS, excepthook_doc},</div></pre></td></tr></table></figure>
<p><code>sys</code>模块初始化的时候把默认<code>excepthook</code>的定义,保存在<code>__excepthook__</code></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">PyObject *</div><div class="line">_PySys_Init(void)</div><div class="line">{</div><div class="line"> PyDict_SetItemString(sysdict, <span class="string">"__excepthook__"</span>,</div><div class="line"> PyDict_GetItemString(sysdict, <span class="string">"excepthook"</span>));</div><div class="line">}</div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<p>Python解释器默认定义了一个<code>excepthook</code>,发生异常退出的时候,会执行这个函数.然而我们可以重新定义这个hook函数,来实现更好的调试.</p>
<p>重新定义hook,也就是重新给<code>sys.excepthook</code>赋
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python __debug__&assert</title>
<link href="http://superway117.github.io/2016/12/22/py_debug/"/>
<id>http://superway117.github.io/2016/12/22/py_debug/</id>
<published>2016-12-22T05:24:31.000Z</published>
<updated>2016-12-22T21:50:06.080Z</updated>
<content type="html"><![CDATA[<p><code>__debug__</code>是python内置的变量,用来判断是否是调试模式. 我们开发过程中的debug代码,可以用它来控制.</p>
<ul>
<li>默认情况下<code>__debug__</code> == True</li>
<li><p>如果执行python的时候加上option -o/-oo,<code>__debug__</code>会被设置成False.</p>
<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">-O : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x</div><div class="line">-OO : remove doc-strings in addition to the -O optimizations</div></pre></td></tr></table></figure>
</li>
<li><p><code>__debug__</code> cannot be reassigned(虽然文档里面2.7可以重新赋值,但是实际好像不行)</p>
<figure class="highlight plain"><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">In [22]: __debug__=False</div><div class="line">File "<ipython-input-22-b964276c1288>", line 1</div><div class="line"> __debug__=False</div><div class="line">SyntaxError: cannot assign to __debug__</div></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="assert"><a href="#assert" class="headerlink" title="assert"></a>assert</h2><p>assert是一个用来调试的断言,他的执行是依赖<code>__debug__</code></p>
<p>Assert statements are a convenient way to insert debugging assertions into a program:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">assert_stmt ::= "assert" expression ["," expression]</div></pre></td></tr></table></figure></p>
<p>他等价于</p>
<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">if __debug__:</div><div class="line"> if not expression: raise AssertionError</div></pre></td></tr></table></figure>
<p>也可以同时写多个表达式<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">assert expression1, expression2,</div></pre></td></tr></table></figure></p>
<p>他等价于</p>
<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">if __debug__:</div><div class="line"> if not expression1: raise AssertionError(expression2)</div></pre></td></tr></table></figure>
<p><code>常规用法</code></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">assert</span> buffer_size % <span class="number">4</span> == <span class="number">0</span>, <span class="string">'buffer size has to be divisible by 4'</span></div></pre></td></tr></table></figure>
<h2 id="AssertionError"><a href="#AssertionError" class="headerlink" title="AssertionError"></a>AssertionError</h2><blockquote>
<p>Python-2.7.11\Objects\exceptions.c</p>
</blockquote>
<figure class="highlight plain"><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></pre></td><td class="code"><pre><div class="line">/*</div><div class="line"> * StandardError extends Exception</div><div class="line"> */</div><div class="line">SimpleExtendsException(PyExc_Exception, StandardError,</div><div class="line"> "Base class for all standard Python exceptions that do not represent\n"</div><div class="line"> "interpreter exiting.");</div><div class="line"></div><div class="line">/*</div><div class="line"> * AssertionError extends StandardError</div><div class="line"> */</div><div class="line">SimpleExtendsException(PyExc_StandardError, AssertionError,</div><div class="line"> "Assertion failed.");</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p><code>__debug__</code>是python内置的变量,用来判断是否是调试模式. 我们开发过程中的debug代码,可以用它来控制.</p>
<ul>
<li>默认情况下<code>__debug__</code> == True</li>
<li><p>如果执
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python property</title>
<link href="http://superway117.github.io/2016/12/22/py_property/"/>
<id>http://superway117.github.io/2016/12/22/py_property/</id>
<published>2016-12-21T16:49:22.000Z</published>
<updated>2016-12-22T04:55:04.868Z</updated>
<content type="html"><![CDATA[<p><code>property</code>对应的是c代码的实现<code>propertyobject</code>. </p>
<p>主要是用来处理class里面的属性get/set/delete/doc操作. </p>
<p>需要注意的是应用property的class必须继承<code>object</code>,不然有问题,root cause未知. python cookbook里面的case有些是跑不起来的,就是因为他的代码很多没有继承object</p>
<p>主要的应用场景:</p>
<ul>
<li>set的时候做类型检查</li>
<li>get的时候做一些运算</li>
<li>禁止delete操作</li>
</ul>
<p>实际python代码里面,可以继承<code>property</code>或者用<code>property</code>作为一个装饰器来用.</p>
<p>下面的写法是一致的. 可以理解是用来做装饰器.</p>
<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></pre></td><td class="code"><pre><div class="line">class C(object):</div><div class="line"> def getx(self): return self._x</div><div class="line"> def setx(self, value): self._x = value</div><div class="line"> def delx(self): del self._x</div><div class="line"> x = property(getx, setx, delx, \"I'm the 'x' property.\")</div><div class="line"></div><div class="line">Decorators make defining new properties or modifying existing ones easy:</div><div class="line">class C(object):</div><div class="line"> @property</div><div class="line"> def x(self):</div><div class="line"> \"I am the 'x' property.\"</div><div class="line"> return self._x</div><div class="line"> @x.setter</div><div class="line"> def x(self, value):</div><div class="line"> self._x = value</div><div class="line"> @x.deleter</div><div class="line"> def x(self):</div><div class="line"> del self._x</div></pre></td></tr></table></figure>
<h2 id="use-case"><a href="#use-case" class="headerlink" title="use case"></a>use case</h2><h3 id="cached-property"><a href="#cached-property" class="headerlink" title="cached_property"></a>cached_property</h3><p>代码从 werkzeug-master\werkzeug\utils.py copy出来的.</p>
<p>这段代码主要用来cache已经计算过的值.</p>
<p>需要注意的是</p>
<ul>
<li>cached value 存在 obj.<strong>dict</strong>[self.<strong>name</strong>], self.<strong>name</strong>默认是函数名</li>
<li>c.area = 11 用来执行 cached_property.<strong>set</strong> ,给cached值重新赋值</li>
</ul>
<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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> math</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">cached_property</span><span class="params">(property)</span>:</span></div><div class="line"></div><div class="line"> <span class="string">"""A decorator that converts a function into a lazy property. The</span></div><div class="line"> function wrapped is called the first time to retrieve the result</div><div class="line"> and then that calculated result is used the next time you access</div><div class="line"> the value::</div><div class="line"></div><div class="line"> class Foo(object):</div><div class="line"></div><div class="line"> @cached_property</div><div class="line"> def foo(self):</div><div class="line"> # calculate something important here</div><div class="line"> return 42</div><div class="line"></div><div class="line"> The class has to have a `__dict__` in order for this property to</div><div class="line"> work.</div><div class="line"> """</div><div class="line"></div><div class="line"> <span class="comment"># implementation detail: A subclass of python's builtin property</span></div><div class="line"> <span class="comment"># decorator, we override __get__ to check for a cached value. If one</span></div><div class="line"> <span class="comment"># choses to invoke __get__ by hand the property will still work as</span></div><div class="line"> <span class="comment"># expected because the lookup logic is replicated in __get__ for</span></div><div class="line"> <span class="comment"># manual invocation.</span></div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, func, name=None, doc=None)</span>:</span></div><div class="line"> self.__name__ = name <span class="keyword">or</span> func.__name__</div><div class="line"> self.__module__ = func.__module__</div><div class="line"> self.__doc__ = doc <span class="keyword">or</span> func.__doc__</div><div class="line"> self.func = func</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__set__</span><span class="params">(self, obj, value)</span>:</span></div><div class="line"> <span class="keyword">print</span> <span class="string">"__set__ value:%d"</span> % (value,)</div><div class="line"> obj.__dict__[self.__name__] = value</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__get__</span><span class="params">(self, obj, type=None)</span>:</span></div><div class="line"> <span class="keyword">if</span> obj <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line"> <span class="keyword">return</span> self</div><div class="line"> value = obj.__dict__.get(self.__name__, <span class="keyword">None</span>)</div><div class="line"> <span class="keyword">if</span> value <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line"> value = self.func(obj)</div><div class="line"> obj.__dict__[self.__name__] = value</div><div class="line"> <span class="keyword">return</span> value</div><div class="line"></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Circle</span><span class="params">(object)</span>:</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, radius)</span>:</span></div><div class="line"> self.radius = radius</div><div class="line"></div><div class="line"><span class="meta"> @cached_property</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">area</span><span class="params">(self)</span>:</span></div><div class="line"> print(<span class="string">'Computing area'</span>)</div><div class="line"> <span class="keyword">return</span> math.pi * self.radius ** <span class="number">2</span></div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line"> c=Circle(<span class="number">2</span>)</div><div class="line"> <span class="keyword">print</span> c.area</div><div class="line"> <span class="keyword">print</span> c.area</div><div class="line"> c.area = <span class="number">11</span></div><div class="line"> <span class="keyword">print</span> c.area</div></pre></td></tr></table></figure>
<p>result</p>
<figure class="highlight plain"><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">Computing area</div><div class="line">12.5663706144</div><div class="line">12.5663706144</div><div class="line">11</div></pre></td></tr></table></figure>
<h3 id="类型检查"><a href="#类型检查" class="headerlink" title="类型检查"></a>类型检查</h3><ul>
<li><code>setter</code>里面做类型检查</li>
<li><code>deleter</code>里面禁止删除动作</li>
</ul>
<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><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span><span class="params">(object)</span>:</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, name)</span>:</span></div><div class="line"> self.name = name</div><div class="line"></div><div class="line"> <span class="comment"># Getter function</span></div><div class="line"><span class="meta"> @property</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">name</span><span class="params">(self)</span>:</span></div><div class="line"> print(<span class="string">'get name in Person'</span>)</div><div class="line"> <span class="keyword">return</span> self._name</div><div class="line"></div><div class="line"> <span class="comment"># Setter function</span></div><div class="line"><span class="meta"> @name.setter</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">name</span><span class="params">(self, value)</span>:</span></div><div class="line"> <span class="keyword">if</span> <span class="keyword">not</span> isinstance(value, str):</div><div class="line"> <span class="keyword">raise</span> TypeError(<span class="string">'Expected a string'</span>)</div><div class="line"> print(<span class="string">'set name in Person'</span>)</div><div class="line"> self._name = value</div><div class="line"></div><div class="line"> <span class="comment"># Deleter function</span></div><div class="line"><span class="meta"> @name.deleter</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">name</span><span class="params">(self)</span>:</span></div><div class="line"> <span class="keyword">raise</span> AttributeError(<span class="string">"Can't delete attribute"</span>)</div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line"> s = Person(<span class="string">'Guido'</span>)</div><div class="line"> <span class="keyword">print</span> s.name</div><div class="line"> s.name = <span class="string">'Larry'</span></div><div class="line"> <span class="keyword">print</span> s.name</div><div class="line"> s.name = <span class="number">42</span></div><div class="line"> <span class="keyword">print</span> s.name</div></pre></td></tr></table></figure>
<p>result</p>
<figure class="highlight plain"><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></pre></td><td class="code"><pre><div class="line">set name in Person</div><div class="line">get name in Person</div><div class="line">Guido</div><div class="line">set name in Person</div><div class="line">get name in Person</div><div class="line">Larry</div><div class="line">Traceback (most recent call last):</div><div class="line"> File "test.py", line 45, in <module></div><div class="line"> s.name = 42</div><div class="line"> File "test.py", line 15, in name</div><div class="line"> raise TypeError('Expected a string')</div><div class="line">TypeError: Expected a string</div></pre></td></tr></table></figure>
<h3 id="Extending-a-Property-in-a-Subclass"><a href="#Extending-a-Property-in-a-Subclass" class="headerlink" title="Extending a Property in a Subclass"></a>Extending a Property in a Subclass</h3><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span><span class="params">(object)</span>:</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, name)</span>:</span></div><div class="line"> self.name = name</div><div class="line"></div><div class="line"> <span class="comment"># Getter function</span></div><div class="line"><span class="meta"> @property</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">name</span><span class="params">(self)</span>:</span></div><div class="line"> print(<span class="string">'get name in Person'</span>)</div><div class="line"> <span class="keyword">return</span> self._name</div><div class="line"></div><div class="line"> <span class="comment"># Setter function</span></div><div class="line"><span class="meta"> @name.setter</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">name</span><span class="params">(self, value)</span>:</span></div><div class="line"> <span class="keyword">if</span> <span class="keyword">not</span> isinstance(value, str):</div><div class="line"> <span class="keyword">raise</span> TypeError(<span class="string">'Expected a string'</span>)</div><div class="line"> print(<span class="string">'set name in Person'</span>)</div><div class="line"> self._name = value</div><div class="line"></div><div class="line"> <span class="comment"># Deleter function</span></div><div class="line"><span class="meta"> @name.deleter</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">name</span><span class="params">(self)</span>:</span></div><div class="line"> <span class="keyword">raise</span> AttributeError(<span class="string">"Can't delete attribute"</span>)</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">SubPerson</span><span class="params">(Person)</span>:</span></div><div class="line"><span class="meta"> @property</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">name</span><span class="params">(self)</span>:</span></div><div class="line"> print(<span class="string">'get name in SubPerson'</span>)</div><div class="line"> <span class="keyword">return</span> super(SubPerson, self).name</div><div class="line"></div><div class="line"><span class="meta"> @name.setter</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">name</span><span class="params">(self, value)</span>:</span></div><div class="line"> print(<span class="string">'set name in SubPerson'</span>)</div><div class="line"> super(SubPerson, SubPerson).name.__set__(self, value)</div><div class="line"></div><div class="line"><span class="meta"> @name.deleter</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">name</span><span class="params">(self)</span>:</span></div><div class="line"> print(<span class="string">'Deleting name'</span>)</div><div class="line"> super(SubPerson, SubPerson).name.__delete__(self)</div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line"> s = SubPerson(<span class="string">'Guido'</span>)</div><div class="line"> <span class="keyword">print</span> s.name</div><div class="line"> s.name = <span class="string">'Larry'</span></div><div class="line"> <span class="keyword">print</span> s.name</div><div class="line"> s.name = <span class="number">42</span></div><div class="line"> <span class="keyword">print</span> s.name</div></pre></td></tr></table></figure>
<p>result</p>
<figure class="highlight plain"><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">set name in SubPerson</div><div class="line">set name in Person</div><div class="line">get name in SubPerson</div><div class="line">get name in Person</div><div class="line">Guido</div><div class="line">set name in SubPerson</div><div class="line">set name in Person</div><div class="line">get name in SubPerson</div><div class="line">get name in Person</div><div class="line">Larry</div><div class="line">set name in SubPerson</div><div class="line">Traceback (most recent call last):</div><div class="line"> File "test.py", line 45, in <module></div><div class="line"> s.name = 42</div><div class="line"> File "test.py", line 33, in name</div><div class="line"> super(SubPerson, SubPerson).name.__set__(self, va</div><div class="line"> File "test.py", line 15, in name</div><div class="line"> raise TypeError('Expected a string')</div><div class="line">TypeError: Expected a string</div></pre></td></tr></table></figure>
<h2 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h2><blockquote>
<p>Python-2.7.11\Objects\descrobject.c</p>
</blockquote>
<h2 id="疑问"><a href="#疑问" class="headerlink" title="疑问"></a>疑问</h2><p><code>super</code>的用法,还真是有点疑惑</p>
]]></content>
<summary type="html">
<p><code>property</code>对应的是c代码的实现<code>propertyobject</code>. </p>
<p>主要是用来处理class里面的属性get/set/delete/doc操作. </p>
<p>需要注意的是应用property的class
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python PyIntObject</title>
<link href="http://superway117.github.io/2016/12/20/py_intobject/"/>
<id>http://superway117.github.io/2016/12/20/py_intobject/</id>
<published>2016-12-19T16:09:10.000Z</published>
<updated>2016-12-19T16:36:49.412Z</updated>
<content type="html"><![CDATA[<p><code>PyIntObject</code>属于固定size的object,所以数据结构也比较简单.</p>
<figure class="highlight c"><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">typedef</span> <span class="keyword">struct</span> {</div><div class="line"> PyObject_HEAD</div><div class="line"> <span class="keyword">long</span> ob_ival;</div><div class="line">} PyIntObject;</div></pre></td></tr></table></figure>
<p>本文topic主要在<code>PyIntObject</code>如何实现内存/性能优化. 概括的说</p>
<ul>
<li>对于small int, 默认是-5–257之间的PyIntObject,是预分配的, 每次只要从small_ints这个池子里面去就行</li>
<li>预先分配了一个pool(free_list),2.7定义的是(1000-8)个PyIntObject,每次需要分配PyIntObject,直接从free_list取</li>
</ul>
<h2 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h2><h3 id="PyInt-Init"><a href="#PyInt-Init" class="headerlink" title="_PyInt_Init"></a>_PyInt_Init</h3><p>Python解释器执行的时候会做一个动作.</p>
<figure class="highlight c"><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">Py_InitializeEx</div><div class="line"> -->_PyInt_Init</div></pre></td></tr></table></figure>
<p>所有的逻辑看<code>_PyInt_Init</code>就清楚了.</p>
<figure class="highlight c"><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="keyword">int</span></div><div class="line">_PyInt_Init(<span class="keyword">void</span>)</div><div class="line">{</div><div class="line"> PyIntObject *v;</div><div class="line"> <span class="keyword">int</span> ival;</div><div class="line"><span class="meta">#<span class="meta-keyword">if</span> NSMALLNEGINTS + NSMALLPOSINTS > 0</span></div><div class="line"> <span class="keyword">for</span> (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) {</div><div class="line"> <span class="keyword">if</span> (!free_list && (free_list = fill_free_list()) == <span class="literal">NULL</span>)</div><div class="line"> <span class="keyword">return</span> <span class="number">0</span>;</div><div class="line"> <span class="comment">/* PyObject_New is inlined */</span></div><div class="line"> v = free_list;</div><div class="line"> free_list = (PyIntObject *)Py_TYPE(v);</div><div class="line"> PyObject_INIT(v, &PyInt_Type);</div><div class="line"> v->ob_ival = ival;</div><div class="line"> small_ints[ival + NSMALLNEGINTS] = v;</div><div class="line"> }</div><div class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></div><div class="line"> <span class="keyword">return</span> <span class="number">1</span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>上面的逻辑:</p>
<figure class="highlight c"><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></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span>(ival=<span class="number">-5</span>; ival<<span class="number">257</span>; ival++)</div><div class="line">{</div><div class="line"> <span class="number">1.</span> 从free_list里面去一个空闲的 PyIntObject -->v</div><div class="line"> <span class="number">2.</span> 给v赋值 ob_ival = ival</div><div class="line"> <span class="number">3.</span> free_list里面ob_type用来指向前一个block,所有这里需要做一个PyObject_INIT</div><div class="line"> <span class="number">4.</span> 因为是从<span class="number">-5</span>开始算起,所有small_ints[<span class="number">0</span>]是给<span class="number">-5</span>用的,以此类推</div><div class="line">}</div></pre></td></tr></table></figure>
<p>free_list只分配一次<br><figure class="highlight c"><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"><span class="keyword">if</span> (!free_list && (free_list = fill_free_list()) == <span class="literal">NULL</span>)</div><div class="line"> <span class="keyword">return</span> <span class="number">0</span>;</div></pre></td></tr></table></figure></p>
<h3 id="free-list"><a href="#free-list" class="headerlink" title="free_list"></a>free_list</h3><p>fill_free_list的逻辑就是一次申请 N_INTOBJECTS 个 PyIntObject.</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">PyMem_MALLOC(<span class="keyword">sizeof</span>(PyIntBlock))</div></pre></td></tr></table></figure>
<p>需要注意的是:</p>
<ul>
<li>fill_free_list返回的是最后一个block: p + N_INTOBJECTS - 1</li>
<li>每一个block的ob_type,用来指向前一个block</li>
<li>第一个block的ob_type是null,这个用来判断当前free_list是否已经用完了</li>
<li>block_list用来维护多个free_list</li>
</ul>
<figure class="highlight c"><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><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">struct</span> _intblock {</div><div class="line"> <span class="keyword">struct</span> _intblock *next;</div><div class="line"> PyIntObject objects[N_INTOBJECTS];</div><div class="line">};</div><div class="line"></div><div class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> _intblock PyIntBlock;</div><div class="line"></div><div class="line"><span class="keyword">static</span> PyIntBlock *block_list = <span class="literal">NULL</span>;</div><div class="line"><span class="keyword">static</span> PyIntObject *free_list = <span class="literal">NULL</span>;</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">static</span> PyIntObject *</span></div><div class="line"><span class="title">fill_free_list</span><span class="params">(<span class="keyword">void</span>)</span></div><div class="line">{</div><div class="line"> PyIntObject *p, *q;</div><div class="line"> <span class="comment">/* Python's object allocator isn't appropriate for large blocks. */</span></div><div class="line"> p = (PyIntObject *) PyMem_MALLOC(<span class="keyword">sizeof</span>(PyIntBlock));</div><div class="line"> <span class="keyword">if</span> (p == <span class="literal">NULL</span>)</div><div class="line"> <span class="keyword">return</span> (PyIntObject *) PyErr_NoMemory();</div><div class="line"> ((PyIntBlock *)p)->next = block_list;</div><div class="line"> block_list = (PyIntBlock *)p;</div><div class="line"> <span class="comment">/* Link the int objects together, from rear to front, then return</span></div><div class="line"> the address of the last int object in the block. */</div><div class="line"> p = &((PyIntBlock *)p)->objects[<span class="number">0</span>];</div><div class="line"> q = p + N_INTOBJECTS;</div><div class="line"> <span class="keyword">while</span> (--q > p)</div><div class="line"> Py_TYPE(q) = (<span class="keyword">struct</span> _typeobject *)(q<span class="number">-1</span>);</div><div class="line"> Py_TYPE(q) = <span class="literal">NULL</span>;</div><div class="line"> <span class="keyword">return</span> p + N_INTOBJECTS - <span class="number">1</span>;</div><div class="line">}</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p><code>PyIntObject</code>属于固定size的object,所以数据结构也比较简单.</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line"
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python PyStringObject</title>
<link href="http://superway117.github.io/2016/12/20/py_stringobject/"/>
<id>http://superway117.github.io/2016/12/20/py_stringobject/</id>
<published>2016-12-19T16:09:10.000Z</published>
<updated>2016-12-20T14:53:12.793Z</updated>
<content type="html"><![CDATA[<p><code>PyStringObject</code>属于变长size的object</p>
<figure class="highlight c"><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="keyword">typedef</span> <span class="keyword">struct</span> {</div><div class="line"> PyObject_VAR_HEAD</div><div class="line"> <span class="keyword">long</span> ob_shash;</div><div class="line"> <span class="keyword">int</span> ob_sstate;</div><div class="line"> <span class="keyword">char</span> ob_sval[<span class="number">1</span>];</div><div class="line"></div><div class="line"> <span class="comment">/* Invariants:</span></div><div class="line"> * ob_sval contains space for 'ob_size+1' elements.</div><div class="line"> * ob_sval[ob_size] == 0.</div><div class="line"> * ob_shash is the hash of the string or -1 if not computed yet.</div><div class="line"> * ob_sstate != 0 iff the string object is in stringobject.c's</div><div class="line"> * 'interned' dictionary; in this case the two references</div><div class="line"> * from 'interned' to this object are *not counted* in ob_refcnt.</div><div class="line"> */</div><div class="line">} PyStringObject;</div><div class="line"></div><div class="line"><span class="meta">#<span class="meta-keyword">define</span> PyObject_VAR_HEAD \</span></div><div class="line"> PyObject_HEAD \</div><div class="line"> Py_ssize_t ob_size; <span class="comment">/* Number of items in variable part */</span></div></pre></td></tr></table></figure>
<p>ob_size存的是字符串的size,strlen(str),不包含结束符</p>
<h2 id="针对size-0-or-1的字符串内存优化"><a href="#针对size-0-or-1的字符串内存优化" class="headerlink" title="针对size=0 or 1的字符串内存优化"></a>针对size=0 or 1的字符串内存优化</h2><p>看<code>PyString_FromStringAndSize</code>的实现</p>
<ol>
<li>如果size==0, 返回<code>null_strings</code>,引用计数+1</li>
<li>如果size==1,如果characters数组里面已经存在,直接返回,引用计数+1;如果characters数组里面不存在,创建一个,并保存在characters数组</li>
</ol>
<figure class="highlight c"><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div></pre></td><td class="code"><pre><div class="line"><span class="function">PyObject *</span></div><div class="line"><span class="title">PyString_FromStringAndSize</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *str, Py_ssize_t size)</span></div><div class="line">{</div><div class="line"> <span class="keyword">register</span> PyStringObject *op;</div><div class="line"> <span class="keyword">if</span> (size < <span class="number">0</span>) {</div><div class="line"> PyErr_SetString(PyExc_SystemError,</div><div class="line"> <span class="string">"Negative size passed to PyString_FromStringAndSize"</span>);</div><div class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (size == <span class="number">0</span> && (op = nullstring) != <span class="literal">NULL</span>) {</div><div class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> COUNT_ALLOCS</span></div><div class="line"> null_strings++;</div><div class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></div><div class="line"> Py_INCREF(op);</div><div class="line"> <span class="keyword">return</span> (PyObject *)op;</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (size == <span class="number">1</span> && str != <span class="literal">NULL</span> &&</div><div class="line"> (op = characters[*str & UCHAR_MAX]) != <span class="literal">NULL</span>)</div><div class="line"> {</div><div class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> COUNT_ALLOCS</span></div><div class="line"> one_strings++;</div><div class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></div><div class="line"> Py_INCREF(op);</div><div class="line"> <span class="keyword">return</span> (PyObject *)op;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (size > PY_SSIZE_T_MAX - PyStringObject_SIZE) {</div><div class="line"> PyErr_SetString(PyExc_OverflowError, <span class="string">"string is too large"</span>);</div><div class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/* Inline PyObject_NewVar */</span></div><div class="line"> op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size);</div><div class="line"> <span class="keyword">if</span> (op == <span class="literal">NULL</span>)</div><div class="line"> <span class="keyword">return</span> PyErr_NoMemory();</div><div class="line"> PyObject_INIT_VAR(op, &PyString_Type, size);</div><div class="line"> op->ob_shash = <span class="number">-1</span>;</div><div class="line"> op->ob_sstate = SSTATE_NOT_INTERNED;</div><div class="line"> <span class="keyword">if</span> (str != <span class="literal">NULL</span>)</div><div class="line"> Py_MEMCPY(op->ob_sval, str, size);</div><div class="line"> op->ob_sval[size] = <span class="string">'\0'</span>;</div><div class="line"> <span class="comment">/* share short strings */</span></div><div class="line"> <span class="keyword">if</span> (size == <span class="number">0</span>) {</div><div class="line"> PyObject *t = (PyObject *)op;</div><div class="line"> PyString_InternInPlace(&t);</div><div class="line"> op = (PyStringObject *)t;</div><div class="line"> nullstring = op;</div><div class="line"> Py_INCREF(op);</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (size == <span class="number">1</span> && str != <span class="literal">NULL</span>) {</div><div class="line"> PyObject *t = (PyObject *)op;</div><div class="line"> PyString_InternInPlace(&t);</div><div class="line"> op = (PyStringObject *)t;</div><div class="line"> characters[*str & UCHAR_MAX] = op;</div><div class="line"> Py_INCREF(op);</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> (PyObject *) op;</div><div class="line">}</div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<p><code>PyStringObject</code>属于变长size的object</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><d
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python Decorator - 理解调用过程</title>
<link href="http://superway117.github.io/2016/12/15/py_decorator_2/"/>
<id>http://superway117.github.io/2016/12/15/py_decorator_2/</id>
<published>2016-12-15T06:54:30.000Z</published>
<updated>2016-12-16T16:02:11.871Z</updated>
<content type="html"><![CDATA[<p>主要topic</p>
<ul>
<li>Decorator是怎么调用的</li>
<li>用partial来实现一个带参数的Decorator</li>
</ul>
<h2 id="Decorator的调用"><a href="#Decorator的调用" class="headerlink" title="Decorator的调用"></a><code>Decorator</code>的调用</h2><p>理解<code>Decorator</code>的第一步要理解<code>Decorator</code>是怎么调用的.</p>
<p>下面的例子是<code>Decorator</code>不带参数的情况</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="meta">@logged()</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">add</span><span class="params">(x, y)</span>:</span></div><div class="line"> <span class="keyword">return</span> x+y</div></pre></td></tr></table></figure>
<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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">add</span><span class="params">(x, y)</span>:</span></div><div class="line"> <span class="keyword">return</span> x + y</div><div class="line"></div><div class="line">add = logged(add)</div></pre></td></tr></table></figure>
<p>下面的例子是<code>Decorator</code>带参数的情况<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></pre></td><td class="code"><pre><div class="line"><span class="meta">@logged(level=logging.CRITICAL, name='example')</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">spam</span><span class="params">()</span>:</span></div><div class="line"> print(<span class="string">'Spam!'</span>)</div></pre></td></tr></table></figure></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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">spam</span><span class="params">()</span>:</span></div><div class="line"> print(<span class="string">'Spam!'</span>)</div><div class="line">spam = logged(level=logging.CRITICAL, name=<span class="string">'example'</span>)(spam)</div></pre></td></tr></table></figure>
<h2 id="用partial实现带参数的Decorator"><a href="#用partial实现带参数的Decorator" class="headerlink" title="用partial实现带参数的Decorator"></a>用<code>partial</code>实现带参数的<code>Decorator</code></h2><p>下面的 <code>logged</code> demo了,怎么样实现兼容一个带或者不带参数的<code>Decorator</code></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><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></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> functools <span class="keyword">import</span> wraps, partial</div><div class="line"><span class="keyword">import</span> logging</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">logged</span><span class="params">(func=None, *, level=logging.DEBUG, name=None, message=None)</span>:</span></div><div class="line"> <span class="keyword">if</span> func <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line"> <span class="keyword">return</span> partial(logged, level=level, name=name, message=message)</div><div class="line"></div><div class="line"> logname = name <span class="keyword">if</span> name <span class="keyword">else</span> func.__module__</div><div class="line"> log = logging.getLogger(logname)</div><div class="line"> logmsg = message <span class="keyword">if</span> message <span class="keyword">else</span> func.__name__</div><div class="line"></div><div class="line"><span class="meta"> @wraps(func)</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(*args, **kwargs)</span>:</span></div><div class="line"> log.log(level, logmsg)</div><div class="line"> <span class="keyword">return</span> func(*args, **kwargs)</div><div class="line"></div><div class="line"> <span class="keyword">return</span> wrapper</div></pre></td></tr></table></figure>
<p>Example use</p>
<figure class="highlight plain"><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></pre></td><td class="code"><pre><div class="line">@logged</div><div class="line">def add(x, y):</div><div class="line"> return x + y</div><div class="line"></div><div class="line">@logged(level=logging.CRITICAL, name='example')</div><div class="line">def spam():</div><div class="line"> print('Spam!')</div></pre></td></tr></table></figure>
<h3 id="不带参数的情况"><a href="#不带参数的情况" class="headerlink" title="不带参数的情况"></a>不带参数的情况</h3><figure class="highlight plain"><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">@logged</div><div class="line">def add(x, y):</div><div class="line"> return x + y</div></pre></td></tr></table></figure>
<p>等价<br><figure class="highlight plain"><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">def add(x, y):</div><div class="line"> return x + y</div><div class="line"></div><div class="line">add = logged(add)</div></pre></td></tr></table></figure></p>
<p>logged里面针对这个情况,返回的是<code>wrapper</code>,注意, 这个<code>wrapper</code>是被<code>@wraps(func)</code>包装过的.</p>
<p>相当于</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">add = logged(add) == wraps(add)(wrapper)</div></pre></td></tr></table></figure>
<p>wraps的实现如下:</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><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line">WRAPPER_ASSIGNMENTS = (<span class="string">'__module__'</span>, <span class="string">'__name__'</span>, <span class="string">'__doc__'</span>)</div><div class="line">WRAPPER_UPDATES = (<span class="string">'__dict__'</span>,)</div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">update_wrapper</span><span class="params">(wrapper,</span></span></div><div class="line"> wrapped,</div><div class="line"> assigned = WRAPPER_ASSIGNMENTS,</div><div class="line"> updated = WRAPPER_UPDATES):</div><div class="line"> <span class="string">"""Update a wrapper function to look like the wrapped function</span></div><div class="line"></div><div class="line"> wrapper is the function to be updated</div><div class="line"> wrapped is the original function</div><div class="line"> assigned is a tuple naming the attributes assigned directly</div><div class="line"> from the wrapped function to the wrapper function (defaults to</div><div class="line"> functools.WRAPPER_ASSIGNMENTS)</div><div class="line"> updated is a tuple naming the attributes of the wrapper that</div><div class="line"> are updated with the corresponding attribute from the wrapped</div><div class="line"> function (defaults to functools.WRAPPER_UPDATES)</div><div class="line"> """</div><div class="line"> <span class="keyword">for</span> attr <span class="keyword">in</span> assigned:</div><div class="line"> setattr(wrapper, attr, getattr(wrapped, attr))</div><div class="line"> <span class="keyword">for</span> attr <span class="keyword">in</span> updated:</div><div class="line"> getattr(wrapper, attr).update(getattr(wrapped, attr, {}))</div><div class="line"> <span class="comment"># Return the wrapper so this can be used as a decorator via partial()</span></div><div class="line"> <span class="keyword">return</span> wrapper</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">wraps</span><span class="params">(wrapped,</span></span></div><div class="line"> assigned = WRAPPER_ASSIGNMENTS,</div><div class="line"> updated = WRAPPER_UPDATES):</div><div class="line"> <span class="string">"""Decorator factory to apply update_wrapper() to a wrapper function</span></div><div class="line"></div><div class="line"> Returns a decorator that invokes update_wrapper() with the decorated</div><div class="line"> function as the wrapper argument and the arguments to wraps() as the</div><div class="line"> remaining arguments. Default arguments are as for update_wrapper().</div><div class="line"> This is a convenience function to simplify applying partial() to</div><div class="line"> update_wrapper().</div><div class="line"> """</div><div class="line"> <span class="keyword">return</span> partial(update_wrapper, wrapped=wrapped,</div><div class="line"> assigned=assigned, updated=updated)</div></pre></td></tr></table></figure>
<p>所以<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></pre></td><td class="code"><pre><div class="line">add = logged(add) == wraps(add)(wrapper)</div><div class="line">==></div><div class="line">1. wraps(add) 返回一个 partialobject 实例(pto),他封装的函数是 update_wrapper</div><div class="line">2. wraps(add)(wrapper) 相当于执行 partial_call</div><div class="line"> partial_call</div><div class="line"> --> ret = PyObject_Call(pto->fn, argappl, kwappl) --> update_wrapper()</div><div class="line"> --> update_wrapper() --> return add</div></pre></td></tr></table></figure></p>
<p>这样绕了一圈 add 终于还是等于 add 了</p>
<h3 id="带参数的情况"><a href="#带参数的情况" class="headerlink" title="带参数的情况"></a>带参数的情况</h3><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="meta">@logged(level=logging.CRITICAL, name='example')</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">spam</span><span class="params">()</span>:</span></div><div class="line"> print(<span class="string">'Spam!'</span>)</div></pre></td></tr></table></figure>
<p>相当于</p>
<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></pre></td><td class="code"><pre><div class="line">add = logged(level=logging.CRITICAL, name='example')(add) == partial(logged,xxx)(add)</div><div class="line"></div><div class="line">partial 封装的是logged, 参数:level=logging.CRITICAL, name='example'也被带入partial</div><div class="line">-->partial_new(logged,level=logging.CRITICAL, name='example')</div><div class="line"></div><div class="line">partial(logged,xxx)(add) 调用 partial_call</div><div class="line">-->partial_call(add)</div><div class="line">-->logged(add,level=logging.CRITICAL, name='example')</div><div class="line">不过这里有个疑问是,logged 怎么指定 func==add?, add是作为PyTuple传入的,不是PyDict</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>主要topic</p>
<ul>
<li>Decorator是怎么调用的</li>
<li>用partial来实现一个带参数的Decorator</li>
</ul>
<h2 id="Decorator的调用"><a href="#Decorator的调用" class="
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python Decorator - 理解partial</title>
<link href="http://superway117.github.io/2016/12/12/py_decorator_1/"/>
<id>http://superway117.github.io/2016/12/12/py_decorator_1/</id>
<published>2016-12-12T15:42:20.000Z</published>
<updated>2016-12-16T02:49:00.079Z</updated>
<content type="html"><![CDATA[<p>主要topic是partial的源码实现</p>
<h2 id="什么是partial"><a href="#什么是partial" class="headerlink" title="什么是partial"></a>什么是partial</h2><p><code>partial</code> 是<code>functools</code>里面的一个函数对象,虽然用起来就是一个函数.</p>
<p>它是一个<code>decorator function</code>,也就是说用来decorator其他函数的.</p>
<p>比如decorator add函数,它的第一个参数必须是一个函数,后面的参数,在真正执行add的时候,会带入到add里面,作为add的参数.</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">In [<span class="number">9</span>]: <span class="keyword">from</span> functools <span class="keyword">import</span> partial</div><div class="line"></div><div class="line">In [<span class="number">10</span>]: <span class="function"><span class="keyword">def</span> <span class="title">add</span><span class="params">(a,b)</span>:</span></div><div class="line">....: <span class="keyword">return</span> a+b</div><div class="line">....:</div><div class="line"></div><div class="line">In [<span class="number">11</span>]: add(<span class="number">4</span>,<span class="number">3</span>)</div><div class="line">Out[<span class="number">11</span>]: <span class="number">7</span></div><div class="line"></div><div class="line">In [<span class="number">12</span>]: plus = partial(add,<span class="number">100</span>)</div><div class="line"></div><div class="line">In [<span class="number">13</span>]: plus(<span class="number">9</span>)</div><div class="line">Out[<span class="number">13</span>]: <span class="number">109</span></div><div class="line"></div><div class="line">In [<span class="number">14</span>]: plus2 = partial(add,<span class="number">99</span>)</div><div class="line"></div><div class="line">In [<span class="number">15</span>]: plus2(<span class="number">9</span>)</div><div class="line">Out[<span class="number">15</span>]: <span class="number">108</span></div></pre></td></tr></table></figure>
<h2 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h2><p>打开python 2.7的源码,partial是用C语言实现的,对应的源码在 </p>
<blockquote>
<p>Python-2.7.11\Modules\_functoolsmodule.c</p>
</blockquote>
<p>主要3个函数:</p>
<ul>
<li>partial_new: 执行plus = partial(add,100),会创建一个partialobject对象</li>
<li>partial_dealloc: 释放partialobject对象</li>
<li>partial_call: 执行plus(9),会调用到这个函数</li>
<li>partial_setstate: 这个用来替换前面传入的add,以及参数, 一般情况很少用</li>
</ul>
<p>下面的这些函数,一般情况是用不上.</p>
<ul>
<li>partial_traverse</li>
<li>partial_get_dict</li>
<li>partial_set_dict</li>
</ul>
<h3 id="partial-new"><a href="#partial-new" class="headerlink" title="partial_new"></a>partial_new</h3><ul>
<li>创建partialobject对象</li>
<li><p>args是一个<code>PyTuple</code>,第一个参数必须是一个<code>PyCallable</code>,简单的说就是一个函数对象</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">func = PyTuple_GET_ITEM(args, <span class="number">0</span>);</div></pre></td></tr></table></figure>
</li>
<li><p>args其他的参数会保存为 <code>pto->args</code></p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pto->args = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);</div></pre></td></tr></table></figure>
</li>
<li><p>kw如果存在会被<code>复制</code>一份</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pto->kw = (kw != NULL) ? PyDict_Copy(kw) : PyDict_New();</div></pre></td></tr></table></figure>
</li>
<li><p>dict默认是null, 后面可以通过<code>partial_set_dict</code>来设置</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pto->dict = NULL;</div></pre></td></tr></table></figure>
</li>
</ul>
<p>source code<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><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div></pre></td><td class="code"><pre><div class="line">static PyObject *</div><div class="line">partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)</div><div class="line">{</div><div class="line"> PyObject *func;</div><div class="line"> partialobject *pto;</div><div class="line"></div><div class="line"> if (PyTuple_GET_SIZE(args) < 1) {</div><div class="line"> PyErr_SetString(PyExc_TypeError,</div><div class="line"> "type 'partial' takes at least one argument");</div><div class="line"> return NULL;</div><div class="line"> }</div><div class="line"></div><div class="line"> func = PyTuple_GET_ITEM(args, 0);</div><div class="line"> if (!PyCallable_Check(func)) {</div><div class="line"> PyErr_SetString(PyExc_TypeError,</div><div class="line"> "the first argument must be callable");</div><div class="line"> return NULL;</div><div class="line"> }</div><div class="line"></div><div class="line"> /* create partialobject structure */</div><div class="line"> pto = (partialobject *)type->tp_alloc(type, 0);</div><div class="line"> if (pto == NULL)</div><div class="line"> return NULL;</div><div class="line"></div><div class="line"> pto->fn = func;</div><div class="line"> Py_INCREF(func);</div><div class="line"> pto->args = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);</div><div class="line"> if (pto->args == NULL) {</div><div class="line"> pto->kw = NULL;</div><div class="line"> Py_DECREF(pto);</div><div class="line"> return NULL;</div><div class="line"> }</div><div class="line"> pto->kw = (kw != NULL) ? PyDict_Copy(kw) : PyDict_New();</div><div class="line"> if (pto->kw == NULL) {</div><div class="line"> Py_DECREF(pto);</div><div class="line"> return NULL;</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> pto->weakreflist = NULL;</div><div class="line"> pto->dict = NULL;</div><div class="line"></div><div class="line"> return (PyObject *)pto;</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h3 id="partial-dealloc"><a href="#partial-dealloc" class="headerlink" title="partial_dealloc"></a>partial_dealloc</h3><p>new创建的所有对象的引用计数全部dec一下</p>
<h3 id="partial-call"><a href="#partial-call" class="headerlink" title="partial_call"></a>partial_call</h3><ul>
<li>执行plus(9),会调用到这个函数</li>
<li><p>args会做一次合并,如果都不为空的话</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">argappl = PySequence_Concat(pto->args, args);</div></pre></td></tr></table></figure>
</li>
<li><p>kw会做一次合并,如果都不为空的话</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (PyDict_Merge(kwappl, kw, <span class="number">1</span>) != <span class="number">0</span>)</div></pre></td></tr></table></figure>
</li>
</ul>
<p>基本上看到这里,大概能理解<code>partial</code>的作用了.</p>
<p>source code<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><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div></pre></td><td class="code"><pre><div class="line">static PyObject *</div><div class="line">partial_call(partialobject *pto, PyObject *args, PyObject *kw)</div><div class="line">{</div><div class="line"> PyObject *ret;</div><div class="line"> PyObject *argappl = NULL, *kwappl = NULL;</div><div class="line"></div><div class="line"> assert (PyCallable_Check(pto->fn));</div><div class="line"> assert (PyTuple_Check(pto->args));</div><div class="line"> assert (pto->kw == Py_None || PyDict_Check(pto->kw));</div><div class="line"></div><div class="line"> if (PyTuple_GET_SIZE(pto->args) == 0) {</div><div class="line"> argappl = args;</div><div class="line"> Py_INCREF(args);</div><div class="line"> } else if (PyTuple_GET_SIZE(args) == 0) {</div><div class="line"> argappl = pto->args;</div><div class="line"> Py_INCREF(pto->args);</div><div class="line"> } else {</div><div class="line"> argappl = PySequence_Concat(pto->args, args);</div><div class="line"> if (argappl == NULL)</div><div class="line"> return NULL;</div><div class="line"> }</div><div class="line"></div><div class="line"> if (pto->kw == Py_None) {</div><div class="line"> kwappl = kw;</div><div class="line"> Py_XINCREF(kw);</div><div class="line"> } else {</div><div class="line"> kwappl = PyDict_Copy(pto->kw);</div><div class="line"> if (kwappl == NULL) {</div><div class="line"> Py_DECREF(argappl);</div><div class="line"> return NULL;</div><div class="line"> }</div><div class="line"> if (kw != NULL) {</div><div class="line"> if (PyDict_Merge(kwappl, kw, 1) != 0) {</div><div class="line"> Py_DECREF(argappl);</div><div class="line"> Py_DECREF(kwappl);</div><div class="line"> return NULL;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> ret = PyObject_Call(pto->fn, argappl, kwappl);</div><div class="line"> Py_DECREF(argappl);</div><div class="line"> Py_XDECREF(kwappl);</div><div class="line"> return ret;</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h2 id="partial的帮手"><a href="#partial的帮手" class="headerlink" title="partial的帮手"></a>partial的帮手</h2><p>从source code里面copy出来的注释:</p>
<blockquote>
<p>update_wrapper() and wraps() are tools to help write wrapper functions that can handle naive introspection</p>
</blockquote>
<p>简单的说,decorator function会导致被 decorator的函数,原有的<strong>module</strong>,<strong>name</strong>,<strong>doc</strong>丢失. update_wrapper() and wraps()就是为了解决这个问题存在的. 所以一般来说,还是多用<code>wraps</code>比较好,他会保留原函数的信息.</p>
<p>但是<code>wraps</code>有一个限制,用了这个函数,第一个参数是函数对象, 后面没机会他给传其他参数了.也就是说,只能传被wrapper的函数,后面调用的时候自己传了. <code>partial</code>就没用这个限制.</p>
<h3 id="Usage"><a href="#Usage" class="headerlink" title="Usage"></a>Usage</h3><p>下面是一个例子,用wraps来实现怎么打印一个函数的时间消耗.</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> time</div><div class="line"><span class="keyword">from</span> functools <span class="keyword">import</span> wraps</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">timethis</span><span class="params">(func)</span>:</span></div><div class="line"> <span class="string">'''</span></div><div class="line"> Decorator that reports the execution time.</div><div class="line"> '''</div><div class="line"><span class="meta"> @wraps(func)</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(*args, **kwargs)</span>:</span></div><div class="line"> start = time.time()</div><div class="line"> result = func(*args, **kwargs)</div><div class="line"> end = time.time()</div><div class="line"> print(func.__name__, end-start)</div><div class="line"> <span class="keyword">return</span> result</div><div class="line"> <span class="keyword">return</span> wrapper</div></pre></td></tr></table></figure>
<p>Here is an example of using the decorator:</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></pre></td><td class="code"><pre><div class="line"><span class="meta">>>> </span>@timethis</div><div class="line"><span class="meta">... </span><span class="function"><span class="keyword">def</span> <span class="title">countdown</span><span class="params">(n)</span>:</span></div><div class="line"><span class="meta">... </span><span class="string">'''</span></div><div class="line"><span class="meta">... </span>Counts down</div><div class="line"><span class="meta">... </span>'''</div><div class="line"><span class="meta">... </span><span class="keyword">while</span> n > <span class="number">0</span>:</div><div class="line"><span class="meta">... </span>n -= <span class="number">1</span></div><div class="line">...</div><div class="line"><span class="meta">>>> </span>countdown(<span class="number">100000</span>)</div><div class="line">countdown <span class="number">0.008917808532714844</span></div><div class="line"><span class="meta">>>> </span>countdown(<span class="number">10000000</span>)</div><div class="line">countdown <span class="number">0.87188299392912</span></div><div class="line">>>></div></pre></td></tr></table></figure>
<p>前面提到wraps,只能</p>
<h3 id="源码分析-1"><a href="#源码分析-1" class="headerlink" title="源码分析"></a>源码分析</h3><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><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line">WRAPPER_ASSIGNMENTS = (<span class="string">'__module__'</span>, <span class="string">'__name__'</span>, <span class="string">'__doc__'</span>)</div><div class="line">WRAPPER_UPDATES = (<span class="string">'__dict__'</span>,)</div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">update_wrapper</span><span class="params">(wrapper,</span></span></div><div class="line"> wrapped,</div><div class="line"> assigned = WRAPPER_ASSIGNMENTS,</div><div class="line"> updated = WRAPPER_UPDATES):</div><div class="line"> <span class="string">"""Update a wrapper function to look like the wrapped function</span></div><div class="line"></div><div class="line"> wrapper is the function to be updated</div><div class="line"> wrapped is the original function</div><div class="line"> assigned is a tuple naming the attributes assigned directly</div><div class="line"> from the wrapped function to the wrapper function (defaults to</div><div class="line"> functools.WRAPPER_ASSIGNMENTS)</div><div class="line"> updated is a tuple naming the attributes of the wrapper that</div><div class="line"> are updated with the corresponding attribute from the wrapped</div><div class="line"> function (defaults to functools.WRAPPER_UPDATES)</div><div class="line"> """</div><div class="line"> <span class="keyword">for</span> attr <span class="keyword">in</span> assigned:</div><div class="line"> setattr(wrapper, attr, getattr(wrapped, attr))</div><div class="line"> <span class="keyword">for</span> attr <span class="keyword">in</span> updated:</div><div class="line"> getattr(wrapper, attr).update(getattr(wrapped, attr, {}))</div><div class="line"> <span class="comment"># Return the wrapper so this can be used as a decorator via partial()</span></div><div class="line"> <span class="keyword">return</span> wrapper</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">wraps</span><span class="params">(wrapped,</span></span></div><div class="line"> assigned = WRAPPER_ASSIGNMENTS,</div><div class="line"> updated = WRAPPER_UPDATES):</div><div class="line"> <span class="string">"""Decorator factory to apply update_wrapper() to a wrapper function</span></div><div class="line"></div><div class="line"> Returns a decorator that invokes update_wrapper() with the decorated</div><div class="line"> function as the wrapper argument and the arguments to wraps() as the</div><div class="line"> remaining arguments. Default arguments are as for update_wrapper().</div><div class="line"> This is a convenience function to simplify applying partial() to</div><div class="line"> update_wrapper().</div><div class="line"> """</div><div class="line"> <span class="keyword">return</span> partial(update_wrapper, wrapped=wrapped,</div><div class="line"> assigned=assigned, updated=updated)</div></pre></td></tr></table></figure>
<h3 id="Notes"><a href="#Notes" class="headerlink" title="Notes"></a>Notes</h3><p>copy from python cookbook</p>
<blockquote>
<p>Last, but not least, be aware that not all decorators utilize @wraps, and thus, they may not work as described. In particular, the built-in decorators @staticmethod and @class method create descriptor objects that don’t follow this convention (instead, they store the original function in a <strong>func</strong> attribute). Your mileage may vary.</p>
</blockquote>
]]></content>
<summary type="html">
<p>主要topic是partial的源码实现</p>
<h2 id="什么是partial"><a href="#什么是partial" class="headerlink" title="什么是partial"></a>什么是partial</h2><p><code>part
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python Package管理</title>
<link href="http://superway117.github.io/2016/12/09/py_package_import/"/>
<id>http://superway117.github.io/2016/12/09/py_package_import/</id>
<published>2016-12-09T04:49:52.000Z</published>
<updated>2016-12-09T06:39:41.952Z</updated>
<content type="html"><![CDATA[<h2 id="init-py"><a href="#init-py" class="headerlink" title="init.py"></a><strong>init</strong>.py</h2><p>module(包括sub module)目录下面, 在py2.7上面,这个文件是需要的;在3.x上面,这个文件已经不是必须的.</p>
<p><code>__init__</code>是会被在module(submodule)加载之前加载 .</p>
<p><code>__init__</code>可以用来实现下面的功能:</p>
<ol>
<li><p>帮用户加载需要的submodule或者符号 </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="comment"># graphics/formats/__init__.py</span></div><div class="line"><span class="keyword">from</span> . <span class="keyword">import</span> jpg</div><div class="line"><span class="keyword">from</span> . <span class="keyword">import</span> png</div></pre></td></tr></table></figure>
<p>这样的话用户只需要下面的语句,就可以得到需要的符号</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">import graphics.formats</div></pre></td></tr></table></figure>
</li>
</ol>
<h2 id="如何控制-export-symbol"><a href="#如何控制-export-symbol" class="headerlink" title="如何控制 export symbol"></a>如何控制 export symbol</h2><h3 id="Problem"><a href="#Problem" class="headerlink" title="Problem"></a>Problem</h3><p>下面的语句会导致把<code>module</code>里面的所有符号都导出. </p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> module <span class="keyword">import</span> *</div></pre></td></tr></table></figure>
<p>这样的做法是不受鼓励的,但是事实上为了方便,我们经常这么干.</p>
<p>从性能或者从安全的角度出发,很多时候我们要控制export的符号</p>
<h3 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h3><p><code>__all__</code> 可以帮你控制输出的符号</p>
<p>demo<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></pre></td><td class="code"><pre><div class="line"><span class="comment"># somemodule.py</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">spam</span><span class="params">()</span>:</span></div><div class="line"> <span class="keyword">pass</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">grok</span><span class="params">()</span>:</span></div><div class="line"> <span class="keyword">pass</span></div><div class="line"></div><div class="line">blah = <span class="number">42</span></div><div class="line"><span class="comment"># Only export 'spam' and 'grok'</span></div><div class="line">__all__ = [<span class="string">'spam'</span>, <span class="string">'grok'</span>]</div></pre></td></tr></table></figure></p>
<ul>
<li>如果你定义了<code>__all__</code>为一个空数组,那么nothing will be exported.</li>
<li>AttributeError is raised on import if <strong>all</strong> contains undefined names.</li>
</ul>
<h2 id="Namespace-Packages"><a href="#Namespace-Packages" class="headerlink" title="Namespace Packages"></a>Namespace Packages</h2><p>“namespace package” Essentially, a namespace package is a special kind of package designed for merging different directories of code together under a common namespace</p>
<p>links</p>
<ul>
<li><a href="https://www.python.org/dev/peps/pep-0420/" target="_blank" rel="external">Implicit Namespace Packages</a></li>
</ul>
]]></content>
<summary type="html">
<h2 id="init-py"><a href="#init-py" class="headerlink" title="init.py"></a><strong>init</strong>.py</h2><p>module(包括sub module)目录下面, 在py2.7上
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
<entry>
<title>Python Thread Local</title>
<link href="http://superway117.github.io/2016/12/07/py_thread_local/"/>
<id>http://superway117.github.io/2016/12/07/py_thread_local/</id>
<published>2016-12-06T16:54:05.000Z</published>
<updated>2016-12-12T15:52:48.063Z</updated>
<content type="html"><![CDATA[<h2 id="Problem"><a href="#Problem" class="headerlink" title="Problem"></a>Problem</h2><p>如何实现: 保存线程自己的值或者状态,并且这个值对其他线程是不可见</p>
<h2 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h2><p><code>thread-local storage object</code> 可以用来满足这个需求,<code>thread-local</code>只有当前的线程可见.</p>
<h2 id="Sample-Code"><a href="#Sample-Code" class="headerlink" title="Sample Code"></a>Sample Code</h2><p>下面的code demo了怎么样使用 thread-local</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><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><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> socket <span class="keyword">import</span> socket, AF_INET, SOCK_STREAM</div><div class="line"><span class="keyword">import</span> threading</div><div class="line"><span class="keyword">from</span> functools <span class="keyword">import</span> partial</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">LazyConnection</span>:</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, address, family=AF_INET, type=SOCK_STREAM)</span>:</span></div><div class="line"> self.address = address</div><div class="line"> self.family = AF_INET</div><div class="line"> self.type = SOCK_STREAM</div><div class="line"> self.local = threading.local()</div><div class="line"> <span class="keyword">print</span> <span class="string">"__init__"</span></div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__enter__</span><span class="params">(self)</span>:</span></div><div class="line"> <span class="keyword">print</span> <span class="string">"__enter__"</span></div><div class="line"> <span class="keyword">if</span> hasattr(self.local, <span class="string">'sock'</span>):</div><div class="line"> <span class="keyword">raise</span> RuntimeError(<span class="string">'Already connected'</span>)</div><div class="line"> self.local.sock = socket(self.family, self.type)</div><div class="line"> self.local.sock.connect(self.address)</div><div class="line"> <span class="keyword">return</span> self.local.sock</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__exit__</span><span class="params">(self, exc_ty, exc_val, tb)</span>:</span></div><div class="line"> <span class="keyword">print</span> <span class="string">"__exit__"</span></div><div class="line"> self.local.sock.close()</div><div class="line"> <span class="keyword">del</span> self.local.sock</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">test</span><span class="params">(conn)</span>:</span></div><div class="line"> <span class="keyword">with</span> conn <span class="keyword">as</span> s:</div><div class="line"> s.send(<span class="string">b'GET /index.html HTTP/1.0\r\n'</span>)</div><div class="line"> s.send(<span class="string">b'Host: www.python.org\r\n'</span>)</div><div class="line"></div><div class="line"> s.send(<span class="string">b'\r\n'</span>)</div><div class="line"> resp = <span class="string">b''</span>.join(iter(partial(s.recv, <span class="number">8192</span>), <span class="string">b''</span>))</div><div class="line"> print(<span class="string">'Got {} bytes'</span>.format(len(resp)))</div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line"> conn = LazyConnection((<span class="string">'www.python.org'</span>, <span class="number">80</span>))</div><div class="line"> t1 = threading.Thread(target=test, args=(conn,))</div><div class="line"> t2 = threading.Thread(target=test, args=(conn,))</div><div class="line"> t1.start()</div><div class="line"> t2.start()</div><div class="line"> t1.join()</div><div class="line"> t2.join()</div></pre></td></tr></table></figure>
<p>打印的结果</p>
<figure class="highlight plain"><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></pre></td><td class="code"><pre><div class="line">__init__</div><div class="line">__enter__</div><div class="line">__enter__</div><div class="line">Got 795 bytes</div><div class="line">__exit__</div><div class="line">Got 795 bytes</div><div class="line">__exit__</div></pre></td></tr></table></figure>
<h2 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h2><p>打开python 2.7的源码,thread local 对应的源码在 </p>
<blockquote>
<p>Python-2.7.11\Lib\_threading_local.py</p>
</blockquote>
<p>thread local 就是下面的继承关系</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">object > _localbase > local</div></pre></td></tr></table></figure>
<h3 id="如何实现线程独立拥有自己的local"><a href="#如何实现线程独立拥有自己的local" class="headerlink" title="如何实现线程独立拥有自己的local"></a>如何实现线程独立拥有自己的local</h3><p>仔细看上面的code, LazyConnection 只实例化了一次,也就是说<code>__init__</code>只调用了一次,所以<code>conn</code>对各个线程来说是共享的,为什么下面的 socket 赋值可以做到各个线程拥有独立的sock对象?</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">self.local.sock = socket(self.family, self.type)</div></pre></td></tr></table></figure>
<p>虽然new 一个 local 实例, 这个实例对于所有线程是共享的,但是真正执行set/get操作的实现在 _patch,这个函数是关键.</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">_patch</span><span class="params">(self)</span>:</span></div><div class="line"> key = object.__getattribute__(self, <span class="string">'_local__key'</span>)</div><div class="line"> d = current_thread().__dict__.get(key)</div><div class="line"> <span class="keyword">if</span> d <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line"> d = {}</div><div class="line"> current_thread().__dict__[key] = d</div><div class="line"> object.__setattr__(self, <span class="string">'__dict__'</span>, d)</div><div class="line"></div><div class="line"> <span class="comment"># we have a new instance dict, so call out __init__ if we have</span></div><div class="line"> <span class="comment"># one</span></div><div class="line"> cls = type(self)</div><div class="line"> <span class="keyword">if</span> cls.__init__ <span class="keyword">is</span> <span class="keyword">not</span> object.__init__:</div><div class="line"> args, kw = object.__getattribute__(self, <span class="string">'_local__args'</span>)</div><div class="line"> cls.__init__(self, *args, **kw)</div><div class="line"> <span class="keyword">else</span>:</div><div class="line"> object.__setattr__(self, <span class="string">'__dict__'</span>, d)</div></pre></td></tr></table></figure>
<p>先看 if d is not None 的case</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">object.__setattr__(self, <span class="string">'__dict__'</span>, d)</div></pre></td></tr></table></figure>
<p>也就是说 每次set/get的时候,上面这句话改变了 <code>__dict__</code>,他把 <code>current_thread().__dict__.get(key)</code> 赋值给了<code>__dict__</code>, 而对object的set/get 操作,实际也就是对 <code>__dict__</code>的操作.</p>
<h3 id="如何实现lock"><a href="#如何实现lock" class="headerlink" title="如何实现lock"></a>如何实现lock</h3><p>因为每次都要改变local.<strong>dict</strong>,必然存在一个问题,就是要锁操作.</p>
<p>下面的代码会构造一个RLock 给 local, 注意,这个rlock是给local的,也就是说所有线程都是用这个rlock来执行锁操作的.</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><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">_localbase</span><span class="params">(object)</span>:</span></div><div class="line"> __slots__ = <span class="string">'_local__key'</span>, <span class="string">'_local__args'</span>, <span class="string">'_local__lock'</span></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, *args, **kw)</span>:</span></div><div class="line"> self = object.__new__(cls)</div><div class="line"> key = <span class="string">'_local__key'</span>, <span class="string">'thread.local.'</span> + str(id(self))</div><div class="line"> object.__setattr__(self, <span class="string">'_local__key'</span>, key)</div><div class="line"> object.__setattr__(self, <span class="string">'_local__args'</span>, (args, kw))</div><div class="line"> object.__setattr__(self, <span class="string">'_local__lock'</span>, RLock())</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (args <span class="keyword">or</span> kw) <span class="keyword">and</span> (cls.__init__ <span class="keyword">is</span> object.__init__):</div><div class="line"> <span class="keyword">raise</span> TypeError(<span class="string">"Initialization arguments are not supported"</span>)</div><div class="line"></div><div class="line"> <span class="comment"># We need to create the thread dict in anticipation of</span></div><div class="line"> <span class="comment"># __init__ being called, to make sure we don't call it</span></div><div class="line"> <span class="comment"># again ourselves.</span></div><div class="line"> dict = object.__getattribute__(self, <span class="string">'__dict__'</span>)</div><div class="line"> current_thread().__dict__[key] = dict</div><div class="line"></div><div class="line"> <span class="keyword">return</span> self</div></pre></td></tr></table></figure>
<p>看下local get操作 ,进入之前acquire,finally 保证了释放</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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">__getattribute__</span><span class="params">(self, name)</span>:</span></div><div class="line"> lock = object.__getattribute__(self, <span class="string">'_local__lock'</span>)</div><div class="line"> lock.acquire()</div><div class="line"> <span class="keyword">try</span>:</div><div class="line"> _patch(self)</div><div class="line"> <span class="keyword">return</span> object.__getattribute__(self, name)</div><div class="line"> <span class="keyword">finally</span>:</div><div class="line"> lock.release()</div></pre></td></tr></table></figure>
<h3 id="slots"><a href="#slots" class="headerlink" title="__slots__"></a>__slots__</h3><p>_localbase 用 __slots__ 来限制 local的 instance variables</p>
<p>__slots__ 的解释: copy from <a href="https://www.python.org/download/releases/2.2.2/descrintro/" target="_blank" rel="external">python org</a></p>
<blockquote>
<p>The __slots__ declaration takes a list of instance variables, and reserves space in the instance for exactly these in the instance. When __slots__ is used, other instance variables cannot be assigned to</p>
</blockquote>
<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="class"><span class="keyword">class</span> <span class="title">defaultdict2</span><span class="params">(dict)</span>:</span></div><div class="line"></div><div class="line"> __slots__ = [<span class="string">'default'</span>]</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, default=None)</span>:</span></div><div class="line"> ...(like before)...</div></pre></td></tr></table></figure>
<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></pre></td><td class="code"><pre><div class="line">>>> a = defaultdict2(default=0.0)</div><div class="line">>>> a[1]</div><div class="line">0.0</div><div class="line">>>> a.default = -1</div><div class="line">>>> a[1]</div><div class="line">-1</div><div class="line">>>> a.x1 = 1</div><div class="line">Traceback (most recent call last):</div><div class="line"> File "<stdin>", line 1, in ?</div><div class="line">AttributeError: 'defaultdict2' object has no attribute 'x1'</div><div class="line">>>></div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h2 id="Problem"><a href="#Problem" class="headerlink" title="Problem"></a>Problem</h2><p>如何实现: 保存线程自己的值或者状态,并且这个值对其他线程是不可见</p>
<h2 id="Solu
</summary>
<category term="python" scheme="http://superway117.github.io/tags/python/"/>
</entry>
</feed>