-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpython-withyu-ju.html
More file actions
291 lines (245 loc) · 16.2 KB
/
python-withyu-ju.html
File metadata and controls
291 lines (245 loc) · 16.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
<link rel="short icon" href="http://softing.qiniudn.com/20140603011448867_easyicon_net_128.ico" type="image/x-ico">
<meta charset="utf-8">
<title>Python with语句</title>
<meta name="author" content="tulpar">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <link href="/favicon.png" rel="icon"> -->
<link href="/theme/css/main.css" media="screen, projection"
rel="stylesheet" type="text/css">
<script src="/theme/js/modernizr-2.0.js"></script>
<script src="/theme/js/ender.js"></script>
<script src="/theme/js/octopress.js" type="text/javascript"></script>
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic"
rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic"
rel="stylesheet" type="text/css">
</head>
<body>
<header role="banner"><hgroup>
<h1><a href="/">Dreaming</a></h1>
</hgroup></header>
<nav role="navigation"><ul class="subscription" data-subscription="rss">
</ul>
<ul class="main-navigation">
<li class="active">
<a href="/category/it.html">It</a>
</li>
<li >
<a href="/category/life.html">Life</a>
</li>
</ul></nav>
<div id="main">
<div id="content">
<div>
<article class="hentry" role="article">
<header>
<h1 class="entry-title">Python with语句</h1>
<p class="meta"><time datetime="2014-07-03T00:00:00+08:00" pubdate>Thu 03 July 2014</time></p>
</header>
<div class="entry-content"><p>感谢<a href="http://sdqali.in/blog/2012/07/09/understanding-pythons-with/">Sadique Ali</a>的总结分享</p>
<h3>With语句是什么?</h3>
<p>有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。 <br />
一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。</p>
<p>如果不用with语句,代码如下:</p>
<div class="highlight"><pre><span class="n">file</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="s">"/tmp/foo.txt"</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">file</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
<p>这里有两个问题。一是可能忘记关闭文件句柄;二是文件读取数据发生异常,没有进行任何处理。下面是处理异常的加强版本:</p>
<div class="highlight"><pre><span class="n">file</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="s">"/tmp/foo.txt"</span><span class="p">)</span>
<span class="nl">try:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="nl">finally:</span>
<span class="n">file</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
<p>虽然这段代码运行良好,但是太冗长了。这时候就是with一展身手的时候了。除了有更优雅的语法,with还可以很好的处理上下文环境产生的异常。下面是with版本的代码:</p>
<div class="highlight"><pre><span class="n">with</span> <span class="n">open</span><span class="p">(</span><span class="s">"/tmp/foo.txt"</span><span class="p">)</span> <span class="n">as</span> <span class="n">file</span><span class="o">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
</pre></div>
<h3>with如何工作?</h3>
<p>这看起来充满魔法,但不仅仅是魔法,Python对with的处理还很聪明。基本思想是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。 </p>
<p>紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。</p>
<p>下面例子可以具体说明with如何工作:</p>
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre></div></td><td class="code"><div class="highlight"><pre><span class="c">#!/usr/bin/env python</span>
<span class="c"># with_example01.py</span>
<span class="k">class</span> <span class="nc">Sample</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">print</span> <span class="s">"In __enter__()"</span>
<span class="k">return</span> <span class="s">"Foo"</span>
<span class="k">def</span> <span class="nf">__exit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">type</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">trace</span><span class="p">):</span>
<span class="k">print</span> <span class="s">"In __exit__()"</span>
<span class="k">def</span> <span class="nf">get_sample</span><span class="p">():</span>
<span class="k">return</span> <span class="n">Sample</span><span class="p">()</span>
<span class="k">with</span> <span class="n">get_sample</span><span class="p">()</span> <span class="k">as</span> <span class="n">sample</span><span class="p">:</span>
<span class="k">print</span> <span class="s">"sample:"</span><span class="p">,</span> <span class="n">sample</span>
</pre></div>
</td></tr></table>
<p>运行代码,输出如下</p>
<div class="highlight"><pre><span class="n">bash</span><span class="o">-</span><span class="mf">3.2</span><span class="err">$</span> <span class="p">.</span><span class="o">/</span><span class="n">with_example01</span><span class="p">.</span><span class="n">py</span>
<span class="n">In</span> <span class="n">__enter__</span><span class="p">()</span>
<span class="nl">sample:</span> <span class="n">Foo</span>
<span class="n">In</span> <span class="n">__exit__</span><span class="p">()</span>
</pre></div>
<p>正如你看到的, </p>
<div class="highlight"><pre><span class="mf">1.</span> <span class="n">__enter__</span><span class="p">()</span><span class="err">方法被执行</span>
<span class="mf">2.</span> <span class="n">__enter__</span><span class="p">()</span><span class="err">方法返回的值</span> <span class="o">-</span> <span class="err">这个例子中是</span><span class="s">"Foo"</span><span class="err">,赋值给变量'</span><span class="n">sample</span><span class="err">'</span>
<span class="mf">3.</span> <span class="err">执行代码块,打印变量</span><span class="s">"sample"</span><span class="err">的值为</span> <span class="s">"Foo"</span>
<span class="mf">4.</span> <span class="n">__exit__</span><span class="p">()</span><span class="err">方法被调用</span>
</pre></div>
<p>with真正强大之处是它可以处理异常。可能你已经注意到Sample类的__exit__方法有三个参数- val, type 和 trace。 这些参数在异常处理中相当有用。我们来改一下代码,看看具体如何工作的。</p>
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre></div></td><td class="code"><div class="highlight"><pre><span class="c">#!/usr/bin/env python</span>
<span class="c"># with_example02.py</span>
<span class="k">class</span> <span class="nc">Sample</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="k">def</span> <span class="nf">__exit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">type</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">trace</span><span class="p">):</span>
<span class="k">print</span> <span class="s">"type:"</span><span class="p">,</span> <span class="nb">type</span>
<span class="k">print</span> <span class="s">"value:"</span><span class="p">,</span> <span class="n">value</span>
<span class="k">print</span> <span class="s">"trace:"</span><span class="p">,</span> <span class="n">trace</span>
<span class="k">def</span> <span class="nf">do_something</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">bar</span> <span class="o">=</span> <span class="mi">1</span><span class="o">/</span><span class="mi">0</span>
<span class="k">return</span> <span class="n">bar</span> <span class="o">+</span> <span class="mi">10</span>
<span class="k">with</span> <span class="n">Sample</span><span class="p">()</span> <span class="k">as</span> <span class="n">sample</span><span class="p">:</span>
<span class="n">sample</span><span class="o">.</span><span class="n">do_something</span><span class="p">()</span>
</pre></div>
</td></tr></table>
<p>这个例子中,with后面的get_sample()变成了Sample()。这没有任何关系,只要紧跟with后面的语句所返回的对象有__enter__()和__exit__()方法即可。此例中,Sample()的__enter__()方法返回新创建的Sample对象,并赋值给变量sample。 </p>
<p>代码执行后:</p>
<div class="highlight"><pre><span class="nx">bash</span><span class="o">-</span><span class="mf">3.2</span><span class="err">$</span> <span class="nx">.</span><span class="p">/</span><span class="nx">with_example02.py</span>
<span class="k">type</span><span class="p">:</span> <span class="o"><</span><span class="k">type</span> <span class="s1">'exceptions.ZeroDivisionError'</span><span class="o">></span>
<span class="nb">value</span><span class="p">:</span> <span class="kt">integer</span> <span class="nx">division</span> <span class="ow">or</span> <span class="nx">modulo</span> <span class="k">by</span> <span class="nx">zero</span>
<span class="nb">trace</span><span class="p">:</span> <span class="o"><</span><span class="nx">traceback</span> <span class="nb">object</span> <span class="nx">at</span> <span class="mh">0x1004a8128</span><span class="o">></span>
<span class="nx">Traceback</span> <span class="p">(</span><span class="nx">most</span> <span class="nx">recent</span> <span class="nb">call</span> <span class="nb">last</span><span class="p">):</span>
<span class="nb">File</span> <span class="s2">"./with_example02.py"</span><span class="p">,</span> <span class="nb">line</span> <span class="mi">19</span><span class="p">,</span> <span class="k">in</span> <span class="o"><</span><span class="nx">module</span><span class="o">></span>
<span class="nx">sample.do_something</span><span class="p">()</span>
<span class="nb">File</span> <span class="s2">"./with_example02.py"</span><span class="p">,</span> <span class="nb">line</span> <span class="mi">15</span><span class="p">,</span> <span class="k">in</span> <span class="nx">do_something</span>
<span class="n">bar</span> <span class="o">=</span> <span class="mi">1</span><span class="p">/</span><span class="nx">0</span>
<span class="nx">ZeroDivisionError</span><span class="p">:</span> <span class="kt">integer</span> <span class="nx">division</span> <span class="ow">or</span> <span class="nx">modulo</span> <span class="k">by</span> <span class="nx">zero</span>
</pre></div>
<p>实际上,在with后面的代码块抛出任何异常时,<strong>exit</strong>()方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给__exit__()方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在__exit__方法当中。</p>
<p>因此,Python的with语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。 </p></div>
<footer>
<p class="meta">
<span class="byline author vcard">
Posted by <span class="fn">tulpar</span>
</span>
<time datetime="2014-07-03T00:00:00+08:00" pubdate>Thu 03 July 2014</time> <span class="categories">
<a class="category" href="/tag/python.html">Python</a>
</span>
</p><div class="sharing">
</div> </footer>
</article>
<!-- Duoshuo Comment BEGIN -->
<div class="ds-thread"></div>
<script type="text/javascript">
var duoshuoQuery = {short_name:"tlbog"};
(function() {
var ds = document.createElement('script');
ds.type = 'text/javascript';ds.async = true;
ds.src = 'http://static.duoshuo.com/embed.js';
ds.charset = 'UTF-8';
(document.getElementsByTagName('head')[0]
|| document.getElementsByTagName('body')[0]).appendChild(ds);
})();
</script>
<!-- Duoshuo Comment END -->
</div>
<aside class="sidebar">
<section>
<h1>Recent Posts</h1>
<ul id="recent_posts">
<li class="post">
<a href="/xie-bo-ke-jiao-ben.html">写博客脚本</a>
</li>
<li class="post">
<a href="/gong-zuo-shi-de-sui-bi.html">工作时的随笔</a>
</li>
<li class="post">
<a href="/ce-shi-wen-zhang.html">测试文章</a>
</li>
<li class="post">
<a href="/djangokai-qi-the-sites-framework.html">Django开启 the sites framework</a>
</li>
<li class="post">
<a href="/django-17shi-yong.html">Django 1.7试用</a>
</li>
</ul>
</section>
<section>
<h1>Categories</h1>
<ul id="recent_posts">
<li><a href="/category/it.html">It</a></li>
<li><a href="/category/life.html">Life</a></li>
</ul>
</section>
<section>
<h1>Tags</h1>
<a href="/tag/mysql.html">Mysql</a>, <a href="/tag/tmux.html">Tmux</a>, <a href="/tag/fan-qiang.html">翻墙</a>, <a href="/tag/linux.html">Linux</a>, <a href="/tag/edx.html">Edx</a>, <a href="/tag/virtualbox.html">VirtualBox</a>, <a href="/tag/wo-ai-wo-jia.html">我爱我家</a>, <a href="/tag/userena.html">userena</a>, <a href="/tag/xadmin.html">Xadmin</a>, <a href="/tag/shell.html">Shell</a>, <a href="/tag/python.html">Python</a>, <a href="/tag/djangopython.html">Django,python</a>, <a href="/tag/ssh.html">ssh</a>, <a href="/tag/ubuntu.html">Ubuntu</a>, <a href="/tag/git.html">Git</a>, <a href="/tag/ce-shi.html">测试</a>, <a href="/tag/ueditor.html">Ueditor</a>, <a href="/tag/github.html">Github</a>, <a href="/tag/socketio.html">Socket.io</a>, <a href="/tag/django.html">Django</a>, <a href="/tag/du-shu.html">读书</a>, <a href="/tag/bo-ke.html">博客</a>, <a href="/tag/ngrok.html">ngrok</a> </section>
<section>
<h1>Social</h1>
<ul>
<li><a href="http://izda.com" target="_blank">ئىزدە</a></li>
<li><a href="http://www.google.com" target="_blank">Google</a></li>
<li><a href="http://www.zhihu.com/" target="_blank">知乎</a></li>
<li><a href="http://www.douban.com/" target="_blank">豆瓣</a></li>
</ul>
</section>
<section>
<h1>Blogroll</h1>
<ul>
<li><a href="https://github.com/tulpar008" target="_blank">My Github</a></li>
<li><a href="#" target="_blank">tulpar008@gmail.com</a></li>
</ul>
</section>
</aside> </div>
</div>
<footer role="contentinfo"><p>
Copyright © 2013-2015 - tulpar -
<span class="credit">Powered by <a href="http://getpelican.com">Pelican</a></span>
</p></footer>
</body>
</html>