<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Python on My Blog</title><link>/tags/python/</link><description>Recent content in Python on My Blog</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Thu, 22 Sep 2016 00:00:00 +0000</lastBuildDate><atom:link href="/tags/python/index.xml" rel="self" type="application/rss+xml"/><item><title>pycharm profession active</title><link>/2016/09/22/pycharm-profession-active/</link><pubDate>Thu, 22 Sep 2016 00:00:00 +0000</pubDate><guid>/2016/09/22/pycharm-profession-active/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;profession的版本要比免费版多些功能,这里就不多介绍了,自己看官方.&lt;/p&gt;
&lt;h2 id="1授权服务器license-server-urls"&gt;1.授权服务器(License Server URLS):&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://idea.imsxm.com"&gt;http://idea.imsxm.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;**使用方法：**激活时选择License server 填入http://&lt;a href="http://idea.imsxm.com/"&gt;idea.imsxm.com&lt;/a&gt; 点击Active即可 &lt;img alt="active.jpg" loading="lazy" src="how-to-active.jpg"&gt; 。&lt;/p&gt;
&lt;p&gt;how-to-active: when active,type the url in License server address input box,and then press the Active button:)&lt;/p&gt;
&lt;h2 id="2local-proxy"&gt;2.local proxy&lt;/h2&gt;
&lt;p&gt;如果第一种方法被拌掉了,那么下载这个实现本地proxy代理 [&lt;a href="http://img.imsxm.com/idea_active_proxy.exe"&gt;idea_active_proxy.exe&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;open it and use &lt;a href="http://localhost:8888/"&gt;http://localhost:8888&lt;/a&gt; to active JB.when done,you can close it.&lt;/p&gt;
&lt;p&gt;意思就是下载这个idea_active_proxy.exe，实现反向代理，然后把http://idea.imsxm.com 换成 http://localhost:8888 即可。&lt;/p&gt;
&lt;p&gt;这样在新建项目的时候就可以看到除了pure Python意外的其他项目了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="new_project.png" loading="lazy" src="pycharm%E4%B8%93%E4%B8%9A%E7%89%88%E6%96%B0%E5%BB%BAproject.png"&gt;&lt;/p&gt;
&lt;p&gt;这种方法还是有点不好,那就是每次你运行pycharm的时候都要先运行这个&lt;code&gt;idea_active_proxy.exe&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="3localhost"&gt;3.localhost&lt;/h2&gt;
&lt;p&gt;第三种就更好了.&lt;/p&gt;
&lt;p&gt;首先在你的host文件中添加 &lt;code&gt;0.0.0.0 account.jetbrains.com&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后就是打开pycharm,在那个激活页面选择 &lt;code&gt;Activation code&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="active.jpg" loading="lazy" src="how-to-active.jpg"&gt;&lt;/p&gt;
&lt;p&gt;复制通用注册码,激活即可.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;EB101IWSWD-eyJsaWNlbnNlSWQiOiJFQjEwMUlXU1dEIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiIiwiYXNzaWduZWVFbWFpbCI6IiIsImxpY2Vuc2VSZXN0cmljdGlvbiI6IkZvciBlZHVjYXRpb25hbCB1c2Ugb25seSIsImNoZWNrQ29uY3VycmVudFVzZSI6ZmFsc2UsInByb2R1Y3RzIjpbeyJjb2RlIjoiSUkiLCJwYWlkVXBUbyI6IjIwMTgtMTAtMTQifSx7ImNvZGUiOiJSUzAiLCJwYWlkVXBUbyI6IjIwMTgtMTAtMTQifSx7ImNvZGUiOiJXUyIsInBhaWRVcFRvIjoiMjAxOC0xMC0xNCJ9LHsiY29kZSI6IlJEIiwicGFpZFVwVG8iOiIyMDE4LTEwLTE0In0seyJjb2RlIjoiUkMiLCJwYWlkVXBUbyI6IjIwMTgtMTAtMTQifSx7ImNvZGUiOiJEQyIsInBhaWRVcFRvIjoiMjAxOC0xMC0xNCJ9LHsiY29kZSI6IkRCIiwicGFpZFVwVG8iOiIyMDE4LTEwLTE0In0seyJjb2RlIjoiUk0iLCJwYWlkVXBUbyI6IjIwMTgtMTAtMTQifSx7ImNvZGUiOiJETSIsInBhaWRVcFRvIjoiMjAxOC0xMC0xNCJ9LHsiY29kZSI6IkFDIiwicGFpZFVwVG8iOiIyMDE4LTEwLTE0In0seyJjb2RlIjoiRFBOIiwicGFpZFVwVG8iOiIyMDE4LTEwLTE0In0seyJjb2RlIjoiUFMiLCJwYWlkVXBUbyI6IjIwMTgtMTAtMTQifSx7ImNvZGUiOiJDTCIsInBhaWRVcFRvIjoiMjAxOC0xMC0xNCJ9LHsiY29kZSI6IlBDIiwicGFpZFVwVG8iOiIyMDE4LTEwLTE0In0seyJjb2RlIjoiUlNVIiwicGFpZFVwVG8iOiIyMDE4LTEwLTE0In1dLCJoYXNoIjoiNjk0NDAzMi8wIiwiZ3JhY2VQZXJpb2REYXlzIjowLCJhdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlLCJpc0F1dG9Qcm9sb25nYXRlZCI6ZmFsc2V9-Gbb7jeR8JWOVxdUFaXfJzVU/O7c7xHQyaidCnhYLp7v32zdeXiHUU7vlrrm5y9ZX0lmQk3plCCsW+phrC9gGAPd6WDKhkal10qVNg0larCR2tQ3u8jfv1t2JAvWrMOJfFG9kKsJuw1P4TozZ/E7Qvj1cupf/rldhoOmaXMyABxNN1af1RV3bVhe4FFZe0p7xlIJF/ctZkFK62HYmh8V3AyhUNTzrvK2k+t/tlDJz2LnW7nYttBLHld8LabPlEEjpTHswhzlthzhVqALIgvF0uNbIJ5Uwpb7NqR4U/2ob0Z+FIcRpFUIAHEAw+RLGwkCge5DyZKfx+RoRJ/In4q/UpA==-MIIEPjCCAiagAwIBAgIBBTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTE1MTEwMjA4MjE0OFoXDTE4MTEwMTA4MjE0OFowETEPMA0GA1UEAwwGcHJvZDN5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcQkq+zdxlR2mmRYBPzGbUNdMN6OaXiXzxIWtMEkrJMO/5oUfQJbLLuMSMK0QHFmaI37WShyxZcfRCidwXjot4zmNBKnlyHodDij/78TmVqFl8nOeD5+07B8VEaIu7c3E1N+e1doC6wht4I4+IEmtsPAdoaj5WCQVQbrI8KeT8M9VcBIWX7fD0fhexfg3ZRt0xqwMcXGNp3DdJHiO0rCdU+Itv7EmtnSVq9jBG1usMSFvMowR25mju2JcPFp1+I4ZI+FqgR8gyG8oiNDyNEoAbsR3lOpI7grUYSvkB/xVy/VoklPCK2h0f0GJxFjnye8NT1PAywoyl7RmiAVRE/EKwIDAQABo4GZMIGWMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGEpG9oZGcfLMGNBkY7SgHiMGgTcMEgGA1UdIwRBMD+AFKOetkhnQhI2Qb1t4Lm0oFKLl/GzoRykGjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBggkA0myxg7KDeeEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQC9WZuYgQedSuOc5TOUSrRigMw4/+wuC5EtZBfvdl4HT/8vzMW/oUlIP4YCvA0XKyBaCJ2iX+ZCDKoPfiYXiaSiH+HxAPV6J79vvouxKrWg2XV6ShFtPLP+0gPdGq3x9R3+kJbmAm8w+FOdlWqAfJrLvpzMGNeDU14YGXiZ9bVzmIQbwrBA+c/F4tlK/DV07dsNExihqFoibnqDiVNTGombaU2dDup2gwKdL81ua8EIcGNExHe82kjF4zwfadHk3bQVvbfdAwxcDy4xBjs3L4raPLU3yenSzr/OEur1+jfOxnQSmEcMXKXgrAQ9U55gwjcOFKrgOxEdek/Sk1VfOjvS+nuM4eyEruFMfaZHzoQiuw4IqgGc45ohFH0UUyjYcuFxxDSU9lMCv8qdHKm+wnPRb0l9l5vXsCBDuhAGYD6ss+Ga+aDY6f/qXZuUCEUOH3QUNbbCUlviSz6+GiRnt1kA9N2Qachl+2yBfaqUqr8h7Z2gsx5LcIf5kYNsqJ0GavXTVyWh7PYiKX4bs354ZQLUwwa/cG++2+wNWP+HtBhVxMRNTdVhSm38AknZlD+PTAsWGu9GyLmhti2EnVwGybSD2Dxmhxk3IPCkhKAK+pl0eWYGZWG3tJ9mZ7SowcXLWDFAk0lRJnKGFMTggrWjV8GYpw5bq23VmIqqDLgkNzuoog==
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>keras回调函数Callbacks</title><link>/2016/07/16/keras%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0callbacks/</link><pubDate>Sat, 16 Jul 2016 00:00:00 +0000</pubDate><guid>/2016/07/16/keras%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0callbacks/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="回调函数使用"&gt;回调函数使用&lt;/h2&gt;
&lt;p&gt;回调函数是一个函数的合集，会在训练的阶段中所使用。你可以使用回调函数来查看训练模型的内在状态和统计。你可以传递一个列表的回调函数（作为 &lt;code&gt;callbacks&lt;/code&gt; 关键字参数）到 &lt;code&gt;Sequential&lt;/code&gt;或 &lt;code&gt;Model&lt;/code&gt; 类型的 &lt;code&gt;.fit()&lt;/code&gt; 方法。在训练时，相应的回调函数的方法就会在各自的阶段被调用。&lt;/p&gt;
&lt;h3 id="callback"&gt;Callback&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;keras.callbacks.Callback()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;用来组建新的回调函数的抽象基类。&lt;/p&gt;
&lt;h3 id="baselogger"&gt;BaseLogger&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;keras.callbacks.BaseLogger()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;会积累训练轮平均评估的回调函数。&lt;/p&gt;
&lt;p&gt;这个回调函数被自动应用到每一个 Keras 模型上面。&lt;/p&gt;
&lt;h3 id="terminateonnan"&gt;TerminateOnNaN&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;keras.callbacks.TerminateOnNaN()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当遇到 NaN 损失会停止训练的回调函数。&lt;/p&gt;
&lt;h3 id="progbarlogger"&gt;ProgbarLogger&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;keras.callbacks.ProgbarLogger(count_mode=&amp;#39;samples&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;会把评估以标准输出打印的回调函数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;count_mode&lt;/strong&gt;: &amp;ldquo;steps&amp;rdquo; 或者 &amp;ldquo;samples&amp;rdquo;。 进度条是否应该计数看见的样本或步骤（批量）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;触发&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ValueError&lt;/strong&gt;: 防止不正确的 &lt;code&gt;count_mode&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="history"&gt;History&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;keras.callbacks.History()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;把所有事件都记录到 &lt;code&gt;History&lt;/code&gt; 对象的回调函数。&lt;/p&gt;
&lt;p&gt;这个回调函数被自动启用到每一个 Keras 模型。&lt;code&gt;History&lt;/code&gt; 对象会被模型的 &lt;code&gt;fit&lt;/code&gt; 方法返回。&lt;/p&gt;
&lt;h3 id="modelcheckpoint"&gt;ModelCheckpoint&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;keras.callbacks.ModelCheckpoint(filepath, monitor=&amp;#39;val_loss&amp;#39;, verbose=0, save_best_only=False, save_weights_only=False, mode=&amp;#39;auto&amp;#39;, period=1)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在每个训练期之后保存模型。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;filepath&lt;/code&gt; 可以包括命名格式选项，可以由 &lt;code&gt;epoch&lt;/code&gt; 的值和 &lt;code&gt;logs&lt;/code&gt; 的键（由 &lt;code&gt;on_epoch_end&lt;/code&gt; 参数传递）来填充。&lt;/p&gt;
&lt;p&gt;例如：如果 &lt;code&gt;filepath&lt;/code&gt; 是 &lt;code&gt;weights.{epoch:02d}-{val_loss:.2f}.hdf5&lt;/code&gt;， 那么模型被保存的的文件名就会有训练轮数和验证损失。&lt;/p&gt;
&lt;h3 id="earlystopping"&gt;EarlyStopping&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;keras.callbacks.EarlyStopping(monitor=&amp;#39;val_loss&amp;#39;, min_delta=0, patience=0, verbose=0, mode=&amp;#39;auto&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当被监测的数量不再提升，则停止训练。&lt;/p&gt;</description></item><item><title>Python异步async await</title><link>/2016/07/01/python%E5%BC%82%E6%AD%A5async-await/</link><pubDate>Fri, 01 Jul 2016 00:00:00 +0000</pubDate><guid>/2016/07/01/python%E5%BC%82%E6%AD%A5async-await/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;用&lt;code&gt;asyncio&lt;/code&gt;提供的&lt;code&gt;@asyncio.coroutine&lt;/code&gt;可以把一个generator标记为coroutine类型，然后在coroutine内部用&lt;code&gt;yield from&lt;/code&gt;调用另一个coroutine实现异步操作。&lt;/p&gt;
&lt;p&gt;为了简化并更好地标识异步IO，从Python 3.5开始引入了新的语法&lt;code&gt;async&lt;/code&gt;和&lt;code&gt;await&lt;/code&gt;，可以让coroutine的代码更简洁易读。&lt;/p&gt;
&lt;p&gt;请注意，&lt;code&gt;async&lt;/code&gt;和&lt;code&gt;await&lt;/code&gt;是针对coroutine的新语法，要使用新的语法，只需要做两步简单的替换：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把&lt;code&gt;@asyncio.coroutine&lt;/code&gt;替换为&lt;code&gt;async&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;把&lt;code&gt;yield from&lt;/code&gt;替换为&lt;code&gt;await&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;让我们对比一下上一节的代码：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;@asyncio.coroutine
def hello():
print(&amp;#34;Hello world!&amp;#34;)
r = yield from asyncio.sleep(1)
print(&amp;#34;Hello again!&amp;#34;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;用新语法重新编写如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;async def hello():
print(&amp;#34;Hello world!&amp;#34;)
r = await asyncio.sleep(1)
print(&amp;#34;Hello again!&amp;#34;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;剩下的代码保持不变。&lt;/p&gt;
&lt;h3 id="小结"&gt;小结&lt;/h3&gt;
&lt;p&gt;Python从3.5版本开始为&lt;code&gt;asyncio&lt;/code&gt;提供了&lt;code&gt;async&lt;/code&gt;和&lt;code&gt;await&lt;/code&gt;的新语法；&lt;/p&gt;
&lt;p&gt;注意新语法只能用在Python 3.5以及后续版本，如果使用3.4版本，则仍需使用上一节的方案。&lt;/p&gt;
&lt;h3 id="try-it-"&gt;try it ?&lt;/h3&gt;
&lt;p&gt;使用async异步获取sina、sohu和163的网站首页。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import asyncio
async def wget(host):
print(&amp;#39;wget %s...&amp;#39; % host)
connect = asyncio.open_connection(host, 80)
[reader, writer] = await connect
header = &amp;#39;GET / HTTP/1.0\r\nHost: %s\r\n\r\n&amp;#39; % host
writer.write(header.encode(&amp;#39;utf-8&amp;#39;))
await writer.drain()
while True:
line = await reader.readline()
if line == b&amp;#39;\r\n&amp;#39;:
break
print(&amp;#39;%s header &amp;gt; %s&amp;#39; % (host, line.decode(&amp;#39;utf-8&amp;#39;).rstrip()))
# Ignore the body, close the socket
writer.close()
if __name__ == &amp;#39;__main__&amp;#39;:
loop = asyncio.get_event_loop()
tasks = [wget(host) for host in [&amp;#39;www.sina.com.cn&amp;#39;, &amp;#39;www.sohu.com&amp;#39;, &amp;#39;www.163.com&amp;#39;]]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Python异步asyncio</title><link>/2016/07/01/python%E5%BC%82%E6%AD%A5asyncio/</link><pubDate>Fri, 01 Jul 2016 00:00:00 +0000</pubDate><guid>/2016/07/01/python%E5%BC%82%E6%AD%A5asyncio/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt;是Python 3.4版本引入的标准库，直接内置了对异步IO的支持。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt;的编程模型就是一个消息循环。我们从&lt;code&gt;asyncio&lt;/code&gt;模块中直接获取一个&lt;code&gt;EventLoop&lt;/code&gt;的引用，然后把需要执行的协程扔到&lt;code&gt;EventLoop&lt;/code&gt;中执行，就实现了异步IO。&lt;/p&gt;
&lt;p&gt;用&lt;code&gt;asyncio&lt;/code&gt;实现&lt;code&gt;Hello world&lt;/code&gt;代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; asyncio
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@asyncio.coroutine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello world!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 异步调用asyncio.sleep(1):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;yield from&lt;/span&gt; asyncio&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sleep(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello again!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 获取EventLoop:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; asyncio&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get_event_loop()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 执行coroutine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loop&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run_until_complete(hello())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loop&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;@asyncio.coroutine&lt;/code&gt;把一个generator标记为coroutine类型，然后，我们就把这个&lt;code&gt;coroutine&lt;/code&gt;扔到&lt;code&gt;EventLoop&lt;/code&gt;中执行。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hello()&lt;/code&gt;会首先打印出&lt;code&gt;Hello world!&lt;/code&gt;，然后，&lt;code&gt;yield from&lt;/code&gt;语法可以让我们方便地调用另一个&lt;code&gt;generator&lt;/code&gt;。由于&lt;code&gt;asyncio.sleep()&lt;/code&gt;也是一个&lt;code&gt;coroutine&lt;/code&gt;，所以线程不会等待&lt;code&gt;asyncio.sleep()&lt;/code&gt;，而是直接中断并执行下一个消息循环。当&lt;code&gt;asyncio.sleep()&lt;/code&gt;返回时，线程就可以从&lt;code&gt;yield from&lt;/code&gt;拿到返回值（此处是&lt;code&gt;None&lt;/code&gt;），然后接着执行下一行语句。&lt;/p&gt;
&lt;p&gt;把&lt;code&gt;asyncio.sleep(1)&lt;/code&gt;看成是一个耗时1秒的IO操作，在此期间，主线程并未等待，而是去执行&lt;code&gt;EventLoop&lt;/code&gt;中其他可以执行的&lt;code&gt;coroutine&lt;/code&gt;了，因此可以实现并发执行。&lt;/p&gt;
&lt;p&gt;我们用Task封装两个&lt;code&gt;coroutine&lt;/code&gt;试试：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; threading
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; asyncio
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@asyncio.coroutine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;Hello world! (&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;)&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; threading&lt;span style="color:#f92672"&gt;.&lt;/span&gt;currentThread())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield from&lt;/span&gt; asyncio&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sleep(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;Hello again! (&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;)&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; threading&lt;span style="color:#f92672"&gt;.&lt;/span&gt;currentThread())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; asyncio&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get_event_loop()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tasks &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [hello(), hello()]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loop&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run_until_complete(asyncio&lt;span style="color:#f92672"&gt;.&lt;/span&gt;wait(tasks))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loop&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;观察执行过程：&lt;/p&gt;</description></item><item><title>Python协程</title><link>/2016/06/30/python%E5%8D%8F%E7%A8%8B/</link><pubDate>Thu, 30 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/30/python%E5%8D%8F%E7%A8%8B/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;协程，又称微线程。英文名Coroutine。&lt;/p&gt;
&lt;p&gt;协程的概念很早就提出来了，但直到最近几年才在某些语言（如Lua）中得到广泛应用。&lt;/p&gt;
&lt;p&gt;子程序，或者称为函数，在所有语言中都是层级调用，比如A调用B，B在执行过程中又调用了C，C执行完毕返回，B执行完毕返回，最后是A执行完毕。&lt;/p&gt;
&lt;p&gt;所以子程序调用是通过栈实现的，一个线程就是执行一个子程序。&lt;/p&gt;
&lt;p&gt;子程序调用总是一个入口，一次返回，调用顺序是明确的。而协程的调用和子程序不同。&lt;/p&gt;
&lt;p&gt;协程看上去也是子程序，但执行过程中，在子程序内部可中断，然后转而执行别的子程序，在适当的时候再返回来接着执行。&lt;/p&gt;
&lt;p&gt;注意，在一个子程序中中断，去执行其他子程序，不是函数调用，有点类似CPU的中断。比如子程序A、B：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def A():
print(&amp;#39;1&amp;#39;)
print(&amp;#39;2&amp;#39;)
print(&amp;#39;3&amp;#39;)
def B():
print(&amp;#39;x&amp;#39;)
print(&amp;#39;y&amp;#39;)
print(&amp;#39;z&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;假设由协程执行，在执行A的过程中，可以随时中断，去执行B，B也可能在执行过程中中断再去执行A，结果可能是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1
2
x
y
3
z
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是在A中是没有调用B的，所以协程的调用比函数调用理解起来要难一些。&lt;/p&gt;
&lt;p&gt;看起来A、B的执行有点像多线程，但协程的特点在于是一个线程执行，那和多线程比，协程有何优势？&lt;/p&gt;
&lt;p&gt;最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换，而是由程序自身控制，因此，没有线程切换的开销，和多线程比，线程数量越多，协程的性能优势就越明显。&lt;/p&gt;
&lt;p&gt;第二大优势就是不需要多线程的锁机制，因为只有一个线程，也不存在同时写变量冲突，在协程中控制共享资源不加锁，只需要判断状态就好了，所以执行效率比多线程高很多。&lt;/p&gt;
&lt;p&gt;因为协程是一个线程执行，那怎么利用多核CPU呢？最简单的方法是多进程+协程，既充分利用多核，又充分发挥协程的高效率，可获得极高的性能。&lt;/p&gt;
&lt;p&gt;Python对协程的支持是通过generator实现的。&lt;/p&gt;
&lt;p&gt;在generator中，我们不但可以通过&lt;code&gt;for&lt;/code&gt;循环来迭代，还可以不断调用&lt;code&gt;next()&lt;/code&gt;函数获取由&lt;code&gt;yield&lt;/code&gt;语句返回的下一个值。&lt;/p&gt;
&lt;p&gt;但是Python的&lt;code&gt;yield&lt;/code&gt;不但可以返回一个值，它还可以接收调用者发出的参数。&lt;/p&gt;
&lt;p&gt;来看例子：&lt;/p&gt;
&lt;p&gt;传统的生产者-消费者模型是一个线程写消息，一个线程取消息，通过锁机制控制队列和等待，但一不小心就可能死锁。&lt;/p&gt;
&lt;p&gt;如果改用协程，生产者生产消息后，直接通过&lt;code&gt;yield&lt;/code&gt;跳转到消费者开始执行，待消费者执行完毕后，切换回生产者继续生产，效率极高：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;consumer&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; r
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; n:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;[CONSUMER] Consuming &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;...&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; n)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;200 OK&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;produce&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;send(&lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; n &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; n &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;[PRODUCER] Producing &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;...&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; n)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;send(n)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;[PRODUCER] Consumer return: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; r)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c &lt;span style="color:#f92672"&gt;=&lt;/span&gt; consumer()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;produce(c)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行结果：&lt;/p&gt;</description></item><item><title>Python异步IO</title><link>/2016/06/29/python%E5%BC%82%E6%AD%A5io/</link><pubDate>Wed, 29 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/29/python%E5%BC%82%E6%AD%A5io/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;在IO编程一节中，我们已经知道，CPU的速度远远快于磁盘、网络等IO。在一个线程中，CPU执行代码的速度极快，然而，一旦遇到IO操作，如读写文件、发送网络数据时，就需要等待IO操作完成，才能继续进行下一步操作。这种情况称为同步IO。&lt;/p&gt;
&lt;p&gt;在IO操作的过程中，当前线程被挂起，而其他需要CPU执行的代码就无法被当前线程执行了。&lt;/p&gt;
&lt;p&gt;因为一个IO操作就阻塞了当前线程，导致其他代码无法执行，所以我们必须使用多线程或者多进程来并发执行代码，为多个用户服务。每个用户都会分配一个线程，如果遇到IO导致线程被挂起，其他用户的线程不受影响。&lt;/p&gt;
&lt;p&gt;多线程和多进程的模型虽然解决了并发问题，但是系统不能无上限地增加线程。由于系统切换线程的开销也很大，所以，一旦线程数量过多，CPU的时间就花在线程切换上了，真正运行代码的时间就少了，结果导致性能严重下降。&lt;/p&gt;
&lt;p&gt;由于我们要解决的问题是CPU高速执行能力和IO设备的龟速严重不匹配，多线程和多进程只是解决这一问题的一种方法。&lt;/p&gt;
&lt;p&gt;另一种解决IO问题的方法是异步IO。当代码需要执行一个耗时的IO操作时，它只发出IO指令，并不等待IO结果，然后就去执行其他代码了。一段时间后，当IO返回结果时，再通知CPU进行处理。&lt;/p&gt;
&lt;p&gt;可以想象如果按普通顺序写出的代码实际上是没法完成异步IO的,所以，同步IO模型的代码是无法实现异步IO模型的。&lt;/p&gt;
&lt;p&gt;异步IO模型需要一个消息循环，在消息循环中，主线程不断地重复“读取消息-处理消息”这一过程：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;loop = get_event_loop()
while True:
event = loop.get_event()
process_event(event)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;消息模型其实早在应用在桌面应用程序中了。一个GUI程序的主线程就负责不停地读取消息并处理消息。所有的键盘、鼠标等消息都被发送到GUI程序的消息队列中，然后由GUI程序的主线程处理。&lt;/p&gt;
&lt;p&gt;由于GUI线程处理键盘、鼠标等消息的速度非常快，所以用户感觉不到延迟。某些时候，GUI线程在一个消息处理的过程中遇到问题导致一次消息处理时间过长，此时，用户会感觉到整个GUI程序停止响应了，敲键盘、点鼠标都没有反应。这种情况说明在消息模型中，处理一个消息必须非常迅速，否则，主线程将无法及时处理消息队列中的其他消息，导致程序看上去停止响应。&lt;/p&gt;
&lt;p&gt;消息模型是如何解决同步IO必须等待IO操作这一问题的呢？当遇到IO操作时，代码只负责发出IO请求，不等待IO结果，然后直接结束本轮消息处理，进入下一轮消息处理过程。当IO操作完成后，将收到一条“IO完成”的消息，处理该消息时就可以直接获取IO操作结果。&lt;/p&gt;
&lt;p&gt;在“发出IO请求”到收到“IO完成”的这段时间里，同步IO模型下，主线程只能挂起，但异步IO模型下，主线程并没有休息，而是在消息循环中继续处理其他消息。这样，在异步IO模型下，一个线程就可以同时处理多个IO请求，并且没有切换线程的操作。对于大多数IO密集型的应用程序，使用异步IO将大大提升系统的多任务处理能力。&lt;/p&gt;</description></item><item><title>Python网络编程TCP</title><link>/2016/06/28/python%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8Btcp/</link><pubDate>Tue, 28 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/28/python%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8Btcp/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”，而打开一个Socket需要知道目标计算机的IP地址和端口号，再指定协议类型即可。&lt;/p&gt;
&lt;h3 id="客户端"&gt;客户端&lt;/h3&gt;
&lt;p&gt;大多数连接都是可靠的TCP连接。创建TCP连接时，主动发起连接的叫客户端，被动响应连接的叫服务器。&lt;/p&gt;
&lt;p&gt;举个例子，当我们在浏览器中访问新浪时，我们自己的计算机就是客户端，浏览器会主动向新浪的服务器发起连接。如果一切顺利，新浪的服务器接受了我们的连接，一个TCP连接就建立起来的，后面的通信就是发送网页内容了。&lt;/p&gt;
&lt;p&gt;所以，我们要创建一个基于TCP连接的Socket，可以这样做：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 导入socket库:
import socket
# 创建一个socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接:
s.connect((&amp;#39;www.sina.com.cn&amp;#39;, 80))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建&lt;code&gt;Socket&lt;/code&gt;时，&lt;code&gt;AF_INET&lt;/code&gt;指定使用IPv4协议，如果要用更先进的IPv6，就指定为&lt;code&gt;AF_INET6&lt;/code&gt;。&lt;code&gt;SOCK_STREAM&lt;/code&gt;指定使用面向流的TCP协议，这样，一个&lt;code&gt;Socket&lt;/code&gt;对象就创建成功，但是还没有建立连接。&lt;/p&gt;
&lt;p&gt;客户端要主动发起TCP连接，必须知道服务器的IP地址和端口号。新浪网站的IP地址可以用域名&lt;code&gt;www.sina.com.cn&lt;/code&gt;自动转换到IP地址，但是怎么知道新浪服务器的端口号呢？&lt;/p&gt;
&lt;p&gt;答案是作为服务器，提供什么样的服务，端口号就必须固定下来。由于我们想要访问网页，因此新浪提供网页服务的服务器必须把端口号固定在&lt;code&gt;80&lt;/code&gt;端口，因为&lt;code&gt;80&lt;/code&gt;端口是Web服务的标准端口。其他服务都有对应的标准端口号，例如SMTP服务是&lt;code&gt;25&lt;/code&gt;端口，FTP服务是&lt;code&gt;21&lt;/code&gt;端口，等等。端口号小于1024的是Internet标准服务的端口，端口号大于1024的，可以任意使用。&lt;/p&gt;
&lt;p&gt;因此，我们连接新浪服务器的代码如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;s.connect((&amp;#39;www.sina.com.cn&amp;#39;, 80))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意参数是一个&lt;code&gt;tuple&lt;/code&gt;，包含地址和端口号。&lt;/p&gt;
&lt;p&gt;建立TCP连接后，我们就可以向新浪服务器发送请求，要求返回首页的内容：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 发送数据:
s.send(b&amp;#39;GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;TCP连接创建的是双向通道，双方都可以同时给对方发数据。但是谁先发谁后发，怎么协调，要根据具体的协议来决定。例如，HTTP协议规定客户端必须先发请求给服务器，服务器收到后才发数据给客户端。&lt;/p&gt;
&lt;p&gt;发送的文本格式必须符合HTTP标准，如果格式没问题，接下来就可以接收新浪服务器返回的数据了：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 接收数据:
buffer = []
while True:
# 每次最多接收1k字节:
d = s.recv(1024)
if d:
buffer.append(d)
else:
break
data = b&amp;#39;&amp;#39;.join(buffer)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;接收数据时，调用&lt;code&gt;recv(max)&lt;/code&gt;方法，一次最多接收指定的字节数，因此，在一个while循环中反复接收，直到&lt;code&gt;recv()&lt;/code&gt;返回空数据，表示接收完毕，退出循环。&lt;/p&gt;
&lt;p&gt;当我们接收完数据后，调用&lt;code&gt;close()&lt;/code&gt;方法关闭Socket，这样，一次完整的网络通信就结束了：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 关闭连接:
s.close()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;接收到的数据包括HTTP头和网页本身，我们只需要把HTTP头和网页分离一下，把HTTP头打印出来，网页内容保存到文件：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;header, html = data.split(b&amp;#39;\r\n\r\n&amp;#39;, 1)
print(header.decode(&amp;#39;utf-8&amp;#39;))
# 把接收的数据写入文件:
with open(&amp;#39;sina.html&amp;#39;, &amp;#39;wb&amp;#39;) as f:
f.write(html)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在，只需要在浏览器中打开这个&lt;code&gt;sina.html&lt;/code&gt;文件，就可以看到新浪的首页了。&lt;/p&gt;</description></item><item><title>Python网络编程UDP</title><link>/2016/06/28/python%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8Budp/</link><pubDate>Tue, 28 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/28/python%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8Budp/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;TCP是建立可靠连接，并且通信双方都可以以流的形式发送数据。相对TCP，UDP则是面向无连接的协议。&lt;/p&gt;
&lt;p&gt;使用UDP协议时，不需要建立连接，只需要知道对方的IP地址和端口号，就可以直接发数据包。但是，能不能到达就不知道了。&lt;/p&gt;
&lt;p&gt;虽然用UDP传输数据不可靠，但它的优点是和TCP比，速度快，对于不要求可靠到达的数据，就可以使用UDP协议。&lt;/p&gt;
&lt;p&gt;我们来看看如何通过UDP协议传输数据。和TCP类似，使用UDP的通信双方也分为客户端和服务器。服务器首先需要绑定端口：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口:
s.bind((&amp;#39;127.0.0.1&amp;#39;, 9999))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建Socket时，&lt;code&gt;SOCK_DGRAM&lt;/code&gt;指定了这个Socket的类型是UDP。绑定端口和TCP一样，但是不需要调用&lt;code&gt;listen()&lt;/code&gt;方法，而是直接接收来自任何客户端的数据：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;print(&amp;#39;Bind UDP on 9999...&amp;#39;)
while True:
# 接收数据:
data, addr = s.recvfrom(1024)
print(&amp;#39;Received from %s:%s.&amp;#39; % (addr, data))
s.sendto(b&amp;#39;Hello, %s!&amp;#39; % data, addr)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;recvfrom()&lt;/code&gt;方法返回数据和客户端的地址与端口，这样，服务器收到数据后，直接调用&lt;code&gt;sendto()&lt;/code&gt;就可以把数据用UDP发给客户端。&lt;/p&gt;
&lt;p&gt;注意这里省掉了多线程，因为这个例子很简单。&lt;/p&gt;
&lt;p&gt;客户端使用UDP时，首先仍然创建基于UDP的Socket，然后，不需要调用&lt;code&gt;connect()&lt;/code&gt;，直接通过&lt;code&gt;sendto()&lt;/code&gt;给服务器发数据：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b&amp;#39;Superman&amp;#39;, b&amp;#39;Hooby&amp;#39;, b&amp;#39;Huyu&amp;#39;]:
# 发送数据:
s.sendto(data, (&amp;#39;127.0.0.1&amp;#39;, 9999))
# 接收数据:
print(s.recv(1024).decode(&amp;#39;utf-8&amp;#39;))
s.close()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从服务器接收数据仍然调用&lt;code&gt;recv()&lt;/code&gt;方法。&lt;/p&gt;
&lt;p&gt;仍然用两个命令行分别启动服务器和客户端测试，结果如下：&lt;/p&gt;
&lt;p&gt;server:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Bind UDP on 9999...
Received from (&amp;#39;127.0.0.1&amp;#39;, 58531):b&amp;#39;Superman&amp;#39;.
Received from (&amp;#39;127.0.0.1&amp;#39;, 58531):b&amp;#39;Hooby&amp;#39;.
Received from (&amp;#39;127.0.0.1&amp;#39;, 58531):b&amp;#39;Huyu&amp;#39;.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;client:&lt;/p&gt;</description></item><item><title>Python环境之virtualenv</title><link>/2016/06/27/python%E7%8E%AF%E5%A2%83%E4%B9%8Bvirtualenv/</link><pubDate>Mon, 27 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/27/python%E7%8E%AF%E5%A2%83%E4%B9%8Bvirtualenv/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;在开发Python应用程序的时候，系统安装的Python3只有一个版本：3.4。所有第三方的包都会被&lt;code&gt;pip&lt;/code&gt;安装到Python3的&lt;code&gt;site-packages&lt;/code&gt;目录下。&lt;/p&gt;
&lt;p&gt;如果我们要同时开发多个应用程序，那这些应用程序都会共用一个Python，就是安装在系统的Python 3。如果应用A需要jinja 2.7，而应用B需要jinja 2.6怎么办？&lt;/p&gt;
&lt;p&gt;这种情况下，每个应用可能需要各自拥有一套“独立”的Python运行环境。virtualenv就是用来为一个应用创建一套“隔离”的Python运行环境。&lt;/p&gt;
&lt;p&gt;首先，我们用&lt;code&gt;pip&lt;/code&gt;安装virtualenv：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pip3 install virtualenv
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后，假定我们要开发一个新的项目，需要一套独立的Python运行环境，可以这么做：&lt;/p&gt;
&lt;p&gt;第一步，创建目录：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Mac:~ michael$ mkdir myproject
Mac:~ michael$ cd myproject/
Mac:myproject michael$
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;第二步，创建一个独立的Python运行环境，命名为&lt;code&gt;venv&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Mac:myproject michael$ virtualenv --no-site-packages venv
Using base prefix &amp;#39;/usr/local/.../Python.framework/Versions/3.4&amp;#39;
New python executable in venv/bin/python3.4
Also creating executable in venv/bin/python
Installing setuptools, pip, wheel...done.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;命令&lt;code&gt;virtualenv&lt;/code&gt;就可以创建一个独立的Python运行环境，我们还加上了参数&lt;code&gt;--no-site-packages&lt;/code&gt;，这样，已经安装到系统Python环境中的所有第三方包都不会复制过来，这样，我们就得到了一个不带任何第三方包的“干净”的Python运行环境。&lt;/p&gt;
&lt;p&gt;新建的Python环境被放到当前目录下的&lt;code&gt;venv&lt;/code&gt;目录。有了&lt;code&gt;venv&lt;/code&gt;这个Python环境，可以用&lt;code&gt;source&lt;/code&gt;进入该环境：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Mac:myproject michael$ source venv/bin/activate
(venv)Mac:myproject michael$
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意到命令提示符变了，有个&lt;code&gt;(venv)&lt;/code&gt;前缀，表示当前环境是一个名为&lt;code&gt;venv&lt;/code&gt;的Python环境。&lt;/p&gt;
&lt;p&gt;下面正常安装各种第三方包，并运行&lt;code&gt;python&lt;/code&gt;命令：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;(venv)Mac:myproject michael$ pip install jinja2
...
Successfully installed jinja2-2.7.3 markupsafe-0.23
(venv)Mac:myproject michael$ python myapp.py
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在&lt;code&gt;venv&lt;/code&gt;环境下，用&lt;code&gt;pip&lt;/code&gt;安装的包都被安装到&lt;code&gt;venv&lt;/code&gt;这个环境下，系统Python环境不受任何影响。也就是说，&lt;code&gt;venv&lt;/code&gt;环境是专门针对&lt;code&gt;myproject&lt;/code&gt;这个应用创建的。&lt;/p&gt;</description></item><item><title>Python模块之psutil</title><link>/2016/06/26/python%E6%A8%A1%E5%9D%97%E4%B9%8Bpsutil/</link><pubDate>Sun, 26 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/26/python%E6%A8%A1%E5%9D%97%E4%B9%8Bpsutil/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;用Python来编写脚本简化日常的运维工作是Python的一个重要用途。在Linux下，有许多系统命令可以让我们时刻监控系统运行的状态，如&lt;code&gt;ps&lt;/code&gt;，&lt;code&gt;top&lt;/code&gt;，&lt;code&gt;free&lt;/code&gt;等等。要获取这些系统信息，Python可以通过&lt;code&gt;subprocess&lt;/code&gt;模块调用并获取结果。但这样做显得很麻烦，尤其是要写很多解析代码。&lt;/p&gt;
&lt;p&gt;在Python中获取系统信息的另一个好办法是使用&lt;code&gt;psutil&lt;/code&gt;这个第三方模块。顾名思义，psutil = process and system utilities，它不仅可以通过一两行代码实现系统监控，还可以跨平台使用，支持Linux／UNIX／OSX／Windows等，是系统管理员和运维小伙伴不可或缺的必备模块。&lt;/p&gt;
&lt;h3 id="安装psutil"&gt;安装psutil&lt;/h3&gt;
&lt;p&gt;如果安装了Anaconda，psutil就已经可用了。否则，需要在命令行下通过pip安装：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pip install psutil
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="获取cpu信息"&gt;获取CPU信息&lt;/h3&gt;
&lt;p&gt;我们先来获取CPU的信息：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import psutil
&amp;gt;&amp;gt;&amp;gt; psutil.cpu_count() # CPU逻辑数量
4
&amp;gt;&amp;gt;&amp;gt; psutil.cpu_count(logical=False) # CPU物理核心
2
# 2说明是双核超线程, 4则是4核非超线程
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;统计CPU的用户／系统／空闲时间：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; psutil.cpu_times()
scputimes(user=10963.31, nice=0.0, system=5138.67, idle=356102.45)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;再实现类似&lt;code&gt;top&lt;/code&gt;命令的CPU使用率，每秒刷新一次，累计10次：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; for x in range(10):
... psutil.cpu_percent(interval=1, percpu=True)
...
[14.0, 4.0, 4.0, 4.0]
[12.0, 3.0, 4.0, 3.0]
[8.0, 4.0, 3.0, 4.0]
[12.0, 3.0, 3.0, 3.0]
[18.8, 5.1, 5.9, 5.0]
[10.9, 5.0, 4.0, 3.0]
[12.0, 5.0, 4.0, 5.0]
[15.0, 5.0, 4.0, 4.0]
[19.0, 5.0, 5.0, 4.0]
[9.0, 3.0, 2.0, 3.0]
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="获取内存信息"&gt;获取内存信息&lt;/h3&gt;
&lt;p&gt;使用psutil获取物理内存和交换内存信息，分别使用：&lt;/p&gt;</description></item><item><title>Python模块之chardet</title><link>/2016/06/25/python%E6%A8%A1%E5%9D%97%E4%B9%8Bchardet/</link><pubDate>Sat, 25 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/25/python%E6%A8%A1%E5%9D%97%E4%B9%8Bchardet/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;字符串编码一直是令人非常头疼的问题，尤其是我们在处理一些不规范的第三方网页的时候。虽然Python提供了Unicode表示的&lt;code&gt;str&lt;/code&gt;和&lt;code&gt;bytes&lt;/code&gt;两种数据类型，并且可以通过&lt;code&gt;encode()&lt;/code&gt;和&lt;code&gt;decode()&lt;/code&gt;方法转换，但是，在不知道编码的情况下，对&lt;code&gt;bytes&lt;/code&gt;做&lt;code&gt;decode()&lt;/code&gt;不好做。&lt;/p&gt;
&lt;p&gt;对于未知编码的&lt;code&gt;bytes&lt;/code&gt;，要把它转换成&lt;code&gt;str&lt;/code&gt;，需要先“猜测”编码。猜测的方式是先收集各种编码的特征字符，根据特征字符判断，就能有很大概率“猜对”。&lt;/p&gt;
&lt;p&gt;当然，我们肯定不能从头自己写这个检测编码的功能，这样做费时费力。chardet这个第三方库正好就派上了用场。用它来检测编码，简单易用。&lt;/p&gt;
&lt;h3 id="安装chardet"&gt;安装chardet&lt;/h3&gt;
&lt;p&gt;如果安装了Anaconda，chardet就已经可用了。否则，需要在命令行下通过pip安装：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pip install chardet
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="使用chardet"&gt;使用chardet&lt;/h3&gt;
&lt;p&gt;当我们拿到一个&lt;code&gt;bytes&lt;/code&gt;时，就可以对其检测编码。用chardet检测编码，只需要一行代码：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; chardet.detect(b&amp;#39;Hello, world!&amp;#39;)
{&amp;#39;encoding&amp;#39;: &amp;#39;ascii&amp;#39;, &amp;#39;confidence&amp;#39;: 1.0, &amp;#39;language&amp;#39;: &amp;#39;&amp;#39;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;检测出的编码是&lt;code&gt;ascii&lt;/code&gt;，注意到还有个&lt;code&gt;confidence&lt;/code&gt;字段，表示检测的概率是1.0（即100%）。&lt;/p&gt;
&lt;p&gt;我们来试试检测GBK编码的中文：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; data = &amp;#39;离离原上草，一岁一枯荣&amp;#39;.encode(&amp;#39;gbk&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; chardet.detect(data)
{&amp;#39;encoding&amp;#39;: &amp;#39;GB2312&amp;#39;, &amp;#39;confidence&amp;#39;: 0.7407407407407407, &amp;#39;language&amp;#39;: &amp;#39;Chinese&amp;#39;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;检测的编码是&lt;code&gt;GB2312&lt;/code&gt;，注意到GBK是GB2312的超集，两者是同一种编码，检测正确的概率是74%，&lt;code&gt;language&lt;/code&gt;字段指出的语言是&lt;code&gt;'Chinese'&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;对UTF-8编码进行检测：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; data = &amp;#39;离离原上草，一岁一枯荣&amp;#39;.encode(&amp;#39;utf-8&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; chardet.detect(data)
{&amp;#39;encoding&amp;#39;: &amp;#39;utf-8&amp;#39;, &amp;#39;confidence&amp;#39;: 0.99, &amp;#39;language&amp;#39;: &amp;#39;&amp;#39;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们再试试对日文进行检测：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; data = &amp;#39;最新の主要ニュース&amp;#39;.encode(&amp;#39;euc-jp&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; chardet.detect(data)
{&amp;#39;encoding&amp;#39;: &amp;#39;EUC-JP&amp;#39;, &amp;#39;confidence&amp;#39;: 0.99, &amp;#39;language&amp;#39;: &amp;#39;Japanese&amp;#39;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可见，用chardet检测编码，使用简单。获取到编码后，再转换为&lt;code&gt;str&lt;/code&gt;，就可以方便后续处理。&lt;/p&gt;
&lt;p&gt;chardet支持检测的编码列表请参考官方文档&lt;a href="https://chardet.readthedocs.io/en/latest/supported-encodings.html"&gt;Supported encodings&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="小结"&gt;小结&lt;/h3&gt;
&lt;p&gt;使用chardet检测编码非常容易，chardet支持检测中文、日文、韩文等多种语言。&lt;/p&gt;</description></item><item><title>Python模块之requests</title><link>/2016/06/24/python%E6%A8%A1%E5%9D%97%E4%B9%8Brequests/</link><pubDate>Fri, 24 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/24/python%E6%A8%A1%E5%9D%97%E4%B9%8Brequests/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;Python内置的模块有urllib，用于访问网络资源。但是，它用起来比较麻烦，而且，缺少很多实用的高级功能。&lt;/p&gt;
&lt;p&gt;更好的方案是使用requests。它是一个Python第三方库，处理URL资源特别方便。&lt;/p&gt;
&lt;h3 id="安装requests"&gt;安装requests&lt;/h3&gt;
&lt;p&gt;如果安装了Anaconda，requests就已经可用了。否则，需要在命令行下通过pip安装：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pip install requests
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="使用requests"&gt;使用requests&lt;/h3&gt;
&lt;p&gt;要通过GET访问一个页面，只需要几行代码：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import requests
&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;https://www.douban.com/&amp;#39;) # 豆瓣首页
&amp;gt;&amp;gt;&amp;gt; r.status_code
200
&amp;gt;&amp;gt;&amp;gt; r.text
r.text
&amp;#39;&amp;lt;!DOCTYPE HTML&amp;gt;\n&amp;lt;html&amp;gt;\n&amp;lt;head&amp;gt;\n&amp;lt;meta name=&amp;#34;description&amp;#34; content=&amp;#34;提供图书、电影、音乐唱片的推荐、评论和...&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对于带参数的URL，传入一个dict作为&lt;code&gt;params&lt;/code&gt;参数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;https://www.douban.com/search&amp;#39;, params={&amp;#39;q&amp;#39;: &amp;#39;python&amp;#39;, &amp;#39;cat&amp;#39;: &amp;#39;1001&amp;#39;})
&amp;gt;&amp;gt;&amp;gt; r.url # 实际请求的URL
&amp;#39;https://www.douban.com/search?q=python&amp;amp;cat=1001&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;requests自动检测编码，可以使用&lt;code&gt;encoding&lt;/code&gt;属性查看：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; r.encoding
&amp;#39;utf-8&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;无论响应是文本还是二进制内容，我们都可以用&lt;code&gt;content&lt;/code&gt;属性获得&lt;code&gt;bytes&lt;/code&gt;对象：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; r.content
b&amp;#39;&amp;lt;!DOCTYPE html&amp;gt;\n&amp;lt;html&amp;gt;\n&amp;lt;head&amp;gt;\n&amp;lt;meta http-equiv=&amp;#34;Content-Type&amp;#34; content=&amp;#34;text/html; charset=utf-8&amp;#34;&amp;gt;\n...&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;requests的方便之处还在于，对于特定类型的响应，例如JSON，可以直接获取：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%202151330&amp;amp;format=json&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; r.json()
{&amp;#39;query&amp;#39;: {&amp;#39;count&amp;#39;: 1, &amp;#39;created&amp;#39;: &amp;#39;2017-11-17T07:14:12Z&amp;#39;, ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;需要传入HTTP Header时，我们传入一个dict作为&lt;code&gt;headers&lt;/code&gt;参数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;https://www.douban.com/&amp;#39;, headers={&amp;#39;User-Agent&amp;#39;: &amp;#39;Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit&amp;#39;})
&amp;gt;&amp;gt;&amp;gt; r.text
&amp;#39;&amp;lt;!DOCTYPE html&amp;gt;\n&amp;lt;html&amp;gt;\n&amp;lt;head&amp;gt;\n&amp;lt;meta charset=&amp;#34;UTF-8&amp;#34;&amp;gt;\n &amp;lt;title&amp;gt;豆瓣(手机版)&amp;lt;/title&amp;gt;...&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;要发送POST请求，只需要把&lt;code&gt;get()&lt;/code&gt;方法变成&lt;code&gt;post()&lt;/code&gt;，然后传入&lt;code&gt;data&lt;/code&gt;参数作为POST请求的数据：&lt;/p&gt;</description></item><item><title>Python模块之pillow</title><link>/2016/06/23/python%E6%A8%A1%E5%9D%97%E4%B9%8Bpillow/</link><pubDate>Thu, 23 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/23/python%E6%A8%A1%E5%9D%97%E4%B9%8Bpillow/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;除了内建的模块外，Python还有大量的第三方模块,而且是相当相当的多。&lt;/p&gt;
&lt;p&gt;基本上，所有的第三方模块都会在&lt;a href="https://pypi.python.org/"&gt;PyPI - the Python Package Index&lt;/a&gt;上注册，只要找到对应的模块名字，即可用pip安装。也可以安装&lt;a href="https://www.anaconda.com/"&gt;Anaconda&lt;/a&gt;，安装后，数十个常用的第三方模块就已经就绪，不用pip手动安装。下面讲解一下pillow这个第三方模块.&lt;/p&gt;
&lt;p&gt;PIL：Python Imaging Library，已经是Python平台事实上的图像处理标准库了。PIL功能非常强大，但API却非常简单易用。&lt;/p&gt;
&lt;p&gt;由于PIL仅支持到Python 2.7，加上年久失修，于是一群志愿者在PIL的基础上创建了兼容的版本，名字叫&lt;a href="https://github.com/python-pillow/Pillow"&gt;Pillow&lt;/a&gt;，支持最新Python 3.x，又加入了许多新特性，因此，我们可以直接安装使用Pillow。&lt;/p&gt;
&lt;h3 id="安装pillow"&gt;安装Pillow&lt;/h3&gt;
&lt;p&gt;如果安装了Anaconda，Pillow就已经可用了。否则，需要在命令行下通过pip安装：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pip install pillow
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="操作图像"&gt;操作图像&lt;/h3&gt;
&lt;p&gt;来看看最常见的图像缩放操作，只需三四行代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; PIL &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Image
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 打开一个jpg图像文件，注意是当前路径:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;im &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Image&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open(&lt;span style="color:#e6db74"&gt;&amp;#39;test.jpg&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 获得图像尺寸:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;w, h &lt;span style="color:#f92672"&gt;=&lt;/span&gt; im&lt;span style="color:#f92672"&gt;.&lt;/span&gt;size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#39;Original image size: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;x&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (w, h))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 缩放到50%:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;im&lt;span style="color:#f92672"&gt;.&lt;/span&gt;thumbnail((w&lt;span style="color:#f92672"&gt;//&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, h&lt;span style="color:#f92672"&gt;//&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#39;Resize image to: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;x&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (w&lt;span style="color:#f92672"&gt;//&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, h&lt;span style="color:#f92672"&gt;//&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 把缩放后的图像用jpeg格式保存:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;im&lt;span style="color:#f92672"&gt;.&lt;/span&gt;save(&lt;span style="color:#e6db74"&gt;&amp;#39;thumbnail.jpg&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;jpeg&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其他功能如切片、旋转、滤镜、输出文字、调色板等一应俱全。&lt;/p&gt;
&lt;p&gt;比如，模糊效果也只需几行代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; PIL &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Image, ImageFilter
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 打开一个jpg图像文件，注意是当前路径:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;im &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Image&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open(&lt;span style="color:#e6db74"&gt;&amp;#39;test.jpg&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 应用模糊滤镜:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;im2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; im&lt;span style="color:#f92672"&gt;.&lt;/span&gt;filter(ImageFilter&lt;span style="color:#f92672"&gt;.&lt;/span&gt;BLUR)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;im2&lt;span style="color:#f92672"&gt;.&lt;/span&gt;save(&lt;span style="color:#e6db74"&gt;&amp;#39;blur.jpg&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;jpeg&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果如下：&lt;/p&gt;</description></item><item><title>Python内建模块HTMLParser</title><link>/2016/06/22/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97htmlparser/</link><pubDate>Wed, 22 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/22/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97htmlparser/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;如果我们要编写一个搜索引擎，第一步是用爬虫把目标网站的页面抓下来，第二步就是解析该HTML页面，看看里面的内容到底是新闻、图片还是视频。&lt;/p&gt;
&lt;p&gt;假设第一步已经完成了，第二步应该如何解析HTML呢？&lt;/p&gt;
&lt;p&gt;HTML本质上是XML的子集，但是HTML的语法没有XML那么严格，所以不能用标准的DOM或SAX来解析HTML。&lt;/p&gt;
&lt;p&gt;好在Python提供了HTMLParser来非常方便地解析HTML，只需简单几行代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; html.parser &lt;span style="color:#f92672"&gt;import&lt;/span&gt; HTMLParser
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; html.entities &lt;span style="color:#f92672"&gt;import&lt;/span&gt; name2codepoint
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyHTMLParser&lt;/span&gt;(HTMLParser):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_starttag&lt;/span&gt;(self, tag, attrs):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; tag)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_endtag&lt;/span&gt;(self, tag):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; tag)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_startendtag&lt;/span&gt;(self, tag, attrs):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/&amp;gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; tag)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_data&lt;/span&gt;(self, data):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_comment&lt;/span&gt;(self, data):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;!--&amp;#39;&lt;/span&gt;, data, &lt;span style="color:#e6db74"&gt;&amp;#39;--&amp;gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_entityref&lt;/span&gt;(self, name):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;amp;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_charref&lt;/span&gt;(self, name):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;amp;#&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parser &lt;span style="color:#f92672"&gt;=&lt;/span&gt; MyHTMLParser()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;feed(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&amp;#39;&amp;lt;html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;!-- test html parser --&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;lt;p&amp;gt;Some &amp;lt;a href=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;gt;html&amp;lt;/a&amp;gt; HTML&amp;amp;nbsp;tutorial...&amp;lt;br&amp;gt;END&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;feed()&lt;/code&gt;方法可以多次调用，也就是不一定一次把整个HTML字符串都塞进去，可以一部分一部分塞进去。&lt;/p&gt;</description></item><item><title>Python内建模块xml</title><link>/2016/06/21/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97xml/</link><pubDate>Tue, 21 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/21/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97xml/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;XML虽然比JSON复杂，在Web中应用也不如以前多了，不过仍有很多地方在用，所以，有必要了解如何操作XML。&lt;/p&gt;
&lt;h3 id="dom-vs-sax"&gt;DOM vs SAX&lt;/h3&gt;
&lt;p&gt;操作XML有两种方法：DOM和SAX。DOM会把整个XML读入内存，解析为树，因此占用内存大，解析慢，优点是可以任意遍历树的节点。SAX是流模式，边读边解析，占用内存小，解析快，缺点是我们需要自己处理事件。&lt;/p&gt;
&lt;p&gt;正常情况下，优先考虑SAX，因为DOM实在太占内存。&lt;/p&gt;
&lt;p&gt;在Python中使用SAX解析XML非常简洁，通常我们关心的事件是&lt;code&gt;start_element&lt;/code&gt;，&lt;code&gt;end_element&lt;/code&gt;和&lt;code&gt;char_data&lt;/code&gt;，准备好这3个函数，然后就可以解析xml了。&lt;/p&gt;
&lt;p&gt;举个例子，当SAX解析器读到一个节点时：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;a href=&amp;#34;/&amp;#34;&amp;gt;python&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;会产生3个事件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;start_element事件，在读取&lt;code&gt;&amp;lt;a href=&amp;quot;/&amp;quot;&amp;gt;&lt;/code&gt;时；&lt;/li&gt;
&lt;li&gt;char_data事件，在读取&lt;code&gt;python&lt;/code&gt;时；&lt;/li&gt;
&lt;li&gt;end_element事件，在读取&lt;code&gt;&amp;lt;/a&amp;gt;&lt;/code&gt;时。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;用代码实验一下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; xml.parsers.expat &lt;span style="color:#f92672"&gt;import&lt;/span&gt; ParserCreate
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DefaultSaxHandler&lt;/span&gt;(object):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;start_element&lt;/span&gt;(self, name, attrs):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;sax:start_element: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, attrs: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (name, str(attrs)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;end_element&lt;/span&gt;(self, name):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;sax:end_element: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;char_data&lt;/span&gt;(self, text):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;sax:char_data: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xml &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&amp;#39;&amp;lt;?xml version=&amp;#34;1.0&amp;#34;?&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;ol&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;lt;li&amp;gt;&amp;lt;a href=&amp;#34;/python&amp;#34;&amp;gt;Python&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;lt;li&amp;gt;&amp;lt;a href=&amp;#34;/ruby&amp;#34;&amp;gt;Ruby&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;/ol&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;handler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; DefaultSaxHandler()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parser &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ParserCreate()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;StartElementHandler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;start_element
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;EndElementHandler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;end_element
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;CharacterDataHandler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;char_data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Parse(xml)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要注意的是读取一大段字符串时，&lt;code&gt;CharacterDataHandler&lt;/code&gt;可能被多次调用，所以需要自己保存起来，在&lt;code&gt;EndElementHandler&lt;/code&gt;里面再合并。&lt;/p&gt;</description></item><item><title>Python内建模块contextlib</title><link>/2016/06/20/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97contextlib/</link><pubDate>Mon, 20 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/20/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97contextlib/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;在Python中，读写文件这样的资源要特别注意，必须在使用完毕后正确关闭它们。正确关闭文件资源的一个方法是使用&lt;code&gt;try...finally&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;try:
f = open(&amp;#39;/path/to/file&amp;#39;, &amp;#39;r&amp;#39;)
f.read()
finally:
if f:
f.close()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;写&lt;code&gt;try...finally&lt;/code&gt;非常繁琐。Python的&lt;code&gt;with&lt;/code&gt;语句允许我们非常方便地使用资源，而不必担心资源没有关闭，所以上面的代码可以简化为：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;with open(&amp;#39;/path/to/file&amp;#39;, &amp;#39;r&amp;#39;) as f:
f.read()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;并不是只有&lt;code&gt;open()&lt;/code&gt;函数返回的fp对象才能使用&lt;code&gt;with&lt;/code&gt;语句。实际上，任何对象，只要正确实现了上下文管理，就可以用于&lt;code&gt;with&lt;/code&gt;语句。&lt;/p&gt;
&lt;p&gt;实现上下文管理是通过&lt;code&gt;__enter__&lt;/code&gt;和&lt;code&gt;__exit__&lt;/code&gt;这两个方法实现的。例如，下面的class实现了这两个方法：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Query(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print(&amp;#39;Begin&amp;#39;)
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
print(&amp;#39;Error&amp;#39;)
else:
print(&amp;#39;End&amp;#39;)
def query(self):
print(&amp;#39;Query info about %s...&amp;#39; % self.name)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这样我们就可以把自己写的资源对象用于&lt;code&gt;with&lt;/code&gt;语句：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;with Query(&amp;#39;Bob&amp;#39;) as q:
q.query()
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="contextmanager"&gt;@contextmanager&lt;/h3&gt;
&lt;p&gt;编写&lt;code&gt;__enter__&lt;/code&gt;和&lt;code&gt;__exit__&lt;/code&gt;仍然很繁琐，因此Python的标准库&lt;code&gt;contextlib&lt;/code&gt;提供了更简单的写法，上面的代码可以改写如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;from contextlib import contextmanager
class Query(object):
def __init__(self, name):
self.name = name
def query(self):
print(&amp;#39;Query info about %s...&amp;#39; % self.name)
@contextmanager
def create_query(name):
print(&amp;#39;Begin&amp;#39;)
q = Query(name)
yield q
print(&amp;#39;End&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;@contextmanager&lt;/code&gt;这个decorator接受一个generator，用&lt;code&gt;yield&lt;/code&gt;语句把&lt;code&gt;with ... as var&lt;/code&gt;把变量输出出去，然后，&lt;code&gt;with&lt;/code&gt;语句就可以正常地工作了：&lt;/p&gt;</description></item><item><title>Python内建模块urllib</title><link>/2016/06/20/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97urllib/</link><pubDate>Mon, 20 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/20/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97urllib/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;urllib提供了一系列用于操作URL的功能。&lt;/p&gt;
&lt;h3 id="get"&gt;Get&lt;/h3&gt;
&lt;p&gt;urllib的&lt;code&gt;request&lt;/code&gt;模块可以非常方便地抓取URL内容，也就是发送一个GET请求到指定的页面，然后返回HTTP的响应：&lt;/p&gt;
&lt;p&gt;例如，对豆瓣的一个URL&lt;code&gt;https://api.douban.com/v2/book/2129650&lt;/code&gt;进行抓取，并返回响应：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; urllib &lt;span style="color:#f92672"&gt;import&lt;/span&gt; request
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; request&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urlopen(&lt;span style="color:#e6db74"&gt;&amp;#39;https://api.douban.com/v2/book/2129650&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;Status:&amp;#39;&lt;/span&gt;, f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;status, f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;reason)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; k, v &lt;span style="color:#f92672"&gt;in&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getheaders():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (k, v))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;Data:&amp;#39;&lt;/span&gt;, data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;decode(&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到HTTP响应的头和JSON数据：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Status: 200 OK
Server: nginx
Date: Tue, 26 May 2015 10:02:27 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 2049
Connection: close
Expires: Sun, 1 Jan 2006 01:00:00 GMT
Pragma: no-cache
Cache-Control: must-revalidate, no-cache, private
X-DAE-Node: pidl1
Data: {&amp;#34;rating&amp;#34;:{&amp;#34;max&amp;#34;:10,&amp;#34;numRaters&amp;#34;:16,&amp;#34;average&amp;#34;:&amp;#34;7.4&amp;#34;,&amp;#34;min&amp;#34;:0},&amp;#34;subtitle&amp;#34;:&amp;#34;&amp;#34;,&amp;#34;author&amp;#34;:[&amp;#34;廖雪峰编著&amp;#34;],&amp;#34;pubdate&amp;#34;:&amp;#34;2007-6&amp;#34;,...}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果我们要想模拟浏览器发送GET请求，就需要使用&lt;code&gt;Request&lt;/code&gt;对象，通过往&lt;code&gt;Request&lt;/code&gt;对象添加HTTP头，我们就可以把请求伪装成浏览器。例如，模拟iPhone 6去请求豆瓣首页：&lt;/p&gt;</description></item><item><title>Python内建模块itertools</title><link>/2016/06/19/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97itertools/</link><pubDate>Sun, 19 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/19/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97itertools/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;Python的内建模块&lt;code&gt;itertools&lt;/code&gt;提供了非常有用的用于操作迭代对象的函数。&lt;/p&gt;
&lt;p&gt;首先，我们看看&lt;code&gt;itertools&lt;/code&gt;提供的几个“无限”迭代器：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import itertools
&amp;gt;&amp;gt;&amp;gt; natuals = itertools.count(1)
&amp;gt;&amp;gt;&amp;gt; for n in natuals:
... print(n)
...
1
2
3
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因为&lt;code&gt;count()&lt;/code&gt;会创建一个无限的迭代器，所以上述代码会打印出自然数序列，根本停不下来，只能按&lt;code&gt;Ctrl+C&lt;/code&gt;退出。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cycle()&lt;/code&gt;会把传入的一个序列无限重复下去：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import itertools
&amp;gt;&amp;gt;&amp;gt; cs = itertools.cycle(&amp;#39;ABC&amp;#39;) # 注意字符串也是序列的一种
&amp;gt;&amp;gt;&amp;gt; for c in cs:
... print(c)
...
&amp;#39;A&amp;#39;
&amp;#39;B&amp;#39;
&amp;#39;C&amp;#39;
&amp;#39;A&amp;#39;
&amp;#39;B&amp;#39;
&amp;#39;C&amp;#39;
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;同样停不下来。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;repeat()&lt;/code&gt;负责把一个元素无限重复下去，不过如果提供第二个参数就可以限定重复次数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; ns = itertools.repeat(&amp;#39;A&amp;#39;, 3)
&amp;gt;&amp;gt;&amp;gt; for n in ns:
... print(n)
...
A
A
A
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;无限序列只有在&lt;code&gt;for&lt;/code&gt;迭代时才会无限地迭代下去，如果只是创建了一个迭代对象，它不会事先把无限个元素生成出来，事实上也不可能在内存中创建无限多个元素。&lt;/p&gt;
&lt;p&gt;无限序列虽然可以无限迭代下去，但是通常我们会通过&lt;code&gt;takewhile()&lt;/code&gt;等函数根据条件判断来截取出一个有限的序列：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; natuals = itertools.count(1)
&amp;gt;&amp;gt;&amp;gt; ns = itertools.takewhile(lambda x: x &amp;lt;= 10, natuals)
&amp;gt;&amp;gt;&amp;gt; list(ns)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;itertools&lt;/code&gt;提供的几个迭代器操作函数更加有用：&lt;/p&gt;</description></item><item><title>Python内建模块hashlib</title><link>/2016/06/18/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97hashlib/</link><pubDate>Sat, 18 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/18/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97hashlib/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="摘要算法简介"&gt;摘要算法简介&lt;/h3&gt;
&lt;p&gt;Python的hashlib提供了常见的摘要算法，如MD5，SHA1等等。&lt;/p&gt;
&lt;p&gt;什么是摘要算法呢？摘要算法又称哈希算法、散列算法。它通过一个函数，把任意长度的数据转换为一个长度固定的数据串（通常用16进制的字符串表示）。&lt;/p&gt;
&lt;p&gt;举个例子，你写了一篇文章，内容是一个字符串&lt;code&gt;'how to use python hashlib - by Michael'&lt;/code&gt;，并附上这篇文章的摘要是&lt;code&gt;'2d73d4f15c0db7f5ecb321b6a65e5d6d'&lt;/code&gt;。如果有人篡改了你的文章，并发表为&lt;code&gt;'how to use python hashlib - by Bob'&lt;/code&gt;，你可以一下子指出Bob篡改了你的文章，因为根据&lt;code&gt;'how to use python hashlib - by Bob'&lt;/code&gt;计算出的摘要不同于原始文章的摘要。&lt;/p&gt;
&lt;p&gt;可见，摘要算法就是通过摘要函数&lt;code&gt;f()&lt;/code&gt;对任意长度的数据&lt;code&gt;data&lt;/code&gt;计算出固定长度的摘要&lt;code&gt;digest&lt;/code&gt;，目的是为了发现原始数据是否被人篡改过。&lt;/p&gt;
&lt;p&gt;摘要算法之所以能指出数据是否被篡改过，就是因为摘要函数是一个单向函数，计算&lt;code&gt;f(data)&lt;/code&gt;很容易，但通过&lt;code&gt;digest&lt;/code&gt;反推&lt;code&gt;data&lt;/code&gt;却非常困难。而且，对原始数据做一个bit的修改，都会导致计算出的摘要完全不同,这种现象称为雪崩效应。&lt;/p&gt;
&lt;p&gt;我们以常见的摘要算法MD5为例，计算出一个字符串的MD5值：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import hashlib
md5 = hashlib.md5()
md5.update(&amp;#39;how to use md5 in python hashlib?&amp;#39;.encode(&amp;#39;utf-8&amp;#39;))
print(md5.hexdigest())
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;计算结果如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;d26a53750bc40b38b65a520292f69306
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果数据量很大，可以分块多次调用&lt;code&gt;update()&lt;/code&gt;，最后计算的结果是一样的：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import hashlib
md5 = hashlib.md5()
md5.update(&amp;#39;how to use md5 in &amp;#39;.encode(&amp;#39;utf-8&amp;#39;))
md5.update(&amp;#39;python hashlib?&amp;#39;.encode(&amp;#39;utf-8&amp;#39;))
print(md5.hexdigest())
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;试试改动一个字母，看看计算的结果是否完全不同。&lt;/p&gt;
&lt;p&gt;MD5是最常见的摘要算法，速度很快，生成结果是固定的128 bit字节，通常用一个32位的16进制字符串表示。&lt;/p&gt;
&lt;p&gt;另一种常见的摘要算法是SHA1，调用SHA1和调用MD5完全类似：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import hashlib
sha1 = hashlib.sha1()
sha1.update(&amp;#39;how to use sha1 in &amp;#39;.encode(&amp;#39;utf-8&amp;#39;))
sha1.update(&amp;#39;python hashlib?&amp;#39;.encode(&amp;#39;utf-8&amp;#39;))
print(sha1.hexdigest())
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;SHA1的结果是160 bit字节，通常用一个40位的16进制字符串表示。&lt;/p&gt;</description></item><item><title>Python内建模块hmac</title><link>/2016/06/18/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97hmac/</link><pubDate>Sat, 18 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/18/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97hmac/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;通过哈希算法，我们可以验证一段数据是否有效，方法就是对比该数据的哈希值，例如，判断用户口令是否正确，我们用保存在数据库中的&lt;code&gt;password_md5&lt;/code&gt;对比计算&lt;code&gt;md5(password)&lt;/code&gt;的结果，如果一致，用户输入的口令就是正确的。&lt;/p&gt;
&lt;p&gt;为了防止黑客通过彩虹表根据哈希值反推原始口令，在计算哈希的时候，不能仅针对原始输入计算，需要增加一个salt来使得相同的输入也能得到不同的哈希，这样，大大增加了黑客破解的难度。&lt;/p&gt;
&lt;p&gt;如果salt是我们自己随机生成的，通常我们计算MD5时采用&lt;code&gt;md5(message + salt)&lt;/code&gt;。但实际上，把salt看做一个“口令”，加salt的哈希就是：计算一段message的哈希时，根据不通口令计算出不同的哈希。要验证哈希值，必须同时提供正确的口令。&lt;/p&gt;
&lt;p&gt;这实际上就是Hmac算法：Keyed-Hashing for Message Authentication。它通过一个标准算法，在计算哈希的过程中，把key混入计算过程中。&lt;/p&gt;
&lt;p&gt;和我们自定义的加salt算法不同，Hmac算法针对所有哈希算法都通用，无论是MD5还是SHA-1。采用Hmac替代我们自己的salt算法，可以使程序算法更标准化，也更安全。&lt;/p&gt;
&lt;p&gt;Python自带的hmac模块实现了标准的Hmac算法。我们来看看如何使用hmac实现带key的哈希。&lt;/p&gt;
&lt;p&gt;我们首先需要准备待计算的原始消息message，随机key，哈希算法，这里采用MD5，使用hmac的代码如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import hmac
&amp;gt;&amp;gt;&amp;gt; message = b&amp;#39;Hello, world!&amp;#39;
&amp;gt;&amp;gt;&amp;gt; key = b&amp;#39;secret&amp;#39;
&amp;gt;&amp;gt;&amp;gt; h = hmac.new(key, message, digestmod=&amp;#39;MD5&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; # 如果消息很长，可以多次调用h.update(msg)
&amp;gt;&amp;gt;&amp;gt; h.hexdigest()
&amp;#39;fa4ee7d173f2d97ee79022d1a7355bcf&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可见使用hmac和普通hash算法非常类似。hmac输出的长度和原始哈希算法的长度一致。需要注意传入的key和message都是&lt;code&gt;bytes&lt;/code&gt;类型，&lt;code&gt;str&lt;/code&gt;类型需要首先编码为&lt;code&gt;bytes&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="练习"&gt;练习&lt;/h3&gt;
&lt;p&gt;将上一节的salt改为标准的hmac算法，验证用户口令：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# -*- coding: utf-8 -*-
import hmac, random
def hmac_md5(key, s):
return hmac.new(key.encode(&amp;#39;utf-8&amp;#39;), s.encode(&amp;#39;utf-8&amp;#39;), &amp;#39;MD5&amp;#39;).hexdigest()
class User(object):
def __init__(self, username, password):
self.username = username
self.key = &amp;#39;&amp;#39;.join([chr(random.randint(48, 122)) for i in range(20)])
self.password = hmac_md5(self.key, password)
db = {
&amp;#39;michael&amp;#39;: User(&amp;#39;michael&amp;#39;, &amp;#39;123456&amp;#39;),
&amp;#39;bob&amp;#39;: User(&amp;#39;bob&amp;#39;, &amp;#39;abc999&amp;#39;),
&amp;#39;alice&amp;#39;: User(&amp;#39;alice&amp;#39;, &amp;#39;alice2008&amp;#39;)
}
def login(username, password):
user = db[username]
return user.password == hmac_md5(user.key, password)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;测试:&lt;/p&gt;</description></item><item><title>Python内建模块struct</title><link>/2016/06/16/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97struct/</link><pubDate>Thu, 16 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/16/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97struct/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;准确地讲，Python没有专门处理字节的数据类型。但由于&lt;code&gt;b'str'&lt;/code&gt;可以表示字节，所以，字节数组＝二进制str。而在C语言中，我们可以很方便地用struct、union来处理字节，以及字节和int，float的转换。&lt;/p&gt;
&lt;p&gt;在Python中，比方说要把一个32位无符号整数变成字节，也就是4个长度的&lt;code&gt;bytes&lt;/code&gt;，你得配合位运算符这么写：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; n = 10240099
&amp;gt;&amp;gt;&amp;gt; b1 = (n &amp;amp; 0xff000000) &amp;gt;&amp;gt; 24
&amp;gt;&amp;gt;&amp;gt; b2 = (n &amp;amp; 0xff0000) &amp;gt;&amp;gt; 16
&amp;gt;&amp;gt;&amp;gt; b3 = (n &amp;amp; 0xff00) &amp;gt;&amp;gt; 8
&amp;gt;&amp;gt;&amp;gt; b4 = n &amp;amp; 0xff
&amp;gt;&amp;gt;&amp;gt; bs = bytes([b1, b2, b3, b4])
&amp;gt;&amp;gt;&amp;gt; bs
b&amp;#39;\x00\x9c@c&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;非常麻烦。如果换成浮点数就无能为力了。&lt;/p&gt;
&lt;p&gt;好在Python提供了一个&lt;code&gt;struct&lt;/code&gt;模块来解决&lt;code&gt;bytes&lt;/code&gt;和其他二进制数据类型的转换。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;struct&lt;/code&gt;的&lt;code&gt;pack&lt;/code&gt;函数把任意数据类型变成&lt;code&gt;bytes&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import struct
&amp;gt;&amp;gt;&amp;gt; struct.pack(&amp;#39;&amp;gt;I&amp;#39;, 10240099)
b&amp;#39;\x00\x9c@c&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;pack&lt;/code&gt;的第一个参数是处理指令，&lt;code&gt;'&amp;gt;I'&lt;/code&gt;的意思是：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;表示字节顺序是big-endian，也就是网络序，&lt;code&gt;I&lt;/code&gt;表示4字节无符号整数。&lt;/p&gt;
&lt;p&gt;后面的参数个数要和处理指令一致。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;unpack&lt;/code&gt;把&lt;code&gt;bytes&lt;/code&gt;变成相应的数据类型：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; struct.unpack(&amp;#39;&amp;gt;IH&amp;#39;, b&amp;#39;\xf0\xf0\xf0\xf0\x80\x80&amp;#39;)
(4042322160, 32896)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;根据&lt;code&gt;&amp;gt;IH&lt;/code&gt;的说明，后面的&lt;code&gt;bytes&lt;/code&gt;依次变为&lt;code&gt;I&lt;/code&gt;：4字节无符号整数和&lt;code&gt;H&lt;/code&gt;：2字节无符号整数。&lt;/p&gt;
&lt;p&gt;所以，尽管Python不适合编写底层操作字节流的代码，但在对性能要求不高的地方，利用&lt;code&gt;struct&lt;/code&gt;就方便多了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;struct&lt;/code&gt;模块定义的数据类型可以参考Python官方文档：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.python.org/3/library/struct.html#format-characters"&gt;https://docs.python.org/3/library/struct.html#format-characters&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Python内建模块base64</title><link>/2016/06/15/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97base64/</link><pubDate>Wed, 15 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/15/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97base64/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;Base64是一种用64个字符来表示任意二进制数据的方法。&lt;/p&gt;
&lt;p&gt;用记事本打开&lt;code&gt;exe&lt;/code&gt;、&lt;code&gt;jpg&lt;/code&gt;、&lt;code&gt;pdf&lt;/code&gt;这些文件时，我们都会看到一大堆乱码，因为二进制文件包含很多无法显示和打印的字符，所以，如果要让记事本这样的文本处理软件能处理二进制数据，就需要一个二进制到字符串的转换方法。Base64是一种最常见的二进制编码方法。&lt;/p&gt;
&lt;p&gt;Base64的原理很简单，首先，准备一个包含64个字符的数组：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[&amp;#39;A&amp;#39;, &amp;#39;B&amp;#39;, &amp;#39;C&amp;#39;, ... &amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;, ... &amp;#39;0&amp;#39;, &amp;#39;1&amp;#39;, ... &amp;#39;+&amp;#39;, &amp;#39;/&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后，对二进制数据进行处理，每3个字节一组，一共是&lt;code&gt;3x8=24&lt;/code&gt;bit，划为4组，每组正好6个bit：&lt;/p&gt;
&lt;p&gt;&lt;img alt="base64-encode" loading="lazy" src="001399415038305edba53df7d784a7fa76c6b7f6526873b000"&gt;&lt;/p&gt;
&lt;p&gt;这样我们得到4个数字作为索引，然后查表，获得相应的4个字符，就是编码后的字符串。&lt;/p&gt;
&lt;p&gt;所以，Base64编码会把3字节的二进制数据编码为4字节的文本数据，长度增加33%，好处是编码后的文本数据可以在邮件正文、网页等直接显示。&lt;/p&gt;
&lt;p&gt;如果要编码的二进制数据不是3的倍数，最后会剩下1个或2个字节怎么办？Base64用&lt;code&gt;\x00&lt;/code&gt;字节在末尾补足后，再在编码的末尾加上1个或2个&lt;code&gt;=&lt;/code&gt;号，表示补了多少字节，解码的时候，会自动去掉。&lt;/p&gt;
&lt;p&gt;Python内置的&lt;code&gt;base64&lt;/code&gt;可以直接进行base64的编解码：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import base64
&amp;gt;&amp;gt;&amp;gt; base64.b64encode(b&amp;#39;binary\x00string&amp;#39;)
b&amp;#39;YmluYXJ5AHN0cmluZw==&amp;#39;
&amp;gt;&amp;gt;&amp;gt; base64.b64decode(b&amp;#39;YmluYXJ5AHN0cmluZw==&amp;#39;)
b&amp;#39;binary\x00string&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由于标准的Base64编码后可能出现字符&lt;code&gt;+&lt;/code&gt;和&lt;code&gt;/&lt;/code&gt;，在URL中就不能直接作为参数，所以又有一种&amp;quot;url safe&amp;quot;的base64编码，其实就是把字符&lt;code&gt;+&lt;/code&gt;和&lt;code&gt;/&lt;/code&gt;分别变成&lt;code&gt;-&lt;/code&gt;和&lt;code&gt;_&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; base64.b64encode(b&amp;#39;i\xb7\x1d\xfb\xef\xff&amp;#39;)
b&amp;#39;abcd++//&amp;#39;
&amp;gt;&amp;gt;&amp;gt; base64.urlsafe_b64encode(b&amp;#39;i\xb7\x1d\xfb\xef\xff&amp;#39;)
b&amp;#39;abcd--__&amp;#39;
&amp;gt;&amp;gt;&amp;gt; base64.urlsafe_b64decode(&amp;#39;abcd--__&amp;#39;)
b&amp;#39;i\xb7\x1d\xfb\xef\xff&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;还可以自己定义64个字符的排列顺序，这样就可以自定义Base64编码，不过，通常情况下完全没有必要。&lt;/p&gt;
&lt;p&gt;Base64是一种通过查表的编码方法，不能用于加密，即使使用自定义的编码表也不行。&lt;/p&gt;
&lt;p&gt;Base64适用于小段内容的编码，比如数字证书签名、Cookie的内容等。&lt;/p&gt;
&lt;p&gt;由于&lt;code&gt;=&lt;/code&gt;字符也可能出现在Base64编码中，但&lt;code&gt;=&lt;/code&gt;用在URL、Cookie里面会造成歧义，所以，很多Base64编码后会把&lt;code&gt;=&lt;/code&gt;去掉：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 标准Base64:
&amp;#39;abcd&amp;#39; -&amp;gt; &amp;#39;YWJjZA==&amp;#39;
# 自动去掉=:
&amp;#39;abcd&amp;#39; -&amp;gt; &amp;#39;YWJjZA&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;去掉&lt;code&gt;=&lt;/code&gt;后怎么解码呢？因为Base64是把3个字节变为4个字节，所以，Base64编码的长度永远是4的倍数，因此，需要加上&lt;code&gt;=&lt;/code&gt;把Base64字符串的长度变为4的倍数，就可以正常解码了。&lt;/p&gt;
&lt;p&gt;小结&lt;/p&gt;
&lt;p&gt;Base64是一种任意二进制到文本字符串的编码方法，常用于在URL、Cookie、网页中传输少量二进制数据。&lt;/p&gt;
&lt;p&gt;练习&lt;/p&gt;
&lt;p&gt;请写一个能处理去掉&lt;code&gt;=&lt;/code&gt;的base64解码函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; base64
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;safe_base64_decode&lt;/span&gt;(s):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试:&lt;/p&gt;</description></item><item><title>Python内建模块collections</title><link>/2016/06/14/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97collections/</link><pubDate>Tue, 14 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/14/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97collections/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;collections是Python内建的一个集合模块，提供了许多有用的集合类。&lt;/p&gt;
&lt;h3 id="namedtuple"&gt;namedtuple&lt;/h3&gt;
&lt;p&gt;我们知道&lt;code&gt;tuple&lt;/code&gt;可以表示不变集合，例如，一个点的二维坐标就可以表示成：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; p = (1, 2)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是，看到&lt;code&gt;(1, 2)&lt;/code&gt;，很难看出这个&lt;code&gt;tuple&lt;/code&gt;是用来表示一个坐标的。&lt;/p&gt;
&lt;p&gt;定义一个class又小题大做了，这时，&lt;code&gt;namedtuple&lt;/code&gt;就派上了用场：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from collections import namedtuple
&amp;gt;&amp;gt;&amp;gt; Point = namedtuple(&amp;#39;Point&amp;#39;, [&amp;#39;x&amp;#39;, &amp;#39;y&amp;#39;])
&amp;gt;&amp;gt;&amp;gt; p = Point(1, 2)
&amp;gt;&amp;gt;&amp;gt; p.x
1
&amp;gt;&amp;gt;&amp;gt; p.y
2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;namedtuple&lt;/code&gt;是一个函数，它用来创建一个自定义的&lt;code&gt;tuple&lt;/code&gt;对象，并且规定了&lt;code&gt;tuple&lt;/code&gt;元素的个数，并可以用属性而不是索引来引用&lt;code&gt;tuple&lt;/code&gt;的某个元素。&lt;/p&gt;
&lt;p&gt;这样一来，我们用&lt;code&gt;namedtuple&lt;/code&gt;可以很方便地定义一种数据类型，它具备tuple的不变性，又可以根据属性来引用，使用十分方便。&lt;/p&gt;
&lt;p&gt;可以验证创建的&lt;code&gt;Point&lt;/code&gt;对象是&lt;code&gt;tuple&lt;/code&gt;的一种子类：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; isinstance(p, Point)
True
&amp;gt;&amp;gt;&amp;gt; isinstance(p, tuple)
True
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;类似的，如果要用坐标和半径表示一个圆，也可以用&lt;code&gt;namedtuple&lt;/code&gt;定义：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# namedtuple(&amp;#39;名称&amp;#39;, [属性list]):
Circle = namedtuple(&amp;#39;Circle&amp;#39;, [&amp;#39;x&amp;#39;, &amp;#39;y&amp;#39;, &amp;#39;r&amp;#39;])
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="deque"&gt;deque&lt;/h3&gt;
&lt;p&gt;使用&lt;code&gt;list&lt;/code&gt;存储数据时，按索引访问元素很快，但是插入和删除元素就很慢了，因为&lt;code&gt;list&lt;/code&gt;是线性存储，数据量大的时候，插入和删除效率很低。&lt;/p&gt;
&lt;p&gt;deque是为了高效实现插入和删除操作的双向列表，适合用于队列和栈：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from collections import deque
&amp;gt;&amp;gt;&amp;gt; q = deque([&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;])
&amp;gt;&amp;gt;&amp;gt; q.append(&amp;#39;x&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; q.appendleft(&amp;#39;y&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; q
deque([&amp;#39;y&amp;#39;, &amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;, &amp;#39;x&amp;#39;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;deque&lt;/code&gt;除了实现list的&lt;code&gt;append()&lt;/code&gt;和&lt;code&gt;pop()&lt;/code&gt;外，还支持&lt;code&gt;appendleft()&lt;/code&gt;和&lt;code&gt;popleft()&lt;/code&gt;，这样就可以非常高效地往头部添加或删除元素。&lt;/p&gt;</description></item><item><title>Python内建模块datetime</title><link>/2016/06/13/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97datetime/</link><pubDate>Mon, 13 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/13/python%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97datetime/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;Python之所以自称“batteries included”，就是因为内置了许多非常有用的模块，无需额外安装和配置，即可直接使用。&lt;/p&gt;
&lt;p&gt;datetime是Python处理日期和时间的标准库。&lt;/p&gt;
&lt;h3 id="获取当前日期和时间"&gt;获取当前日期和时间&lt;/h3&gt;
&lt;p&gt;我们先看如何获取当前日期和时间：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from datetime import datetime
&amp;gt;&amp;gt;&amp;gt; now = datetime.now() # 获取当前datetime
&amp;gt;&amp;gt;&amp;gt; print(now)
2015-05-18 16:28:07.198690
&amp;gt;&amp;gt;&amp;gt; print(type(now))
&amp;lt;class &amp;#39;datetime.datetime&amp;#39;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意到&lt;code&gt;datetime&lt;/code&gt;是模块，&lt;code&gt;datetime&lt;/code&gt;模块还包含一个&lt;code&gt;datetime&lt;/code&gt;类，通过&lt;code&gt;from datetime import datetime&lt;/code&gt;导入的才是&lt;code&gt;datetime&lt;/code&gt;这个类。&lt;/p&gt;
&lt;p&gt;如果仅导入&lt;code&gt;import datetime&lt;/code&gt;，则必须引用全名&lt;code&gt;datetime.datetime&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;datetime.now()&lt;/code&gt;返回当前日期和时间，其类型是&lt;code&gt;datetime&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="获取指定日期和时间"&gt;获取指定日期和时间&lt;/h3&gt;
&lt;p&gt;要指定某个日期和时间，我们直接用参数构造一个&lt;code&gt;datetime&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from datetime import datetime
&amp;gt;&amp;gt;&amp;gt; dt = datetime(2015, 4, 19, 12, 20) # 用指定日期时间创建datetime
&amp;gt;&amp;gt;&amp;gt; print(dt)
2015-04-19 12:20:00
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="datetime转换为timestamp"&gt;datetime转换为timestamp&lt;/h3&gt;
&lt;p&gt;在计算机中，时间实际上是用数字表示的。我们把1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time，记为&lt;code&gt;0&lt;/code&gt;（1970年以前的时间timestamp为负数），当前时间就是相对于epoch time的秒数，称为timestamp。&lt;/p&gt;
&lt;p&gt;你可以认为：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对应的北京时间是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可见timestamp的值与时区毫无关系，因为timestamp一旦确定，其UTC时间就确定了，转换到任意时区的时间也是完全确定的，这就是为什么计算机存储的当前时间是以timestamp表示的，因为全球各地的计算机在任意时刻的timestamp都是完全相同的（假定时间已校准）。&lt;/p&gt;</description></item><item><title>Python正则表达式</title><link>/2016/06/12/python%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/</link><pubDate>Sun, 12 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/12/python%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;字符串是编程时涉及到的最多的一种数据结构，对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的Email地址，虽然可以编程提取&lt;code&gt;@&lt;/code&gt;前后的子串，再分别判断是否是单词和域名，但这样做不但麻烦，而且代码难以复用。&lt;/p&gt;
&lt;p&gt;正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则，凡是符合规则的字符串，我们就认为它“匹配”了，否则，该字符串就是不合法的。&lt;/p&gt;
&lt;p&gt;所以我们判断一个字符串是否是合法的Email的方法是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;创建一个匹配Email的正则表达式；&lt;/li&gt;
&lt;li&gt;用该正则表达式去匹配用户的输入来判断是否合法。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因为正则表达式也是用字符串表示的，所以，我们要首先了解如何用字符来描述字符。&lt;/p&gt;
&lt;p&gt;在正则表达式中，如果直接给出字符，就是精确匹配。用&lt;code&gt;\d&lt;/code&gt;可以匹配一个数字，&lt;code&gt;\w&lt;/code&gt;可以匹配一个字母或数字，所以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;'00\d'&lt;/code&gt;可以匹配&lt;code&gt;'007'&lt;/code&gt;，但无法匹配&lt;code&gt;'00A'&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;'\d\d\d'&lt;/code&gt;可以匹配&lt;code&gt;'010'&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;'\w\w\d'&lt;/code&gt;可以匹配&lt;code&gt;'py3'&lt;/code&gt;；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;.&lt;/code&gt;可以匹配任意&lt;strong&gt;单个&lt;/strong&gt;字符，所以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;'py.'&lt;/code&gt;可以匹配&lt;code&gt;'pyc'&lt;/code&gt;、&lt;code&gt;'pyo'&lt;/code&gt;、&lt;code&gt;'py!'&lt;/code&gt;等等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;要匹配变长的字符，在正则表达式中，用&lt;code&gt;*&lt;/code&gt;表示任意个字符（包括0个），用&lt;code&gt;+&lt;/code&gt;表示至少一个字符，用&lt;code&gt;?&lt;/code&gt;表示0个或1个字符，用&lt;code&gt;{n}&lt;/code&gt;表示n个字符，用&lt;code&gt;{n,m}&lt;/code&gt;表示n-m个字符：&lt;/p&gt;
&lt;p&gt;来看一个复杂的例子：&lt;code&gt;\d{3}\s+\d{3,8}&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;我们来从左到右解读一下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;\d{3}&lt;/code&gt;表示匹配3个数字，例如&lt;code&gt;'010'&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\s&lt;/code&gt;可以匹配一个空格（也包括Tab等空白符），所以&lt;code&gt;\s+&lt;/code&gt;表示至少有一个空格，例如匹配&lt;code&gt;' '&lt;/code&gt;，&lt;code&gt;' '&lt;/code&gt;等；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\d{3,8}&lt;/code&gt;表示3-8个数字，例如&lt;code&gt;'1234567'&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;综合起来，上面的正则表达式可以匹配以任意个空格隔开的带区号的电话号码。&lt;/p&gt;
&lt;p&gt;如果要匹配&lt;code&gt;'010-12345'&lt;/code&gt;这样的号码呢？由于&lt;code&gt;'-'&lt;/code&gt;是特殊字符，在正则表达式中，要用&lt;code&gt;'\'&lt;/code&gt;转义，所以，上面的正则是&lt;code&gt;\d{3}\-\d{3,8}&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;但是，仍然无法匹配&lt;code&gt;'010 - 12345'&lt;/code&gt;，因为带有空格。所以我们需要更复杂的匹配方式。&lt;/p&gt;
&lt;h3 id="进阶"&gt;进阶&lt;/h3&gt;
&lt;p&gt;要做更精确地匹配，可以用&lt;code&gt;[]&lt;/code&gt;表示范围，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[0-9a-zA-Z\_]&lt;/code&gt;可以匹配一个数字、字母或者下划线；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[0-9a-zA-Z\_]+&lt;/code&gt;可以匹配至少由一个数字、字母或者下划线组成的字符串，比如&lt;code&gt;'a100'&lt;/code&gt;，&lt;code&gt;'0_Z'&lt;/code&gt;，&lt;code&gt;'Py3000'&lt;/code&gt;等等；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[a-zA-Z\_][0-9a-zA-Z\_]*&lt;/code&gt;可以匹配由字母或下划线开头，后接任意个由一个数字、字母或者下划线组成的字符串，也就是Python合法的变量；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[a-zA-Z\_][0-9a-zA-Z\_]{0, 19}&lt;/code&gt;更精确地限制了变量的长度是1-20个字符（前面1个字符+后面最多19个字符）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;A|B&lt;/code&gt;可以匹配A或B，所以&lt;code&gt;(P|p)ython&lt;/code&gt;可以匹配&lt;code&gt;'Python'&lt;/code&gt;或者&lt;code&gt;'python'&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;^&lt;/code&gt;表示行的开头，&lt;code&gt;^\d&lt;/code&gt;表示必须以数字开头。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$&lt;/code&gt;表示行的结束，&lt;code&gt;\d$&lt;/code&gt;表示必须以数字结束。&lt;/p&gt;
&lt;p&gt;你可能注意到了，&lt;code&gt;py&lt;/code&gt;也可以匹配&lt;code&gt;'python'&lt;/code&gt;，但是加上&lt;code&gt;^py$&lt;/code&gt;就变成了整行匹配，就只能匹配&lt;code&gt;'py'&lt;/code&gt;了。&lt;/p&gt;
&lt;h3 id="re模块"&gt;re模块&lt;/h3&gt;
&lt;p&gt;有了准备知识，我们就可以在Python中使用正则表达式了。Python提供&lt;code&gt;re&lt;/code&gt;模块，包含所有正则表达式的功能。由于Python的字符串本身也用&lt;code&gt;\&lt;/code&gt;转义，所以要特别注意：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;s = &amp;#39;ABC\\-001&amp;#39; # Python的字符串
# 对应的正则表达式字符串变成：
# &amp;#39;ABC\-001&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因此我们强烈建议使用Python的&lt;code&gt;r&lt;/code&gt;前缀，就不用考虑转义的问题了：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;s = r&amp;#39;ABC\-001&amp;#39; # Python的字符串
# 对应的正则表达式字符串不变：
# &amp;#39;ABC\-001&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;先看看如何判断正则表达式是否匹配：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import re
&amp;gt;&amp;gt;&amp;gt; re.match(r&amp;#39;^\d{3}\-\d{3,8}$&amp;#39;, &amp;#39;010-12345&amp;#39;)
&amp;lt;_sre.SRE_Match object; span=(0, 9), match=&amp;#39;010-12345&amp;#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; re.match(r&amp;#39;^\d{3}\-\d{3,8}$&amp;#39;, &amp;#39;010 12345&amp;#39;)
&amp;gt;&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;match()&lt;/code&gt;方法判断是否匹配，如果匹配成功，返回一个&lt;code&gt;Match&lt;/code&gt;对象，否则返回&lt;code&gt;None&lt;/code&gt;。常见的判断方法就是：&lt;/p&gt;</description></item><item><title>Python多任务处理</title><link>/2016/06/11/python%E5%A4%9A%E4%BB%BB%E5%8A%A1%E5%A4%84%E7%90%86/</link><pubDate>Sat, 11 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/11/python%E5%A4%9A%E4%BB%BB%E5%8A%A1%E5%A4%84%E7%90%86/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;前两天写了多进程和多线程，这是实现多任务最常用的两种方式。现在，我们来讨论一下这两种方式的优缺点。&lt;/p&gt;
&lt;p&gt;首先，要实现多任务，通常我们会设计Master-Worker模式，Master负责分配任务，Worker负责执行任务，因此，多任务环境下，通常是一个Master，多个Worker。&lt;/p&gt;
&lt;p&gt;如果用多进程实现Master-Worker，主进程就是Master，其他进程就是Worker。&lt;/p&gt;
&lt;p&gt;如果用多线程实现Master-Worker，主线程就是Master，其他线程就是Worker。&lt;/p&gt;
&lt;p&gt;多进程模式最大的优点就是稳定性高，因为一个子进程崩溃了，不会影响主进程和其他子进程。（当然主进程挂了所有进程就全挂了，但是Master进程只负责分配任务，挂掉的概率低）著名的Apache最早就是采用多进程模式。&lt;/p&gt;
&lt;p&gt;多进程模式的缺点是创建进程的代价大，在Unix/Linux系统下，用&lt;code&gt;fork&lt;/code&gt;调用还行，在Windows下创建进程开销巨大。另外，操作系统能同时运行的进程数也是有限的，在内存和CPU的限制下，如果有几千个进程同时运行，操作系统连调度都会成问题。&lt;/p&gt;
&lt;p&gt;多线程模式通常比多进程快一点，但是也快不到哪去，而且，多线程模式致命的缺点就是任何一个线程挂掉都可能直接造成整个进程崩溃，因为所有线程共享进程的内存。在Windows上，如果一个线程执行的代码出了问题，你经常可以看到这样的提示：“该程序执行了非法操作，即将关闭”，其实往往是某个线程出了问题，但是操作系统会强制结束整个进程。&lt;/p&gt;
&lt;p&gt;在Windows下，多线程的效率比多进程要高，所以微软的IIS服务器默认采用多线程模式。由于多线程存在稳定性的问题，IIS的稳定性就不如Apache。为了缓解这个问题，IIS和Apache现在又有多进程+多线程的混合模式，真是把问题越搞越复杂。&lt;/p&gt;
&lt;h3 id="线程切换"&gt;线程切换&lt;/h3&gt;
&lt;p&gt;无论是多进程还是多线程，只要数量一多，效率肯定上不去，为什么呢？&lt;/p&gt;
&lt;p&gt;我们打个比方，假设你不幸正在准备中考，每天晚上需要做语文、数学、英语、物理、化学这5科的作业，每项作业耗时1小时。&lt;/p&gt;
&lt;p&gt;如果你先花1小时做语文作业，做完了，再花1小时做数学作业，这样，依次全部做完，一共花5小时，这种方式称为单任务模型，或者批处理任务模型。&lt;/p&gt;
&lt;p&gt;假设你打算切换到多任务模型，可以先做1分钟语文，再切换到数学作业，做1分钟，再切换到英语，以此类推，只要切换速度足够快，这种方式就和单核CPU执行多任务是一样的了，以幼儿园小朋友的眼光来看，你就正在同时写5科作业。&lt;/p&gt;
&lt;p&gt;但是，切换作业是有代价的，比如从语文切到数学，要先收拾桌子上的语文书本、钢笔（这叫保存现场），然后，打开数学课本、找出圆规直尺（这叫准备新环境），才能开始做数学作业。操作系统在切换进程或者线程时也是一样的，它需要先保存当前执行的现场环境（CPU寄存器状态、内存页等），然后，把新任务的执行环境准备好（恢复上次的寄存器状态，切换内存页等），才能开始执行。这个切换过程虽然很快，但是也需要耗费时间。如果有几千个任务同时进行，操作系统可能就主要忙着切换任务，根本没有多少时间去执行任务了，这种情况最常见的就是硬盘狂响，点窗口无反应，系统处于假死状态。&lt;/p&gt;
&lt;p&gt;所以，多任务一旦多到一个限度，就会消耗掉系统所有的资源，结果效率急剧下降，所有任务都做不好。&lt;/p&gt;
&lt;h3 id="计算密集型-vs-io密集型"&gt;计算密集型 vs. IO密集型&lt;/h3&gt;
&lt;p&gt;是否采用多任务的第二个考虑是任务的类型。我们可以把任务分为计算密集型和IO密集型。&lt;/p&gt;
&lt;p&gt;计算密集型任务的特点是要进行大量的计算，消耗CPU资源，比如计算圆周率、对视频进行高清解码等等，全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成，但是任务越多，花在任务切换的时间就越多，CPU执行任务的效率就越低，所以，要最高效地利用CPU，计算密集型任务同时进行的数量应当等于CPU的核心数。&lt;/p&gt;
&lt;p&gt;计算密集型任务由于主要消耗CPU资源，因此，代码运行效率至关重要。Python这样的脚本语言运行效率很低，完全不适合计算密集型任务。对于计算密集型任务，最好用C语言编写。&lt;/p&gt;
&lt;p&gt;第二种任务的类型是IO密集型，涉及到网络、磁盘IO的任务都是IO密集型任务，这类任务的特点是CPU消耗很少，任务的大部分时间都在等待IO操作完成（因为IO的速度远远低于CPU和内存的速度）。对于IO密集型任务，任务越多，CPU效率越高，但也有一个限度。常见的大部分任务都是IO密集型任务，比如Web应用。&lt;/p&gt;
&lt;p&gt;IO密集型任务执行期间，99%的时间都花在IO上，花在CPU上的时间很少，因此，用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言，完全无法提升运行效率。对于IO密集型任务，最合适的语言就是开发效率最高（代码量最少）的语言，脚本语言是首选，C语言最差。&lt;/p&gt;
&lt;h3 id="异步io"&gt;异步IO&lt;/h3&gt;
&lt;p&gt;考虑到CPU和IO之间巨大的速度差异，一个任务在执行的过程中大部分时间都在等待IO操作，单进程单线程模型会导致别的任务无法并行执行，因此，我们才需要多进程模型或者多线程模型来支持多任务并发执行。&lt;/p&gt;
&lt;p&gt;现代操作系统对IO操作已经做了巨大的改进，最大的特点就是支持异步IO。如果充分利用操作系统提供的异步IO支持，就可以用单进程单线程模型来执行多任务，这种全新的模型称为事件驱动模型，Nginx就是支持异步IO的Web服务器，它在单核CPU上采用单进程模型就可以高效地支持多任务。在多核CPU上，可以运行多个进程（数量与CPU核心数相同），充分利用多核CPU。由于系统总的进程数量十分有限，因此操作系统调度非常高效。用异步IO编程模型来实现多任务是一个主要的趋势。&lt;/p&gt;
&lt;p&gt;对应到Python语言，单线程的异步编程模型称为协程，有了协程的支持，就可以基于事件驱动编写高效的多任务程序。后面再写协程.&lt;/p&gt;</description></item><item><title>Python ThreadLocal</title><link>/2016/06/10/python-threadlocal/</link><pubDate>Fri, 10 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/10/python-threadlocal/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;在多线程环境下，每个线程都有自己的数据。一个线程使用自己的局部变量比使用全局变量好，因为局部变量只有线程自己能看见，不会影响其他线程，而全局变量的修改必须加锁。&lt;/p&gt;
&lt;p&gt;但是局部变量也有问题，就是在函数调用的时候，传递起来很麻烦：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def process_student(name):
std = Student(name)
# std是局部变量，但是每个函数都要用它，因此必须传进去：
do_task_1(std)
do_task_2(std)
def do_task_1(std):
do_subtask_1(std)
do_subtask_2(std)
def do_task_2(std):
do_subtask_2(std)
do_subtask_2(std)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;每个函数一层一层调用都这么传参数那还得了？用全局变量？也不行，因为每个线程处理不同的&lt;code&gt;Student&lt;/code&gt;对象，不能共享。&lt;/p&gt;
&lt;p&gt;如果用一个全局&lt;code&gt;dict&lt;/code&gt;存放所有的&lt;code&gt;Student&lt;/code&gt;对象，然后以&lt;code&gt;thread&lt;/code&gt;自身作为&lt;code&gt;key&lt;/code&gt;获得线程对应的&lt;code&gt;Student&lt;/code&gt;对象如何？&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;global_dict = {}
def std_thread(name):
std = Student(name)
# 把std放到全局变量global_dict中：
global_dict[threading.current_thread()] = std
do_task_1()
do_task_2()
def do_task_1():
# 不传入std，而是根据当前线程查找：
std = global_dict[threading.current_thread()]
...
def do_task_2():
# 任何函数都可以查找出当前线程的std变量：
std = global_dict[threading.current_thread()]
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这种方式理论上是可行的，它最大的优点是消除了&lt;code&gt;std&lt;/code&gt;对象在每层函数中的传递问题，但是，每个函数获取&lt;code&gt;std&lt;/code&gt;的代码有点丑。&lt;/p&gt;
&lt;p&gt;有没有更简单的方式？&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ThreadLocal&lt;/code&gt;应运而生，不用查找&lt;code&gt;dict&lt;/code&gt;，&lt;code&gt;ThreadLocal&lt;/code&gt;帮你自动做这件事：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import threading
# 创建全局ThreadLocal对象:
local_school = threading.local()
def process_student():
# 获取当前线程关联的student:
std = local_school.student
print(&amp;#39;Hello, %s (in %s)&amp;#39; % (std, threading.current_thread().name))
def process_thread(name):
# 绑定ThreadLocal的student:
local_school.student = name
process_student()
t1 = threading.Thread(target= process_thread, args=(&amp;#39;Alice&amp;#39;,), name=&amp;#39;Thread-A&amp;#39;)
t2 = threading.Thread(target= process_thread, args=(&amp;#39;Bob&amp;#39;,), name=&amp;#39;Thread-B&amp;#39;)
t1.start()
t2.start()
t1.join()
t2.join()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;执行结果：&lt;/p&gt;</description></item><item><title>Python多线程</title><link>/2016/06/09/python%E5%A4%9A%E7%BA%BF%E7%A8%8B/</link><pubDate>Thu, 09 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/09/python%E5%A4%9A%E7%BA%BF%E7%A8%8B/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="线程"&gt;线程&lt;/h2&gt;
&lt;p&gt;在一个进程内部，要同时干多件事，就需要同时运行多个“子任务”，我们把进程内的这些“子任务”称为线程（Thread）。&lt;/p&gt;
&lt;p&gt;多任务可以由多进程完成，也可以由一个进程内的多线程完成。&lt;/p&gt;
&lt;p&gt;我们前面提到了进程是由若干线程组成的，一个进程至少有一个线程。&lt;/p&gt;
&lt;p&gt;由于线程是操作系统直接支持的执行单元，因此，高级语言通常都内置多线程的支持，Python也不例外，并且，Python的线程是真正的Posix Thread，而不是模拟出来的线程。&lt;/p&gt;
&lt;p&gt;Python的标准库提供了两个模块：&lt;code&gt;_thread&lt;/code&gt;和&lt;code&gt;threading&lt;/code&gt;，&lt;code&gt;_thread&lt;/code&gt;是低级模块，&lt;code&gt;threading&lt;/code&gt;是高级模块，对&lt;code&gt;_thread&lt;/code&gt;进行了封装。绝大多数情况下，我们只需要使用&lt;code&gt;threading&lt;/code&gt;这个高级模块。&lt;/p&gt;
&lt;p&gt;启动一个线程就是把一个函数传入并创建&lt;code&gt;Thread&lt;/code&gt;实例，然后调用&lt;code&gt;start()&lt;/code&gt;开始执行：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import time, threading
# 新线程执行的代码:
def loop():
print(&amp;#39;thread %s is running...&amp;#39; % threading.current_thread().name)
n = 0
while n &amp;lt; 5:
n = n + 1
print(&amp;#39;thread %s &amp;gt;&amp;gt;&amp;gt; %s&amp;#39; % (threading.current_thread().name, n))
time.sleep(1)
print(&amp;#39;thread %s ended.&amp;#39; % threading.current_thread().name)
print(&amp;#39;thread %s is running...&amp;#39; % threading.current_thread().name)
t = threading.Thread(target=loop, name=&amp;#39;LoopThread&amp;#39;)
t.start()
t.join()
print(&amp;#39;thread %s ended.&amp;#39; % threading.current_thread().name)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;执行结果如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;thread MainThread is running...
thread LoopThread is running...
thread LoopThread &amp;gt;&amp;gt;&amp;gt; 1
thread LoopThread &amp;gt;&amp;gt;&amp;gt; 2
thread LoopThread &amp;gt;&amp;gt;&amp;gt; 3
thread LoopThread &amp;gt;&amp;gt;&amp;gt; 4
thread LoopThread &amp;gt;&amp;gt;&amp;gt; 5
thread LoopThread ended.
thread MainThread ended.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由于任何进程默认就会启动一个线程，我们把该线程称为主线程，主线程又可以启动新的线程，Python的&lt;code&gt;threading&lt;/code&gt;模块有个&lt;code&gt;current_thread()&lt;/code&gt;函数，它永远返回当前线程的实例。主线程实例的名字叫&lt;code&gt;MainThread&lt;/code&gt;，子线程的名字在创建时指定，我们用&lt;code&gt;LoopThread&lt;/code&gt;命名子线程。名字仅仅在打印时用来显示，完全没有其他意义，如果不起名字Python就自动给线程命名为&lt;code&gt;Thread-1&lt;/code&gt;，&lt;code&gt;Thread-2&lt;/code&gt;……&lt;/p&gt;</description></item><item><title>Python多进程</title><link>/2016/06/09/python%E5%A4%9A%E8%BF%9B%E7%A8%8B/</link><pubDate>Thu, 09 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/09/python%E5%A4%9A%E8%BF%9B%E7%A8%8B/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="进程"&gt;进程&lt;/h2&gt;
&lt;p&gt;一个任务就是一个进程（Process）&lt;/p&gt;
&lt;p&gt;要让Python程序实现多进程（multiprocessing），我们先了解操作系统的相关知识。&lt;/p&gt;
&lt;p&gt;Unix/Linux操作系统提供了一个&lt;code&gt;fork()&lt;/code&gt;系统调用，它非常特殊。普通的函数调用，调用一次，返回一次，但是&lt;code&gt;fork()&lt;/code&gt;调用一次，返回两次，因为操作系统自动把当前进程（称为父进程）复制了一份（称为子进程），然后，分别在父进程和子进程内返回。&lt;/p&gt;
&lt;p&gt;子进程永远返回&lt;code&gt;0&lt;/code&gt;，而父进程返回子进程的ID。这样做的理由是，一个父进程可以fork出很多子进程，所以，父进程要记下每个子进程的ID，而子进程只需要调用&lt;code&gt;getppid()&lt;/code&gt;就可以拿到父进程的ID。&lt;/p&gt;
&lt;p&gt;Python的&lt;code&gt;os&lt;/code&gt;模块封装了常见的系统调用，其中就包括&lt;code&gt;fork&lt;/code&gt;，可以在Python程序中轻松创建子进程：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import os
print(&amp;#39;Process (%s) start...&amp;#39; % os.getpid())
# Only works on Unix/Linux/Mac:
pid = os.fork()
if pid == 0:
print(&amp;#39;I am child process (%s) and my parent is %s.&amp;#39; % (os.getpid(), os.getppid()))
else:
print(&amp;#39;I (%s) just created a child process (%s).&amp;#39; % (os.getpid(), pid))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;运行结果如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Process (876) start...
I (876) just created a child process (877).
I am child process (877) and my parent is 876.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由于Windows没有&lt;code&gt;fork&lt;/code&gt;调用，上面的代码在Windows上无法运行。由于Mac系统是基于BSD（Unix的一种）内核，所以，在Mac下运行是没有问题的，推荐大家用Mac学Python , Linux 系统更是没有问题的啦, 推荐使用Ubuntu！&lt;/p&gt;</description></item><item><title>Python序列化</title><link>/2016/06/08/python%E5%BA%8F%E5%88%97%E5%8C%96/</link><pubDate>Wed, 08 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/08/python%E5%BA%8F%E5%88%97%E5%8C%96/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="序列化"&gt;序列化&lt;/h2&gt;
&lt;p&gt;把变量从内存中变成可存储或传输的过程称之为序列化，在Python中叫pickling&lt;/p&gt;
&lt;p&gt;在程序运行的过程中，所有的变量都是在内存中，比如，定义一个dict：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;d = dict(name=&amp;#39;Bob&amp;#39;, age=20, score=88)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以随时修改变量，比如把&lt;code&gt;name&lt;/code&gt;改成&lt;code&gt;'Bill'&lt;/code&gt;，但是一旦程序结束，变量所占用的内存就被操作系统全部回收。如果没有把修改后的&lt;code&gt;'Bill'&lt;/code&gt;存储到磁盘上，下次重新运行程序，变量又被初始化为&lt;code&gt;'Bob'&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;序列化在Python中叫pickling，在其他语言中也被称之为serialization，marshalling，flattening等等，都是一个意思。&lt;/p&gt;
&lt;p&gt;序列化之后，就可以把序列化后的内容写入磁盘，或者通过网络传输到别的机器上。&lt;/p&gt;
&lt;p&gt;反过来，把变量内容从序列化的对象重新读到内存里称之为反序列化，即unpickling。&lt;/p&gt;
&lt;p&gt;Python提供了&lt;code&gt;pickle&lt;/code&gt;模块来实现序列化。&lt;/p&gt;
&lt;p&gt;首先，我们尝试把一个对象序列化并写入文件：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import pickle
&amp;gt;&amp;gt;&amp;gt; d = dict(name=&amp;#39;Bob&amp;#39;, age=20, score=88)
&amp;gt;&amp;gt;&amp;gt; pickle.dumps(d)
b&amp;#39;\x80\x03}q\x00(X\x03\x00\x00\x00ageq\x01K\x14X\x05\x00\x00\x00scoreq\x02KXX\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00Bobq\x04u.&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;pickle.dumps()&lt;/code&gt;方法把任意对象序列化成一个&lt;code&gt;bytes&lt;/code&gt;，然后，就可以把这个&lt;code&gt;bytes&lt;/code&gt;写入文件。或者用另一个方法&lt;code&gt;pickle.dump()&lt;/code&gt;直接把对象序列化后写入一个file-like Object：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f = open(&amp;#39;dump.txt&amp;#39;, &amp;#39;wb&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; pickle.dump(d, f)
&amp;gt;&amp;gt;&amp;gt; f.close()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;看看写入的&lt;code&gt;dump.txt&lt;/code&gt;文件，一堆乱七八糟的内容，这些都是Python保存的对象内部信息。&lt;/p&gt;
&lt;p&gt;当我们要把对象从磁盘读到内存时，可以先把内容读到一个&lt;code&gt;bytes&lt;/code&gt;，然后用&lt;code&gt;pickle.loads()&lt;/code&gt;方法反序列化出对象，也可以直接用&lt;code&gt;pickle.load()&lt;/code&gt;方法从一个&lt;code&gt;file-like Object&lt;/code&gt;中直接反序列化出对象。我们打开另一个Python命令行来反序列化刚才保存的对象：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f = open(&amp;#39;dump.txt&amp;#39;, &amp;#39;rb&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; d = pickle.load(f)
&amp;gt;&amp;gt;&amp;gt; f.close()
&amp;gt;&amp;gt;&amp;gt; d
{&amp;#39;age&amp;#39;: 20, &amp;#39;score&amp;#39;: 88, &amp;#39;name&amp;#39;: &amp;#39;Bob&amp;#39;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;变量的内容又回来了！&lt;/p&gt;
&lt;p&gt;当然，这个变量和原来的变量是完全不相干的对象，它们只是内容相同而已。&lt;/p&gt;
&lt;p&gt;Pickle的问题和所有其他编程语言特有的序列化问题一样，就是它只能用于Python，并且可能不同版本的Python彼此都不兼容，因此，只能用Pickle保存那些不重要的数据，不能成功地反序列化也没关系。&lt;/p&gt;
&lt;h3 id="json"&gt;JSON&lt;/h3&gt;
&lt;p&gt;如果我们要在不同的编程语言之间传递对象，就必须把对象序列化为标准格式，比如XML，但更好的方法是序列化为JSON，因为JSON表示出来就是一个字符串，可以被所有语言读取，也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式，并且比XML更快，而且可以直接在Web页面中读取，非常方便。&lt;/p&gt;
&lt;p&gt;JSON表示的对象就是标准的JavaScript语言的对象，JSON和Python内置的数据类型对应如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;JSON类型&lt;/th&gt;
&lt;th&gt;Python类型&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;{}&lt;/td&gt;
&lt;td&gt;dict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[]&lt;/td&gt;
&lt;td&gt;list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;ldquo;string&amp;rdquo;&lt;/td&gt;
&lt;td&gt;str&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1234.56&lt;/td&gt;
&lt;td&gt;int或float&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;true/false&lt;/td&gt;
&lt;td&gt;True/False&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;null&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Python内置的&lt;code&gt;json&lt;/code&gt;模块提供了非常完善的Python对象到JSON格式的转换。我们先看看如何把Python对象变成一个JSON：&lt;/p&gt;</description></item><item><title>Python操作文件和目录</title><link>/2016/06/07/python%E6%93%8D%E4%BD%9C%E6%96%87%E4%BB%B6%E5%92%8C%E7%9B%AE%E5%BD%95/</link><pubDate>Tue, 07 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/07/python%E6%93%8D%E4%BD%9C%E6%96%87%E4%BB%B6%E5%92%8C%E7%9B%AE%E5%BD%95/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;如果我们要操作文件、目录，可以在命令行下面输入操作系统提供的各种命令来完成。比如&lt;code&gt;dir&lt;/code&gt;、&lt;code&gt;cp&lt;/code&gt;等命令。&lt;/p&gt;
&lt;p&gt;如果要在Python程序中执行这些目录和文件的操作怎么办？其实操作系统提供的命令只是简单地调用了操作系统提供的接口函数，Python内置的&lt;code&gt;os&lt;/code&gt;模块也可以直接调用操作系统提供的接口函数。&lt;/p&gt;
&lt;p&gt;打开Python交互式命令行，我们来看看如何使用&lt;code&gt;os&lt;/code&gt;模块的基本功能：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import os
&amp;gt;&amp;gt;&amp;gt; os.name # 操作系统类型
&amp;#39;posix&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果是&lt;code&gt;posix&lt;/code&gt;，说明系统是&lt;code&gt;Linux&lt;/code&gt;、&lt;code&gt;Unix&lt;/code&gt;或&lt;code&gt;Mac OS X&lt;/code&gt;，如果是&lt;code&gt;nt&lt;/code&gt;，就是&lt;code&gt;Windows&lt;/code&gt;系统。&lt;/p&gt;
&lt;p&gt;要获取详细的系统信息，可以调用&lt;code&gt;uname()&lt;/code&gt;函数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; os.uname()
posix.uname_result(sysname=&amp;#39;Darwin&amp;#39;, nodename=&amp;#39;MichaelMacPro.local&amp;#39;, release=&amp;#39;14.3.0&amp;#39;, version=&amp;#39;Darwin Kernel Version 14.3.0: Mon Mar 23 11:59:05 PDT 2015; root:xnu-2782.20.48~5/RELEASE_X86_64&amp;#39;, machine=&amp;#39;x86_64&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意&lt;code&gt;uname()&lt;/code&gt;函数在Windows上不提供，也就是说，&lt;code&gt;os&lt;/code&gt;模块的某些函数是跟操作系统相关的。&lt;/p&gt;
&lt;h3 id="环境变量"&gt;环境变量&lt;/h3&gt;
&lt;p&gt;在操作系统中定义的环境变量，全部保存在&lt;code&gt;os.environ&lt;/code&gt;这个变量中，可以直接查看：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; os.environ
environ({&amp;#39;VERSIONER_PYTHON_PREFER_32_BIT&amp;#39;: &amp;#39;no&amp;#39;, &amp;#39;TERM_PROGRAM_VERSION&amp;#39;: &amp;#39;326&amp;#39;, &amp;#39;LOGNAME&amp;#39;: &amp;#39;michael&amp;#39;, &amp;#39;USER&amp;#39;: &amp;#39;michael&amp;#39;, &amp;#39;PATH&amp;#39;: &amp;#39;/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/mysql/bin&amp;#39;, ...})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;要获取某个环境变量的值，可以调用&lt;code&gt;os.environ.get('key')&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; os.environ.get(&amp;#39;PATH&amp;#39;)
&amp;#39;/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/mysql/bin&amp;#39;
&amp;gt;&amp;gt;&amp;gt; os.environ.get(&amp;#39;x&amp;#39;, &amp;#39;default&amp;#39;)
&amp;#39;default&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="操作文件和目录"&gt;操作文件和目录&lt;/h3&gt;
&lt;p&gt;操作文件和目录的函数一部分放在&lt;code&gt;os&lt;/code&gt;模块中，一部分放在&lt;code&gt;os.path&lt;/code&gt;模块中，这一点要注意一下。查看、创建和删除目录可以这么调用：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 查看当前目录的绝对路径:
&amp;gt;&amp;gt;&amp;gt; os.path.abspath(&amp;#39;.&amp;#39;)
&amp;#39;/Users/michael&amp;#39;
# 在某个目录下创建一个新目录，首先把新目录的完整路径表示出来:
&amp;gt;&amp;gt;&amp;gt; os.path.join(&amp;#39;/Users/michael&amp;#39;, &amp;#39;testdir&amp;#39;)
&amp;#39;/Users/michael/testdir&amp;#39;
# 然后创建一个目录:
&amp;gt;&amp;gt;&amp;gt; os.mkdir(&amp;#39;/Users/michael/testdir&amp;#39;)
# 删掉一个目录:
&amp;gt;&amp;gt;&amp;gt; os.rmdir(&amp;#39;/Users/michael/testdir&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;把两个路径合成一个时，不要直接拼字符串，而要通过&lt;code&gt;os.path.join()&lt;/code&gt;函数，这样可以正确处理不同操作系统的路径分隔符。在Linux/Unix/Mac下，&lt;code&gt;os.path.join()&lt;/code&gt;返回这样的字符串：&lt;/p&gt;</description></item><item><title>Python StringIO和BytesIO</title><link>/2016/06/06/python-stringio%E5%92%8Cbytesio/</link><pubDate>Mon, 06 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/06/python-stringio%E5%92%8Cbytesio/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="stringio"&gt;StringIO&lt;/h3&gt;
&lt;p&gt;很多时候，数据读写不一定是文件，也可以在内存中读写。&lt;/p&gt;
&lt;p&gt;StringIO顾名思义就是在内存中读写str。&lt;/p&gt;
&lt;p&gt;要把str写入StringIO，我们需要先创建一个StringIO，然后，像文件一样写入即可：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from io import StringIO
&amp;gt;&amp;gt;&amp;gt; f = StringIO()
&amp;gt;&amp;gt;&amp;gt; f.write(&amp;#39;hello&amp;#39;)
5
&amp;gt;&amp;gt;&amp;gt; f.write(&amp;#39; &amp;#39;)
1
&amp;gt;&amp;gt;&amp;gt; f.write(&amp;#39;world!&amp;#39;)
6
&amp;gt;&amp;gt;&amp;gt; print(f.getvalue())
hello world!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;getvalue()&lt;/code&gt;方法用于获得写入后的str。&lt;/p&gt;
&lt;p&gt;要读取StringIO，可以用一个str初始化StringIO，然后，像读文件一样读取：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from io import StringIO
&amp;gt;&amp;gt;&amp;gt; f = StringIO(&amp;#39;Hello!\nHi!\nGoodbye!&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; while True:
... s = f.readline()
... if s == &amp;#39;&amp;#39;:
... break
... print(s.strip())
...
Hello!
Hi!
Goodbye!
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="bytesio"&gt;BytesIO&lt;/h3&gt;
&lt;p&gt;StringIO操作的只能是str，如果要操作二进制数据，就需要使用BytesIO。&lt;/p&gt;
&lt;p&gt;BytesIO实现了在内存中读写bytes，我们创建一个BytesIO，然后写入一些bytes：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from io import BytesIO
&amp;gt;&amp;gt;&amp;gt; f = BytesIO()
&amp;gt;&amp;gt;&amp;gt; f.write(&amp;#39;中文&amp;#39;.encode(&amp;#39;utf-8&amp;#39;))
6
&amp;gt;&amp;gt;&amp;gt; print(f.getvalue())
b&amp;#39;\xe4\xb8\xad\xe6\x96\x87&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;请注意，写入的不是str，而是经过UTF-8编码的bytes。&lt;/p&gt;</description></item><item><title>Python文件读写</title><link>/2016/06/05/python%E6%96%87%E4%BB%B6%E8%AF%BB%E5%86%99/</link><pubDate>Sun, 05 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/05/python%E6%96%87%E4%BB%B6%E8%AF%BB%E5%86%99/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;读写文件是最常见的IO操作。Python内置了读写文件的函数，用法和C是兼容的。&lt;/p&gt;
&lt;p&gt;读写文件前，我们先必须了解一下，在磁盘上读写文件的功能都是由操作系统提供的，现代操作系统不允许普通的程序直接操作磁盘，所以，读写文件就是请求操作系统打开一个文件对象（通常称为文件描述符），然后，通过操作系统提供的接口从这个文件对象中读取数据（读文件），或者把数据写入这个文件对象（写文件）。&lt;/p&gt;
&lt;h3 id="读文件"&gt;读文件&lt;/h3&gt;
&lt;p&gt;要以读文件的模式打开一个文件对象，使用Python内置的&lt;code&gt;open()&lt;/code&gt;函数，传入文件名和标示符：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f = open(&amp;#39;/Users/michael/test.txt&amp;#39;, &amp;#39;r&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;标示符&amp;rsquo;r&amp;rsquo;表示读，这样，我们就成功地打开了一个文件。&lt;/p&gt;
&lt;p&gt;如果文件不存在，&lt;code&gt;open()&lt;/code&gt;函数就会抛出一个&lt;code&gt;IOError&lt;/code&gt;的错误，并且给出错误码和详细的信息告诉你文件不存在：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f=open(&amp;#39;/Users/michael/notfound.txt&amp;#39;, &amp;#39;r&amp;#39;)
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
FileNotFoundError: [Errno 2] No such file or directory: &amp;#39;/Users/michael/notfound.txt&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果文件打开成功，接下来，调用&lt;code&gt;read()&lt;/code&gt;方法可以一次读取文件的全部内容，Python把内容读到内存，用一个&lt;code&gt;str&lt;/code&gt;对象表示：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f.read()
&amp;#39;Hello, world!&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最后一步是调用&lt;code&gt;close()&lt;/code&gt;方法关闭文件。文件使用完毕后必须关闭，因为文件对象会占用操作系统的资源，并且操作系统同一时间能打开的文件数量也是有限的：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f.close()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由于文件读写时都有可能产生&lt;code&gt;IOError&lt;/code&gt;，一旦出错，后面的&lt;code&gt;f.close()&lt;/code&gt;就不会调用。所以，为了保证无论是否出错都能正确地关闭文件，我们可以使用&lt;code&gt;try ... finally&lt;/code&gt;来实现：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;try:
f = open(&amp;#39;/path/to/file&amp;#39;, &amp;#39;r&amp;#39;)
print(f.read())
finally:
if f:
f.close()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是每次都这么写实在太繁琐，所以，Python引入了&lt;code&gt;with&lt;/code&gt;语句来自动帮我们调用&lt;code&gt;close()&lt;/code&gt;方法：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;with open(&amp;#39;/path/to/file&amp;#39;, &amp;#39;r&amp;#39;) as f:
print(f.read())
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这和前面的&lt;code&gt;try ... finally&lt;/code&gt;是一样的，但是代码更佳简洁，并且不必调用&lt;code&gt;f.close()&lt;/code&gt;方法。&lt;/p&gt;
&lt;p&gt;调用&lt;code&gt;read()&lt;/code&gt;会一次性读取文件的全部内容，如果文件有10G，内存就爆了，所以，要保险起见，可以反复调用&lt;code&gt;read(size)&lt;/code&gt;方法，每次最多读取size个字节的内容。另外，调用&lt;code&gt;readline()&lt;/code&gt;可以每次读取一行内容，调用&lt;code&gt;readlines()&lt;/code&gt;一次读取所有内容并按行返回&lt;code&gt;list&lt;/code&gt;。因此，要根据需要决定怎么调用。&lt;/p&gt;
&lt;p&gt;如果文件很小，&lt;code&gt;read()&lt;/code&gt;一次性读取最方便；如果不能确定文件大小，反复调用&lt;code&gt;read(size)&lt;/code&gt;比较保险；如果是配置文件，调用&lt;code&gt;readlines()&lt;/code&gt;最方便：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;for line in f.readlines():
print(line.strip()) # 把末尾的&amp;#39;\n&amp;#39;删掉
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="file-like-object"&gt;file-like Object&lt;/h3&gt;
&lt;p&gt;像&lt;code&gt;open()&lt;/code&gt;函数返回的这种有个&lt;code&gt;read()&lt;/code&gt;方法的对象，在Python中统称为file-like Object。除了file外，还可以是内存的字节流，网络流，自定义流等等。file-like Object不要求从特定类继承，只要写个&lt;code&gt;read()&lt;/code&gt;方法就行。&lt;/p&gt;</description></item><item><title>Python文档测试</title><link>/2016/06/03/python%E6%96%87%E6%A1%A3%E6%B5%8B%E8%AF%95/</link><pubDate>Fri, 03 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/03/python%E6%96%87%E6%A1%A3%E6%B5%8B%E8%AF%95/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;如果你经常阅读Python的官方文档，可以看到很多文档都有示例代码。比如&lt;a href="https://docs.python.org/3/library/re.html"&gt;re模块&lt;/a&gt;就带了很多示例代码：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import re
&amp;gt;&amp;gt;&amp;gt; m = re.search(&amp;#39;(?&amp;lt;=abc)def&amp;#39;, &amp;#39;abcdef&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; m.group(0)
&amp;#39;def&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以把这些示例代码在Python的交互式环境下输入并执行，结果与文档中的示例代码显示的一致。&lt;/p&gt;
&lt;p&gt;这些代码与其他说明可以写在注释中，然后，由一些工具来自动生成文档。既然这些代码本身就可以粘贴出来直接运行，那么，可不可以自动执行写在注释中的这些代码呢？&lt;/p&gt;
&lt;p&gt;答案是肯定的。&lt;/p&gt;
&lt;p&gt;当我们编写注释时，如果写上这样的注释：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def abs(n):
&amp;#39;&amp;#39;&amp;#39;
Function to get absolute value of number.
Example:
&amp;gt;&amp;gt;&amp;gt; abs(1)
1
&amp;gt;&amp;gt;&amp;gt; abs(-1)
1
&amp;gt;&amp;gt;&amp;gt; abs(0)
0
&amp;#39;&amp;#39;&amp;#39;
return n if n &amp;gt;= 0 else (-n)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;无疑更明确地告诉函数的调用者该函数的期望输入和输出。&lt;/p&gt;
&lt;p&gt;并且，Python内置的“文档测试”（doctest）模块可以直接提取注释中的代码并执行测试。&lt;/p&gt;
&lt;p&gt;doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。只有测试异常的时候，可以用&lt;code&gt;...&lt;/code&gt;表示中间一大段烦人的输出。&lt;/p&gt;
&lt;p&gt;让我们用doctest来测试上次编写的&lt;code&gt;Dict&lt;/code&gt;类：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# mydict2.py
class Dict(dict):
&amp;#39;&amp;#39;&amp;#39;
Simple dict but also support access as x.y style.
&amp;gt;&amp;gt;&amp;gt; d1 = Dict()
&amp;gt;&amp;gt;&amp;gt; d1[&amp;#39;x&amp;#39;] = 100
&amp;gt;&amp;gt;&amp;gt; d1.x
100
&amp;gt;&amp;gt;&amp;gt; d1.y = 200
&amp;gt;&amp;gt;&amp;gt; d1[&amp;#39;y&amp;#39;]
200
&amp;gt;&amp;gt;&amp;gt; d2 = Dict(a=1, b=2, c=&amp;#39;3&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; d2.c
&amp;#39;3&amp;#39;
&amp;gt;&amp;gt;&amp;gt; d2[&amp;#39;empty&amp;#39;]
Traceback (most recent call last):
...
KeyError: &amp;#39;empty&amp;#39;
&amp;gt;&amp;gt;&amp;gt; d2.empty
Traceback (most recent call last):
...
AttributeError: &amp;#39;Dict&amp;#39; object has no attribute &amp;#39;empty&amp;#39;
&amp;#39;&amp;#39;&amp;#39;
def __init__(self, **kw):
super(Dict, self).__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r&amp;#34;&amp;#39;Dict&amp;#39; object has no attribute &amp;#39;%s&amp;#39;&amp;#34; % key)
def __setattr__(self, key, value):
self[key] = value
if __name__==&amp;#39;__main__&amp;#39;:
import doctest
doctest.testmod()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;运行&lt;code&gt;python mydict2.py&lt;/code&gt;：&lt;/p&gt;</description></item><item><title>Python单元测试</title><link>/2016/06/02/python%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</link><pubDate>Thu, 02 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/02/python%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;如果你听说过“测试驱动开发”（TDD：Test-Driven Development），单元测试就不陌生。&lt;/p&gt;
&lt;p&gt;单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。&lt;/p&gt;
&lt;p&gt;比如对函数&lt;code&gt;abs()&lt;/code&gt;，我们可以编写出以下几个测试用例：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;输入正数，比如&lt;code&gt;1&lt;/code&gt;、&lt;code&gt;1.2&lt;/code&gt;、&lt;code&gt;0.99&lt;/code&gt;，期待返回值与输入相同；&lt;/li&gt;
&lt;li&gt;输入负数，比如&lt;code&gt;-1&lt;/code&gt;、&lt;code&gt;-1.2&lt;/code&gt;、&lt;code&gt;-0.99&lt;/code&gt;，期待返回值与输入相反；&lt;/li&gt;
&lt;li&gt;输入&lt;code&gt;0&lt;/code&gt;，期待返回&lt;code&gt;0&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;输入非数值类型，比如&lt;code&gt;None&lt;/code&gt;、&lt;code&gt;[]&lt;/code&gt;、&lt;code&gt;{}&lt;/code&gt;，期待抛出&lt;code&gt;TypeError&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;把上面的测试用例放到一个测试模块里，就是一个完整的单元测试。&lt;/p&gt;
&lt;p&gt;如果单元测试通过，说明我们测试的这个函数能够正常工作。如果单元测试不通过，要么函数有bug，要么测试条件输入不正确，总之，需要修复使单元测试能够通过。&lt;/p&gt;
&lt;p&gt;单元测试通过后有什么意义呢？如果我们对&lt;code&gt;abs()&lt;/code&gt;函数代码做了修改，只需要再跑一遍单元测试，如果通过，说明我们的修改不会对&lt;code&gt;abs()&lt;/code&gt;函数原有的行为造成影响，如果测试不通过，说明我们的修改与原有行为不一致，要么修改代码，要么修改测试。&lt;/p&gt;
&lt;p&gt;这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候，可以极大程度地保证该模块行为仍然是正确的。&lt;/p&gt;
&lt;p&gt;我们来编写一个&lt;code&gt;Dict&lt;/code&gt;类，这个类的行为和&lt;code&gt;dict&lt;/code&gt;一致，但是可以通过属性来访问，用起来就像下面这样：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; d = Dict(a=1, b=2)
&amp;gt;&amp;gt;&amp;gt; d[&amp;#39;a&amp;#39;]
1
&amp;gt;&amp;gt;&amp;gt; d.a
1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;mydict.py&lt;/code&gt;代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dict&lt;/span&gt;(dict):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self, &lt;span style="color:#f92672"&gt;**&lt;/span&gt;kw):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; super()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(&lt;span style="color:#f92672"&gt;**&lt;/span&gt;kw)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__getattr__&lt;/span&gt;(self, key):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; self[key]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;KeyError&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;raise&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AttributeError&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#39;Dict&amp;#39; object has no attribute &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; key)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__setattr__&lt;/span&gt;(self, key, value):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self[key] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; value
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为了编写单元测试，我们需要引入Python自带的&lt;code&gt;unittest&lt;/code&gt;模块，编写&lt;code&gt;mydict_test.py&lt;/code&gt;如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; unittest
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; mydict &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Dict
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestDict&lt;/span&gt;(unittest&lt;span style="color:#f92672"&gt;.&lt;/span&gt;TestCase):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_init&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; d &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Dict(a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assertEqual(d&lt;span style="color:#f92672"&gt;.&lt;/span&gt;a, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assertEqual(d&lt;span style="color:#f92672"&gt;.&lt;/span&gt;b, &lt;span style="color:#e6db74"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assertTrue(isinstance(d, dict))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_key&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; d &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Dict()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; d[&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assertEqual(d&lt;span style="color:#f92672"&gt;.&lt;/span&gt;key, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_attr&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; d &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Dict()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; d&lt;span style="color:#f92672"&gt;.&lt;/span&gt;key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assertTrue(&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;in&lt;/span&gt; d)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assertEqual(d[&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;], &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_keyerror&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; d &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Dict()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assertRaises(&lt;span style="color:#a6e22e"&gt;KeyError&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; d[&lt;span style="color:#e6db74"&gt;&amp;#39;empty&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_attrerror&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; d &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Dict()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assertRaises(&lt;span style="color:#a6e22e"&gt;AttributeError&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; d&lt;span style="color:#f92672"&gt;.&lt;/span&gt;empty
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编写单元测试时，我们需要编写一个测试类，从&lt;code&gt;unittest.TestCase&lt;/code&gt;继承。&lt;/p&gt;</description></item><item><title>Python调试</title><link>/2016/06/01/python%E8%B0%83%E8%AF%95/</link><pubDate>Wed, 01 Jun 2016 00:00:00 +0000</pubDate><guid>/2016/06/01/python%E8%B0%83%E8%AF%95/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="print方法"&gt;print方法&lt;/h3&gt;
&lt;p&gt;程序能一次写完并正常运行的概率很小，基本不超过1%。总会有各种各样的bug需要修正。有的bug很简单，看看错误信息就知道，有的bug很复杂，我们需要知道出错时，哪些变量的值是正确的，哪些变量的值是错误的，因此，需要一整套调试程序的手段来修复bug。&lt;/p&gt;
&lt;p&gt;第一种方法简单直接粗暴有效，就是用&lt;code&gt;print()&lt;/code&gt;把可能有问题的变量打印出来看看：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;(s):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; int(s)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;gt;&amp;gt;&amp;gt; n = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; n)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; foo(&lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;main()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行后在输出中查找打印的变量值：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ python err.py
&amp;gt;&amp;gt;&amp;gt; n = 0
Traceback (most recent call last):
...
ZeroDivisionError: integer division or modulo by zero
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;用&lt;code&gt;print()&lt;/code&gt;最大的坏处是将来还得删掉它，想想程序里到处都是&lt;code&gt;print()&lt;/code&gt;，运行结果也会包含很多垃圾信息。所以，我们又有第二种方法。&lt;/p&gt;
&lt;h3 id="断言"&gt;断言&lt;/h3&gt;
&lt;p&gt;凡是用&lt;code&gt;print()&lt;/code&gt;来辅助查看的地方，都可以用断言（assert）来替代：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;(s):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; int(s)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;assert&lt;/span&gt; n &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;n is zero!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; foo(&lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;assert&lt;/code&gt;的意思是，表达式&lt;code&gt;n != 0&lt;/code&gt;应该是&lt;code&gt;True&lt;/code&gt;，否则，根据程序运行的逻辑，后面的代码肯定会出错。&lt;/p&gt;
&lt;p&gt;如果断言失败，&lt;code&gt;assert&lt;/code&gt;语句本身就会抛出&lt;code&gt;AssertionError&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ python err.py
Traceback (most recent call last):
...
AssertionError: n is zero!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;程序中如果到处充斥着&lt;code&gt;assert&lt;/code&gt;，和&lt;code&gt;print()&lt;/code&gt;相比也好不到哪去。不过，启动Python解释器时可以用&lt;code&gt;-O&lt;/code&gt;参数来关闭&lt;code&gt;assert&lt;/code&gt;：&lt;/p&gt;</description></item><item><title>Python错误处理</title><link>/2016/05/31/python%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86/</link><pubDate>Tue, 31 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/31/python%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;在程序运行过程中，总会遇到各种各样的错误。&lt;/p&gt;
&lt;p&gt;有的错误是程序编写有问题造成的，比如本来应该输出整数结果输出了字符串，这种错误我们通常称之为bug，bug是必须修复的。&lt;/p&gt;
&lt;p&gt;有的错误是用户输入造成的，比如让用户输入email地址，结果得到一个空字符串，这种错误可以通过检查用户输入来做相应的处理。&lt;/p&gt;
&lt;p&gt;还有一类错误是完全无法在程序运行过程中预测的，比如写入文件的时候，磁盘满了，写不进去了，或者从网络抓取数据，网络突然断掉了。这类错误也称为异常，在程序中通常是必须处理的，否则，程序会因为各种问题终止并退出。&lt;/p&gt;
&lt;p&gt;Python内置了一套异常处理机制，来帮助我们进行错误处理。&lt;/p&gt;
&lt;p&gt;在程序运行的过程中，如果发生了错误，可以事先约定返回一个错误代码，这样，就可以知道是否有错，以及出错的原因。在操作系统提供的调用中，返回错误码非常常见。比如打开文件的函数&lt;code&gt;open()&lt;/code&gt;，成功时返回文件描述符（就是一个整数），出错时返回&lt;code&gt;-1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;用错误码来表示是否出错十分不便，因为函数本身应该返回的正常结果和错误码混在一起，造成调用者必须用大量的代码来判断是否出错：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; some_function()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; r&lt;span style="color:#f92672"&gt;==&lt;/span&gt;(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# do something&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; r
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; foo()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; r&lt;span style="color:#f92672"&gt;==&lt;/span&gt;(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;Error&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一旦出错，还要一级一级上报，直到某个函数可以处理该错误（比如，给用户输出一个错误信息）。&lt;/p&gt;
&lt;p&gt;所以高级语言通常都内置了一套&lt;code&gt;try...except...finally...&lt;/code&gt;的错误处理机制，Python也不例外。&lt;/p&gt;
&lt;h3 id="try命令"&gt;try命令&lt;/h3&gt;
&lt;p&gt;让我们用一个例子来看看&lt;code&gt;try&lt;/code&gt;的机制：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;try...&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;result:&amp;#39;&lt;/span&gt;, r)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZeroDivisionError&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;except:&amp;#39;&lt;/span&gt;, e)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;finally&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;finally...&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#39;END&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当我们认为某些代码可能会出错时，就可以用&lt;code&gt;try&lt;/code&gt;来运行这段代码，如果执行出错，则后续代码不会继续执行，而是直接跳转至错误处理代码，即&lt;code&gt;except&lt;/code&gt;语句块，执行完&lt;code&gt;except&lt;/code&gt;后，如果有&lt;code&gt;finally&lt;/code&gt;语句块，则执行&lt;code&gt;finally&lt;/code&gt;语句块，至此，执行完毕。&lt;/p&gt;
&lt;p&gt;上面的代码在计算&lt;code&gt;10 / 0&lt;/code&gt;时会产生一个除法运算错误：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;try...
except: division by zero
finally...
END
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从输出可以看到，当错误发生时，后续语句&lt;code&gt;print('result:', r)&lt;/code&gt;不会被执行，&lt;code&gt;except&lt;/code&gt;由于捕获到&lt;code&gt;ZeroDivisionError&lt;/code&gt;，因此被执行。最后，&lt;code&gt;finally&lt;/code&gt;语句被执行。然后，程序继续按照流程往下走。&lt;/p&gt;
&lt;p&gt;如果把除数&lt;code&gt;0&lt;/code&gt;改成&lt;code&gt;2&lt;/code&gt;，则执行结果如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;try...
result: 5
finally...
END
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由于没有错误发生，所以&lt;code&gt;except&lt;/code&gt;语句块不会被执行，但是&lt;code&gt;finally&lt;/code&gt;如果有，则一定会被执行（可以没有&lt;code&gt;finally&lt;/code&gt;语句）。&lt;/p&gt;</description></item><item><title>Python元类</title><link>/2016/05/27/python%E5%85%83%E7%B1%BB/</link><pubDate>Fri, 27 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/27/python%E5%85%83%E7%B1%BB/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="type"&gt;type()&lt;/h3&gt;
&lt;p&gt;动态语言和静态语言最大的不同，就是函数和类的定义，不是编译时定义的，而是运行时动态创建的。&lt;/p&gt;
&lt;p&gt;比方说我们要定义一个&lt;code&gt;Hello&lt;/code&gt;的class，就写一个&lt;code&gt;hello.py&lt;/code&gt;模块：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Hello(object):
def hello(self, name=&amp;#39;world&amp;#39;):
print(&amp;#39;Hello, %s.&amp;#39; % name)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当Python解释器载入&lt;code&gt;hello&lt;/code&gt;模块时，就会依次执行该模块的所有语句，执行结果就是动态创建出一个&lt;code&gt;Hello&lt;/code&gt;的class对象，测试如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from hello import Hello
&amp;gt;&amp;gt;&amp;gt; h = Hello()
&amp;gt;&amp;gt;&amp;gt; h.hello()
Hello, world.
&amp;gt;&amp;gt;&amp;gt; print(type(Hello))
&amp;lt;class &amp;#39;type&amp;#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; print(type(h))
&amp;lt;class &amp;#39;hello.Hello&amp;#39;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;type()&lt;/code&gt;函数可以查看一个类型或变量的类型，&lt;code&gt;Hello&lt;/code&gt;是一个class，它的类型就是&lt;code&gt;type&lt;/code&gt;，而&lt;code&gt;h&lt;/code&gt;是一个实例，它的类型就是class &lt;code&gt;Hello&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;我们说class的定义是运行时动态创建的，而创建class的方法就是使用&lt;code&gt;type()&lt;/code&gt;函数。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;type()&lt;/code&gt;函数既可以返回一个对象的类型，又可以创建出新的类型，比如，我们可以通过&lt;code&gt;type()&lt;/code&gt;函数创建出&lt;code&gt;Hello&lt;/code&gt;类，而无需通过&lt;code&gt;class Hello(object)...&lt;/code&gt;的定义：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; def fn(self, name=&amp;#39;world&amp;#39;): # 先定义函数
... print(&amp;#39;Hello, %s.&amp;#39; % name)
...
&amp;gt;&amp;gt;&amp;gt; Hello = type(&amp;#39;Hello&amp;#39;, (object,), dict(hello=fn)) # 创建Hello class
&amp;gt;&amp;gt;&amp;gt; h = Hello()
&amp;gt;&amp;gt;&amp;gt; h.hello()
Hello, world.
&amp;gt;&amp;gt;&amp;gt; print(type(Hello))
&amp;lt;class &amp;#39;type&amp;#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; print(type(h))
&amp;lt;class &amp;#39;__main__.Hello&amp;#39;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;要创建一个class对象，&lt;code&gt;type()&lt;/code&gt;函数依次传入3个参数：&lt;/p&gt;</description></item><item><title>Python枚举类</title><link>/2016/05/26/python%E6%9E%9A%E4%B8%BE%E7%B1%BB/</link><pubDate>Thu, 26 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/26/python%E6%9E%9A%E4%B8%BE%E7%B1%BB/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;当我们需要定义常量时，一个办法是用大写变量通过整数来定义，例如月份：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;JAN = 1
FEB = 2
MAR = 3
...
NOV = 11
DEC = 12
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;好处是简单，缺点是类型是&lt;code&gt;int&lt;/code&gt;，并且仍然是变量。&lt;/p&gt;
&lt;p&gt;更好的方法是为这样的枚举类型定义一个class类型，然后，每个常量都是class的一个唯一实例。Python提供了&lt;code&gt;Enum&lt;/code&gt;类来实现这个功能：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;from enum import Enum
Month = Enum(&amp;#39;Month&amp;#39;, (&amp;#39;Jan&amp;#39;, &amp;#39;Feb&amp;#39;, &amp;#39;Mar&amp;#39;, &amp;#39;Apr&amp;#39;, &amp;#39;May&amp;#39;, &amp;#39;Jun&amp;#39;, &amp;#39;Jul&amp;#39;, &amp;#39;Aug&amp;#39;, &amp;#39;Sep&amp;#39;, &amp;#39;Oct&amp;#39;, &amp;#39;Nov&amp;#39;, &amp;#39;Dec&amp;#39;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这样我们就获得了&lt;code&gt;Month&lt;/code&gt;类型的枚举类，可以直接使用&lt;code&gt;Month.Jan&lt;/code&gt;来引用一个常量，或者枚举它的所有成员：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;for name, member in Month.__members__.items():
print(name, &amp;#39;=&amp;gt;&amp;#39;, member, &amp;#39;,&amp;#39;, member.value)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;value&lt;/code&gt;属性则是自动赋给成员的&lt;code&gt;int&lt;/code&gt;常量，默认从&lt;code&gt;1&lt;/code&gt;开始计数。&lt;/p&gt;
&lt;p&gt;如果需要更精确地控制枚举类型，可以从&lt;code&gt;Enum&lt;/code&gt;派生出自定义类：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;@unique&lt;/code&gt;装饰器可以帮助我们检查保证没有重复值。&lt;/p&gt;</description></item><item><title>Python定制类</title><link>/2016/05/24/python%E5%AE%9A%E5%88%B6%E7%B1%BB/</link><pubDate>Tue, 24 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/24/python%E5%AE%9A%E5%88%B6%E7%B1%BB/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;看到类似&lt;code&gt;__slots__&lt;/code&gt;这种形如&lt;code&gt;__xxx__&lt;/code&gt;的变量或者函数名就要注意，这些在Python中是有特殊用途的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;__slots__&lt;/code&gt;我们已经知道怎么用了，&lt;code&gt;__len__()&lt;/code&gt;方法我们也知道是为了能让class作用于&lt;code&gt;len()&lt;/code&gt;函数。&lt;/p&gt;
&lt;p&gt;除此之外，Python的class中还有许多这样有特殊用途的函数，可以帮助我们定制类。&lt;/p&gt;
&lt;h3 id="__str__-__repr__"&gt;&lt;code&gt;__str__&lt;/code&gt;, &lt;code&gt;__repr__&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;我们先定义一个&lt;code&gt;Student&lt;/code&gt;类，打印一个实例：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; class Student(object):
... def __init__(self, name):
... self.name = name
...
&amp;gt;&amp;gt;&amp;gt; print(Student(&amp;#39;Michael&amp;#39;))
&amp;lt;__main__.Student object at 0x109afb190&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;打印出一堆&lt;code&gt;&amp;lt;__main__.Student object at 0x109afb190&amp;gt;&lt;/code&gt;，不好看。&lt;/p&gt;
&lt;p&gt;怎么才能打印得好看呢？只需要定义好&lt;code&gt;__str__()&lt;/code&gt;方法，返回一个好看的字符串就可以了：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; class Student(object):
... def __init__(self, name):
... self.name = name
... def __str__(self):
... return &amp;#39;Student object (name: %s)&amp;#39; % self.name
...
&amp;gt;&amp;gt;&amp;gt; print(Student(&amp;#39;Michael&amp;#39;))
Student object (name: Michael)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这样打印出来的实例，不但好看，而且容易看出实例内部重要的数据。&lt;/p&gt;
&lt;p&gt;但是细心的朋友会发现直接敲变量不用&lt;code&gt;print&lt;/code&gt;，打印出来的实例还是不好看：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; s = Student(&amp;#39;Michael&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; s
&amp;lt;__main__.Student object at 0x109afb310&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是因为直接显示变量调用的不是&lt;code&gt;__str__()&lt;/code&gt;，而是&lt;code&gt;__repr__()&lt;/code&gt;，两者的区别是&lt;code&gt;__str__()&lt;/code&gt;返回用户看到的字符串，而&lt;code&gt;__repr__()&lt;/code&gt;返回程序开发者看到的字符串，也就是说，&lt;code&gt;__repr__()&lt;/code&gt;是为调试服务的。&lt;/p&gt;</description></item><item><title>Python多重继承</title><link>/2016/05/23/python%E5%A4%9A%E9%87%8D%E7%BB%A7%E6%89%BF/</link><pubDate>Mon, 23 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/23/python%E5%A4%9A%E9%87%8D%E7%BB%A7%E6%89%BF/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="多重继承"&gt;多重继承&lt;/h2&gt;
&lt;p&gt;一个子类同时获得多个父类的所有功能。&lt;/p&gt;
&lt;p&gt;继承是面向对象编程的一个重要的方式，因为通过继承，子类就可以扩展父类的功能。&lt;/p&gt;
&lt;p&gt;回忆一下&lt;code&gt;Animal&lt;/code&gt;类层次的设计，假设我们要实现以下4种动物：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dog - 狗狗；&lt;/li&gt;
&lt;li&gt;Bat - 蝙蝠；&lt;/li&gt;
&lt;li&gt;Parrot - 鹦鹉；&lt;/li&gt;
&lt;li&gt;Ostrich - 鸵鸟。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果按照哺乳动物和鸟类归类，我们可以设计出这样的类的层次：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; ┌───────────────┐
│ Animal │
└───────────────┘
│
┌────────────┴────────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Mammal │ │ Bird │
└─────────────┘ └─────────────┘
│ │
┌─────┴──────┐ ┌─────┴──────┐
│ │ │ │
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Dog │ │ Bat │ │ Parrot │ │ Ostrich │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是如果按照“能跑”和“能飞”来归类，我们就应该设计出这样的类的层次：&lt;/p&gt;</description></item><item><title>Python内置@property装饰器实现方法转属性</title><link>/2016/05/20/python%E5%86%85%E7%BD%AE@property%E8%A3%85%E9%A5%B0%E5%99%A8%E5%AE%9E%E7%8E%B0%E6%96%B9%E6%B3%95%E8%BD%AC%E5%B1%9E%E6%80%A7/</link><pubDate>Fri, 20 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/20/python%E5%86%85%E7%BD%AE@property%E8%A3%85%E9%A5%B0%E5%99%A8%E5%AE%9E%E7%8E%B0%E6%96%B9%E6%B3%95%E8%BD%AC%E5%B1%9E%E6%80%A7/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;在绑定属性时，如果我们直接把属性暴露出去，虽然写起来很简单，但是，没办法检查参数，导致可以把成绩随便改：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;s = Student()
s.score = 9999
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这显然不合逻辑。为了限制score的范围，可以通过一个&lt;code&gt;set_score()&lt;/code&gt;方法来设置成绩，再通过一个&lt;code&gt;get_score()&lt;/code&gt;来获取成绩，这样，在&lt;code&gt;set_score()&lt;/code&gt;方法里，就可以检查参数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError(&amp;#39;score must be an integer!&amp;#39;)
if value &amp;lt; 0 or value &amp;gt; 100:
raise ValueError(&amp;#39;score must between 0 ~ 100!&amp;#39;)
self._score = value
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在，对任意的Student实例进行操作，就不能随心所欲地设置score了：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; s = Student()
&amp;gt;&amp;gt;&amp;gt; s.set_score(60) # ok!
&amp;gt;&amp;gt;&amp;gt; s.get_score()
60
&amp;gt;&amp;gt;&amp;gt; s.set_score(9999)
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是，上面的调用方法又略显复杂，没有直接用属性这么直接简单。&lt;/p&gt;</description></item><item><title>Python变量__slots__属性限制</title><link>/2016/05/19/python%E5%8F%98%E9%87%8F__slots__%E5%B1%9E%E6%80%A7%E9%99%90%E5%88%B6/</link><pubDate>Thu, 19 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/19/python%E5%8F%98%E9%87%8F__slots__%E5%B1%9E%E6%80%A7%E9%99%90%E5%88%B6/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;正常情况下，当我们定义了一个class，创建了一个class的实例后，我们可以给该实例绑定任何属性和方法，这就是动态语言的灵活性。先定义class：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Student(object):
pass
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后，尝试给实例绑定一个属性：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; s = Student()
&amp;gt;&amp;gt;&amp;gt; s.name = &amp;#39;Michael&amp;#39; # 动态给实例绑定一个属性
&amp;gt;&amp;gt;&amp;gt; print(s.name)
Michael
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;还可以尝试给实例绑定一个方法：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; def set_age(self, age): # 定义一个函数作为实例方法
... self.age = age
...
&amp;gt;&amp;gt;&amp;gt; from types import MethodType
&amp;gt;&amp;gt;&amp;gt; s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
&amp;gt;&amp;gt;&amp;gt; s.set_age(25) # 调用实例方法
&amp;gt;&amp;gt;&amp;gt; s.age # 测试结果
25
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是，给一个实例绑定的方法，对另一个实例是不起作用的：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; s2 = Student() # 创建新的实例
&amp;gt;&amp;gt;&amp;gt; s2.set_age(25) # 尝试调用方法
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
AttributeError: &amp;#39;Student&amp;#39; object has no attribute &amp;#39;set_age&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;为了给所有实例都绑定方法，可以给class绑定方法：&lt;/p&gt;</description></item><item><title>Python实例属性和类属性</title><link>/2016/05/18/python%E5%AE%9E%E4%BE%8B%E5%B1%9E%E6%80%A7%E5%92%8C%E7%B1%BB%E5%B1%9E%E6%80%A7/</link><pubDate>Wed, 18 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/18/python%E5%AE%9E%E4%BE%8B%E5%B1%9E%E6%80%A7%E5%92%8C%E7%B1%BB%E5%B1%9E%E6%80%A7/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;由于Python是动态语言，根据类创建的实例可以任意绑定属性。&lt;/p&gt;
&lt;p&gt;给实例绑定属性的方法是通过实例变量，或者通过&lt;code&gt;self&lt;/code&gt;变量：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Student&lt;/span&gt;(object):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self, name):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Student(&lt;span style="color:#e6db74"&gt;&amp;#39;Bob&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s&lt;span style="color:#f92672"&gt;.&lt;/span&gt;score &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;90&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是，如果&lt;code&gt;Student&lt;/code&gt;类本身需要绑定一个属性呢？可以直接在class中定义属性，这种属性是类属性，归&lt;code&gt;Student&lt;/code&gt;类所有：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Student&lt;/span&gt;(object):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Student&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当我们定义了一个类属性后，这个属性虽然归类所有，但类的所有实例都可以访问到。来测试一下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; class Student(object):
... name = &amp;#39;Student&amp;#39;
...
&amp;gt;&amp;gt;&amp;gt; s = Student() # 创建实例s
&amp;gt;&amp;gt;&amp;gt; print(s.name) # 打印name属性，因为实例并没有name属性，所以会继续查找class的name属性
Student
&amp;gt;&amp;gt;&amp;gt; print(Student.name) # 打印类的name属性
Student
&amp;gt;&amp;gt;&amp;gt; s.name = &amp;#39;Michael&amp;#39; # 给实例绑定name属性
&amp;gt;&amp;gt;&amp;gt; print(s.name) # 由于实例属性优先级比类属性高，因此，它会屏蔽掉类的name属性
Michael
&amp;gt;&amp;gt;&amp;gt; print(Student.name) # 但是类属性并未消失，用Student.name仍然可以访问
Student
&amp;gt;&amp;gt;&amp;gt; del s.name # 如果删除实例的name属性
&amp;gt;&amp;gt;&amp;gt; print(s.name) # 再次调用s.name，由于实例的name属性没有找到，类的name属性就显示出来了
Student
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从上面的例子可以看出，在编写程序的时候，千万不要对实例属性和类属性使用相同的名字，因为相同名称的实例属性将屏蔽掉类属性，但是当你删除实例属性后，再使用相同的名称，访问到的将是类属性。&lt;/p&gt;</description></item><item><title>Python</title><link>/2016/05/17/python/</link><pubDate>Tue, 17 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/17/python/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="路径和名字的获取方式"&gt;路径和名字的获取方式&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import os,sys
if __name__ == &amp;#39;__main__&amp;#39;:
filename = __file__
print(&amp;#34;filename : &amp;#34;, filename)
filepath = os.path.abspath(filename)
print(&amp;#34;filepath : &amp;#34;, filepath)
dirname = os.path.dirname(__file__)
print(&amp;#34;dirname : &amp;#34;, dirname)
dirpath = os.path.abspath(dirname)
print(&amp;#34;dirpath : &amp;#34;, dirpath)
输出：
filename : C:/Users/dell/Desktop/git/SimpleStorageServer-Windows10/test.py
filepath : C:\Users\dell\Desktop\git\SimpleStorageServer-Windows10\test.py
dirname : C:/Users/dell/Desktop/git/SimpleStorageServer-Windows10
dirpath : C:\Users\dell\Desktop\git\SimpleStorageServer-Windows10
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="oswalk的用法"&gt;os.walk的用法&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;os.walk(directorypath, topdown=True, onerror=None, followlinks=False)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这里directorypath 必须是一个目录的路径，如果是一个文件的路径，则不会得到任何东西&lt;/p&gt;
&lt;p&gt;第一个为起始路径，第二个为起始路径下的文件夹，第三个是起始路径下的文件。
dirpath 是一个string，代表目录的路径，
dirnames 是一个list，包含了dirpath下所有子目录的名字。
filenames 是一个list，包含了非目录文件的名字。
这些名字不包含路径信息，如果需要得到全路径，需要使用os.path.join(dirpath, name).通过for循环自动完成递归枚举&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import os,sys
if __name__ == &amp;#39;__main__&amp;#39;:
filename = __file__
print(&amp;#34;filename : &amp;#34;, filename)
filepath = os.path.abspath(filename)
print(&amp;#34;filepath : &amp;#34;, filepath)
dirname = os.path.dirname(__file__)
print(&amp;#34;dirname : &amp;#34;, dirname)
dirpath = os.path.abspath(dirname)
print(&amp;#34;dirpath : &amp;#34;, dirpath)
# for dirpaths, dirnames, filenames in os.walk(filepath):
# print(dirpaths, dirnames, filenames)
# for dirpaths, dirnames, filenames in os.walk(dirpath, topdown=False):
for dirpaths, dirnames, filenames in os.walk(dirpath):
print(dirpaths, dirnames, filenames)
# print(dirpaths, filenames)
# for i in filenames:
# print(os.path.join(dirpaths,i))
# for j in dirnames:
# print(os.path.join(dirpaths, j))
# pass
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出:&lt;/p&gt;</description></item><item><title>Python获取对象信息</title><link>/2016/05/17/python%E8%8E%B7%E5%8F%96%E5%AF%B9%E8%B1%A1%E4%BF%A1%E6%81%AF/</link><pubDate>Tue, 17 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/17/python%E8%8E%B7%E5%8F%96%E5%AF%B9%E8%B1%A1%E4%BF%A1%E6%81%AF/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;当我们拿到一个对象的引用时，如何知道这个对象是什么类型、有哪些方法呢？&lt;/p&gt;
&lt;h3 id="使用type"&gt;使用type()&lt;/h3&gt;
&lt;p&gt;首先，我们来判断对象类型，使用&lt;code&gt;type()&lt;/code&gt;函数：&lt;/p&gt;
&lt;p&gt;基本类型都可以用&lt;code&gt;type()&lt;/code&gt;判断：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; type(123)
&amp;lt;class &amp;#39;int&amp;#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; type(&amp;#39;str&amp;#39;)
&amp;lt;class &amp;#39;str&amp;#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; type(None)
&amp;lt;type(None) &amp;#39;NoneType&amp;#39;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果一个变量指向函数或者类，也可以用&lt;code&gt;type()&lt;/code&gt;判断：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; type(abs)
&amp;lt;class &amp;#39;builtin_function_or_method&amp;#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; type(a)
&amp;lt;class &amp;#39;__main__.Animal&amp;#39;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是&lt;code&gt;type()&lt;/code&gt;函数返回的是什么类型呢？它返回对应的Class类型。如果我们要在&lt;code&gt;if&lt;/code&gt;语句中判断，就需要比较两个变量的type类型是否相同：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; type(123)==type(456)
True
&amp;gt;&amp;gt;&amp;gt; type(123)==int
True
&amp;gt;&amp;gt;&amp;gt; type(&amp;#39;abc&amp;#39;)==type(&amp;#39;123&amp;#39;)
True
&amp;gt;&amp;gt;&amp;gt; type(&amp;#39;abc&amp;#39;)==str
True
&amp;gt;&amp;gt;&amp;gt; type(&amp;#39;abc&amp;#39;)==type(123)
False
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="types"&gt;types&lt;/h3&gt;
&lt;p&gt;判断基本数据类型可以直接写&lt;code&gt;int&lt;/code&gt;，&lt;code&gt;str&lt;/code&gt;等，但如果要判断一个对象是否是函数怎么办？可以使用&lt;code&gt;types&lt;/code&gt;模块中定义的常量：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import types
&amp;gt;&amp;gt;&amp;gt; def fn():
... pass
...
&amp;gt;&amp;gt;&amp;gt; type(fn)==types.FunctionType
True
&amp;gt;&amp;gt;&amp;gt; type(abs)==types.BuiltinFunctionType
True
&amp;gt;&amp;gt;&amp;gt; type(lambda x: x)==types.LambdaType
True
&amp;gt;&amp;gt;&amp;gt; type((x for x in range(10)))==types.GeneratorType
True
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="使用isinstance"&gt;使用isinstance()&lt;/h3&gt;
&lt;p&gt;对于class的继承关系来说，使用&lt;code&gt;type()&lt;/code&gt;就很不方便。我们要判断class的类型，可以使用&lt;code&gt;isinstance()&lt;/code&gt;函数。&lt;/p&gt;</description></item><item><title>Python类的继承和多态</title><link>/2016/05/16/python%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF%E5%92%8C%E5%A4%9A%E6%80%81/</link><pubDate>Mon, 16 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/16/python%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF%E5%92%8C%E5%A4%9A%E6%80%81/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="继承"&gt;继承&lt;/h2&gt;
&lt;p&gt;在OOP程序设计中，当我们定义一个class的时候，可以从某个现有的class继承，新的class称为子类（Subclass），而被继承的class称为基类、父类或超类（Base class、Super class）。&lt;/p&gt;
&lt;p&gt;比如，我们已经编写了一个名为&lt;code&gt;Animal&lt;/code&gt;的class，有一个&lt;code&gt;run()&lt;/code&gt;方法可以直接打印：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Animal(object):
def run(self):
print(&amp;#39;Animal is running...&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当我们需要编写&lt;code&gt;Dog&lt;/code&gt;和&lt;code&gt;Cat&lt;/code&gt;类时，就可以直接从&lt;code&gt;Animal&lt;/code&gt;类继承：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Dog(Animal):
pass
class Cat(Animal):
pass
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对于&lt;code&gt;Dog&lt;/code&gt;来说，&lt;code&gt;Animal&lt;/code&gt;就是它的父类，对于&lt;code&gt;Animal&lt;/code&gt;来说，&lt;code&gt;Dog&lt;/code&gt;就是它的子类。&lt;code&gt;Cat&lt;/code&gt;和&lt;code&gt;Dog&lt;/code&gt;类似。&lt;/p&gt;
&lt;p&gt;继承有什么好处？最大的好处是子类获得了父类的全部功能。由于&lt;code&gt;Animial&lt;/code&gt;实现了&lt;code&gt;run()&lt;/code&gt;方法，因此，&lt;code&gt;Dog&lt;/code&gt;和&lt;code&gt;Cat&lt;/code&gt;作为它的子类，什么事也没干，就自动拥有了&lt;code&gt;run()&lt;/code&gt;方法：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;dog = Dog()
dog.run()
cat = Cat()
cat.run()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;运行结果如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Animal is running...
Animal is running...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当然，也可以对子类增加一些方法，比如Dog类：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Dog(Animal):
def run(self):
print(&amp;#39;Dog is running...&amp;#39;)
def eat(self):
print(&amp;#39;Eating meat...&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="多态"&gt;多态&lt;/h2&gt;
&lt;p&gt;继承的第二个好处需要我们对代码做一点改进。你看到了，无论是&lt;code&gt;Dog&lt;/code&gt;还是&lt;code&gt;Cat&lt;/code&gt;，它们&lt;code&gt;run()&lt;/code&gt;的时候，显示的都是&lt;code&gt;Animal is running...&lt;/code&gt;，符合逻辑的做法是分别显示&lt;code&gt;Dog is running...&lt;/code&gt;和&lt;code&gt;Cat is running...&lt;/code&gt;，因此，对&lt;code&gt;Dog&lt;/code&gt;和&lt;code&gt;Cat&lt;/code&gt;类改进如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Dog(Animal):
def run(self):
print(&amp;#39;Dog is running...&amp;#39;)
class Cat(Animal):
def run(self):
print(&amp;#39;Cat is running...&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;再次运行，结果如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Dog is running...
Cat is running...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当子类和父类都存在相同的&lt;code&gt;run()&lt;/code&gt;方法时，我们说，子类的&lt;code&gt;run()&lt;/code&gt;覆盖了父类的&lt;code&gt;run()&lt;/code&gt;，在代码运行的时候，总是会调用子类的&lt;code&gt;run()&lt;/code&gt;。这样，我们就获得了继承的另一个好处：多态。&lt;/p&gt;</description></item><item><title>Python类的访问限制</title><link>/2016/05/15/python%E7%B1%BB%E7%9A%84%E8%AE%BF%E9%97%AE%E9%99%90%E5%88%B6/</link><pubDate>Sun, 15 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/15/python%E7%B1%BB%E7%9A%84%E8%AE%BF%E9%97%AE%E9%99%90%E5%88%B6/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;在Class内部，可以有属性和方法，而外部代码可以通过直接调用实例变量的方法来操作数据，这样，就隐藏了内部的复杂逻辑。&lt;/p&gt;
&lt;p&gt;但是，从前面Student类的定义来看，外部代码还是可以自由地修改一个实例的&lt;code&gt;name&lt;/code&gt;、&lt;code&gt;score&lt;/code&gt;属性：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; bart = Student(&amp;#39;Bart Simpson&amp;#39;, 59)
&amp;gt;&amp;gt;&amp;gt; bart.score
59
&amp;gt;&amp;gt;&amp;gt; bart.score = 99
&amp;gt;&amp;gt;&amp;gt; bart.score
99
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果要让内部属性不被外部访问，可以把属性的名称前加上两个下划线&lt;code&gt;__&lt;/code&gt;，在Python中，实例的变量名如果以&lt;code&gt;__&lt;/code&gt;开头，就变成了一个私有变量（private），只有内部可以访问，外部不能访问，所以，我们把Student类改一改：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print(&amp;#39;%s: %s&amp;#39; % (self.__name, self.__score))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;改完后，对于外部代码来说，没什么变动，但是已经无法从外部访问&lt;code&gt;实例变量.__name&lt;/code&gt;和&lt;code&gt;实例变量.__score&lt;/code&gt;了：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; bart = Student(&amp;#39;Bart Simpson&amp;#39;, 59)
&amp;gt;&amp;gt;&amp;gt; bart.__name
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
AttributeError: &amp;#39;Student&amp;#39; object has no attribute &amp;#39;__name&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这样就确保了外部代码不能随意修改对象内部的状态，这样通过访问限制的保护，代码更加健壮。&lt;/p&gt;
&lt;p&gt;但是如果外部代码要获取name和score怎么办？可以给Student类增加&lt;code&gt;get_name&lt;/code&gt;和&lt;code&gt;get_score&lt;/code&gt;这样的方法：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果又要允许外部代码修改score怎么办？可以再给Student类增加&lt;code&gt;set_score&lt;/code&gt;方法：&lt;/p&gt;</description></item><item><title>Python类和实例</title><link>/2016/05/14/python%E7%B1%BB%E5%92%8C%E5%AE%9E%E4%BE%8B/</link><pubDate>Sat, 14 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/14/python%E7%B1%BB%E5%92%8C%E5%AE%9E%E4%BE%8B/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;面向对象最重要的概念就是类（Class）和实例（Instance），必须牢记类是抽象的模板，比如Student类，而实例是根据类创建出来的一个个具体的“对象”，每个对象都拥有相同的方法，但各自的数据可能不同。&lt;/p&gt;
&lt;p&gt;仍以Student类为例，在Python中，定义类是通过&lt;code&gt;class&lt;/code&gt;关键字：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Student(object):
pass
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;class&lt;/code&gt;后面紧接着是类名，即&lt;code&gt;Student&lt;/code&gt;，类名通常是大写开头的单词，紧接着是&lt;code&gt;(object)&lt;/code&gt;，表示该类是从哪个类继承下来的，继承的概念我们后面再讲，通常，如果没有合适的继承类，就使用&lt;code&gt;object&lt;/code&gt;类，这是所有类最终都会继承的类。&lt;/p&gt;
&lt;p&gt;定义好了&lt;code&gt;Student&lt;/code&gt;类，就可以根据&lt;code&gt;Student&lt;/code&gt;类创建出&lt;code&gt;Student&lt;/code&gt;的实例，创建实例是通过类名+()实现的：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; bart = Student()
&amp;gt;&amp;gt;&amp;gt; bart
&amp;lt;__main__.Student object at 0x10a67a590&amp;gt;
&amp;gt;&amp;gt;&amp;gt; Student
&amp;lt;class &amp;#39;__main__.Student&amp;#39;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以看到，变量&lt;code&gt;bart&lt;/code&gt;指向的就是一个&lt;code&gt;Student&lt;/code&gt;的实例，后面的&lt;code&gt;0x10a67a590&lt;/code&gt;是内存地址，每个object的地址都不一样，而&lt;code&gt;Student&lt;/code&gt;本身则是一个类。&lt;/p&gt;
&lt;p&gt;可以自由地给一个实例变量绑定属性，比如，给实例&lt;code&gt;bart&lt;/code&gt;绑定一个&lt;code&gt;name&lt;/code&gt;属性：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; bart.name = &amp;#39;Bart Simpson&amp;#39;
&amp;gt;&amp;gt;&amp;gt; bart.name
&amp;#39;Bart Simpson&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由于类可以起到模板的作用，因此，可以在创建实例的时候，把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的&lt;code&gt;__init__&lt;/code&gt;方法，在创建实例的时候，就把&lt;code&gt;name&lt;/code&gt;，&lt;code&gt;score&lt;/code&gt;等属性绑上去：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;注意：特殊方法&lt;code&gt;__init__&lt;/code&gt;前后分别有两个下划线！！！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;注意到&lt;code&gt;__init__&lt;/code&gt;方法的第一个参数永远是&lt;code&gt;self&lt;/code&gt;，表示创建的实例本身，因此，在&lt;code&gt;__init__&lt;/code&gt;方法内部，就可以把各种属性绑定到&lt;code&gt;self&lt;/code&gt;，因为&lt;code&gt;self&lt;/code&gt;就指向创建的实例本身。&lt;/p&gt;
&lt;p&gt;有了&lt;code&gt;__init__&lt;/code&gt;方法，在创建实例的时候，就不能传入空的参数了，必须传入与&lt;code&gt;__init__&lt;/code&gt;方法匹配的参数，但&lt;code&gt;self&lt;/code&gt;不需要传，Python解释器自己会把实例变量传进去：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; bart = Student(&amp;#39;Bart Simpson&amp;#39;, 59)
&amp;gt;&amp;gt;&amp;gt; bart.name
&amp;#39;Bart Simpson&amp;#39;
&amp;gt;&amp;gt;&amp;gt; bart.score
59
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;和普通的函数相比，在类中定义的函数只有一点不同，就是第一个参数永远是实例变量&lt;code&gt;self&lt;/code&gt;，并且，调用时，不用传递该参数。除此之外，类的方法和普通函数没有什么区别，所以，你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。&lt;/p&gt;
&lt;h3 id="数据封装"&gt;数据封装&lt;/h3&gt;
&lt;p&gt;面向对象编程的一个重要特点就是数据封装。在上面的&lt;code&gt;Student&lt;/code&gt;类中，每个实例就拥有各自的&lt;code&gt;name&lt;/code&gt;和&lt;code&gt;score&lt;/code&gt;这些数据。我们可以通过函数来访问这些数据，比如打印一个学生的成绩：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; def print_score(std):
... print(&amp;#39;%s: %s&amp;#39; % (std.name, std.score))
...
&amp;gt;&amp;gt;&amp;gt; print_score(bart)
Bart Simpson: 59
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是，既然&lt;code&gt;Student&lt;/code&gt;实例本身就拥有这些数据，要访问这些数据，就没有必要从外面的函数去访问，可以直接在&lt;code&gt;Student&lt;/code&gt;类的内部定义访问数据的函数，这样，就把“数据”给封装起来了。这些封装数据的函数是和&lt;code&gt;Student&lt;/code&gt;类本身是关联起来的，我们称之为类的方法：&lt;/p&gt;</description></item><item><title>Python面向对象初印象</title><link>/2016/05/14/python%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E5%88%9D%E5%8D%B0%E8%B1%A1/</link><pubDate>Sat, 14 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/14/python%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E5%88%9D%E5%8D%B0%E8%B1%A1/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;面向对象编程——Object Oriented Programming，简称OOP，是一种程序设计思想。OOP把对象作为程序的基本单元，一个对象包含了数据和操作数据的函数。&lt;/p&gt;
&lt;p&gt;面向过程的程序设计把计算机程序视为一系列的命令集合，即一组函数的顺序执行。为了简化程序设计，面向过程把函数继续切分为子函数，即把大块函数通过切割成小块函数来降低系统的复杂度。&lt;/p&gt;
&lt;p&gt;而面向对象的程序设计把计算机程序视为一组对象的集合，而每个对象都可以接收其他对象发过来的消息，并处理这些消息，计算机程序的执行就是一系列消息在各个对象之间传递。&lt;/p&gt;
&lt;p&gt;在Python中，所有数据类型都可以视为对象，当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类（Class）的概念。&lt;/p&gt;
&lt;p&gt;我们以一个例子来说明面向过程和面向对象在程序流程上的不同之处。&lt;/p&gt;
&lt;p&gt;假设我们要处理学生的成绩表，为了表示一个学生的成绩，面向过程的程序可以用一个dict表示：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;std1 = { &amp;#39;name&amp;#39;: &amp;#39;Michael&amp;#39;, &amp;#39;score&amp;#39;: 98 }
std2 = { &amp;#39;name&amp;#39;: &amp;#39;Bob&amp;#39;, &amp;#39;score&amp;#39;: 81 }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;而处理学生成绩可以通过函数实现，比如打印学生的成绩：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def print_score(std):
print(&amp;#39;%s: %s&amp;#39; % (std[&amp;#39;name&amp;#39;], std[&amp;#39;score&amp;#39;]))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果采用面向对象的程序设计思想，我们首选思考的不是程序的执行流程，而是&lt;code&gt;Student&lt;/code&gt;这种数据类型应该被视为一个对象，这个对象拥有&lt;code&gt;name&lt;/code&gt;和&lt;code&gt;score&lt;/code&gt;这两个属性（Property）。如果要打印一个学生的成绩，首先必须创建出这个学生对应的对象，然后，给对象发一个&lt;code&gt;print_score&lt;/code&gt;消息，让对象自己把自己的数据打印出来。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print(&amp;#39;%s: %s&amp;#39; % (self.name, self.score))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;给对象发消息实际上就是调用对象对应的关联函数，我们称之为对象的方法（Method）。面向对象的程序写出来就像这样：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;bart = Student(&amp;#39;Bart Simpson&amp;#39;, 59)
lisa = Student(&amp;#39;Lisa Simpson&amp;#39;, 87)
bart.print_score()
lisa.print_score()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;面向对象的设计思想是从自然界中来的，因为在自然界中，类（Class）和实例（Instance）的概念是很自然的。Class是一种抽象概念，比如我们定义的Class——Student，是指学生这个概念，而实例（Instance）则是一个个具体的Student，比如，Bart Simpson和Lisa Simpson是两个具体的Student。&lt;/p&gt;
&lt;p&gt;所以，面向对象的设计思想是抽象出Class，根据Class创建Instance。&lt;/p&gt;
&lt;p&gt;面向对象的抽象程度又比函数要高，因为一个Class既包含数据，又包含操作数据的方法。&lt;/p&gt;</description></item><item><title>Python偏函数</title><link>/2016/05/11/python%E5%81%8F%E5%87%BD%E6%95%B0/</link><pubDate>Wed, 11 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/11/python%E5%81%8F%E5%87%BD%E6%95%B0/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="标准文件模板"&gt;标准文件模板&lt;/h2&gt;
&lt;p&gt;Python本身就内置了很多非常有用的模块，只要安装完毕，这些模块就可以立刻使用。&lt;/p&gt;
&lt;p&gt;我们以内建的&lt;code&gt;sys&lt;/code&gt;模块为例，编写一个&lt;code&gt;hello&lt;/code&gt;的模块：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#!/usr/bin/env python3
# -*- coding: utf-8 -*-
&amp;#39; a test module &amp;#39;
__author__ = &amp;#39;superman hooby&amp;#39;
import sys
def test():
args = sys.argv
if len(args)==1:
print(&amp;#39;Hello, world!&amp;#39;)
elif len(args)==2:
print(&amp;#39;Hello, %s!&amp;#39; % args[1])
else:
print(&amp;#39;Too many arguments!&amp;#39;)
if __name__==&amp;#39;__main__&amp;#39;:
test()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;第1行和第2行是标准注释，第1行注释可以让这个&lt;code&gt;hello.py&lt;/code&gt;文件直接在Unix/Linux/Mac上运行，第2行注释表示.py文件本身使用标准UTF-8编码；&lt;/p&gt;
&lt;p&gt;第4行是一个字符串，表示模块的文档注释，任何模块代码的第一个字符串都被视为模块的文档注释；&lt;/p&gt;
&lt;p&gt;第6行使用&lt;code&gt;__author__&lt;/code&gt;变量把作者写进去，这样当你公开源代码后别人就可以瞻仰你的大名；&lt;/p&gt;
&lt;p&gt;以上就是Python模块的标准文件模板，当然也可以全部删掉不写，但是，按标准办事肯定没错。&lt;/p&gt;
&lt;p&gt;后面开始就是真正的代码部分。&lt;/p&gt;
&lt;h3 id="导入模块"&gt;导入模块&lt;/h3&gt;
&lt;p&gt;你可能注意到了，使用&lt;code&gt;sys&lt;/code&gt;模块的第一步，就是导入该模块：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import sys
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;导入&lt;code&gt;sys&lt;/code&gt;模块后，我们就有了变量&lt;code&gt;sys&lt;/code&gt;指向该模块，利用&lt;code&gt;sys&lt;/code&gt;这个变量，就可以访问&lt;code&gt;sys&lt;/code&gt;模块的所有功能。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sys&lt;/code&gt;模块有一个&lt;code&gt;argv&lt;/code&gt;变量，用list存储了命令行的所有参数。&lt;code&gt;argv&lt;/code&gt;至少有一个元素，因为第一个参数永远是该.py文件的名称，例如：&lt;/p&gt;
&lt;p&gt;运行&lt;code&gt;python3 hello.py&lt;/code&gt;获得的&lt;code&gt;sys.argv&lt;/code&gt;就是&lt;code&gt;['hello.py']&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;运行&lt;code&gt;python3 hello.py Michael&lt;/code&gt;获得的&lt;code&gt;sys.argv&lt;/code&gt;就是&lt;code&gt;['hello.py', 'Michael]&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="main"&gt;main&lt;/h3&gt;
&lt;p&gt;最后，注意到这两行代码：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;if __name__==&amp;#39;__main__&amp;#39;:
test()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当我们在命令行运行&lt;code&gt;hello&lt;/code&gt;模块文件时，Python解释器把一个特殊变量&lt;code&gt;__name__&lt;/code&gt;置为&lt;code&gt;__main__&lt;/code&gt;，而如果在其他地方导入该&lt;code&gt;hello&lt;/code&gt;模块时，&lt;code&gt;if&lt;/code&gt;判断将失败，因此，这种&lt;code&gt;if&lt;/code&gt;测试可以让一个模块通过命令行运行时执行一些额外的代码，最常见的就是运行测试。&lt;/p&gt;
&lt;p&gt;我们可以用命令行运行&lt;code&gt;hello.py&lt;/code&gt;看看效果：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ python3 hello.py
Hello, world!
$ python hello.py hooby
Hello, hooby!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果启动Python交互环境，再导入&lt;code&gt;hello&lt;/code&gt;模块：&lt;/p&gt;</description></item><item><title>Python安装模块</title><link>/2016/05/11/python%E5%AE%89%E8%A3%85%E6%A8%A1%E5%9D%97/</link><pubDate>Wed, 11 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/11/python%E5%AE%89%E8%A3%85%E6%A8%A1%E5%9D%97/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;在Python中，安装第三方模块，是通过包管理工具pip完成的。&lt;/p&gt;
&lt;p&gt;如果你正在使用Mac或Linux，安装pip本身这个步骤就可以跳过了。&lt;/p&gt;
&lt;p&gt;如果你正在使用Windows，确保安装时勾选了&lt;code&gt;pip&lt;/code&gt;和&lt;code&gt;Add python.exe to Path&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在命令提示符窗口下尝试运行&lt;code&gt;pip&lt;/code&gt;，如果Windows提示未找到命令，可以重新运行安装程序添加&lt;code&gt;pip&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;注意：Mac或Linux上有可能并存Python 3.x和Python 2.x，因此对应的pip命令是&lt;code&gt;pip3&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;例如，我们要安装一个第三方库——Python Imaging Library，这是Python下非常强大的处理图像的工具库。不过，PIL目前只支持到Python 2.7，并且有年头没有更新了，因此，基于PIL的Pillow项目开发非常活跃，并且支持最新的Python 3。&lt;/p&gt;
&lt;p&gt;一般来说，第三方库都会在Python官方的&lt;a href="https://pypi.python.org/"&gt;pypi.python.org&lt;/a&gt;网站注册，要安装一个第三方库，必须先知道该库的名称，可以在官网或者pypi上搜索，比如Pillow的名称叫&lt;a href="https://pypi.python.org/pypi/Pillow/"&gt;Pillow&lt;/a&gt;，因此，安装Pillow的命令就是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pip install Pillow
# pip3 install Pillow
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;耐心等待下载并安装后，就可以使用Pillow了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="且慢" loading="lazy" src="l"&gt;&lt;/p&gt;
&lt;h3 id="安装常用模块"&gt;安装常用模块&lt;/h3&gt;
&lt;p&gt;在使用Python时，我们经常需要用到很多第三方库，例如，上面提到的Pillow，以及MySQL驱动程序，Web框架Flask，科学计算Numpy等。用pip一个一个安装费时费力，还需要考虑兼容性。推荐直接使用&lt;a href="https://www.anaconda.com/"&gt;Anaconda&lt;/a&gt;，这是一个基于Python的数据处理和科学计算平台，它已经内置了许多非常有用的第三方库，我们装上Anaconda，就相当于把数十个第三方模块自动安装好了，非常简单易用。&lt;/p&gt;
&lt;p&gt;可以从&lt;a href="https://www.anaconda.com/download/"&gt;Anaconda官网&lt;/a&gt;下载GUI安装包，安装包有500~600M，所以需要耐心等待下载。网速慢的同学请移步&lt;a href="https://pan.baidu.com/s/1kU5OCOB#list/path=%2Fpub%2Fpython"&gt;国内镜像&lt;/a&gt;。下载后直接安装，Anaconda会把系统Path中的python指向自己自带的Python，并且，Anaconda安装的第三方模块会安装在Anaconda自己的路径下，不影响系统已安装的Python目录。安装好Anaconda后，重新打开命令行窗口，输入python，可以看到Anaconda的信息：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌────────────────────────────────────────────────────────┐
│Command Prompt - python - □ x │
├────────────────────────────────────────────────────────┤
│Microsoft Windows [Version 10.0.0] │
│(c) 2015 Microsoft Corporation. All rights reserved. │
│ │
│C:\&amp;gt; python │
│Python 3.6.3 |Anaconda, Inc.| ... on win32 │
│Type &amp;#34;help&amp;#34;, ... for more information. │
│&amp;gt;&amp;gt;&amp;gt; import numpy │
│&amp;gt;&amp;gt;&amp;gt; _ │ │
└────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以尝试直接&lt;code&gt;import numpy&lt;/code&gt;等已安装的第三方模块。&lt;/p&gt;</description></item><item><title>Python模块的概念</title><link>/2016/05/11/python%E6%A8%A1%E5%9D%97%E7%9A%84%E6%A6%82%E5%BF%B5/</link><pubDate>Wed, 11 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/11/python%E6%A8%A1%E5%9D%97%E7%9A%84%E6%A6%82%E5%BF%B5/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="module"&gt;Module&lt;/h2&gt;
&lt;p&gt;在计算机程序的开发过程中，随着程序代码越写越多，在一个文件里代码就会越来越长，越来越不容易维护。&lt;/p&gt;
&lt;p&gt;为了编写可维护的代码，我们把很多函数分组，分别放到不同的文件里，这样，每个文件包含的代码就相对较少，很多编程语言都采用这种组织代码的方式。在Python中，一个.py文件就称之为一个模块（Module）。&lt;/p&gt;
&lt;p&gt;使用模块有什么好处？&lt;/p&gt;
&lt;p&gt;最大的好处是大大提高了代码的可维护性。其次，编写代码不必从零开始。当一个模块编写完毕，就可以被其他地方引用。我们在编写程序的时候，也经常引用其他模块，包括Python内置的模块和来自第三方的模块。&lt;/p&gt;
&lt;p&gt;使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中，因此，我们自己在编写模块时，不必考虑名字会与其他模块冲突。但是也要注意，尽量不要与内置函数名字冲突。点&lt;a href="http://docs.python.org/3/library/functions.html"&gt;这里&lt;/a&gt;查看Python的所有内置函数。&lt;/p&gt;
&lt;h2 id="package"&gt;Package&lt;/h2&gt;
&lt;p&gt;你也许还想到，如果不同的人编写的模块名相同怎么办？为了避免模块名冲突，Python又引入了按目录来组织模块的方法，称为包（Package）。&lt;/p&gt;
&lt;p&gt;举个例子，一个&lt;code&gt;abc.py&lt;/code&gt;的文件就是一个名字叫&lt;code&gt;abc&lt;/code&gt;的模块。&lt;/p&gt;
&lt;p&gt;现在，假设我们的&lt;code&gt;abc&lt;/code&gt;和&lt;code&gt;xyz&lt;/code&gt;这两个模块名字与其他模块冲突了，于是我们可以通过包来组织模块，避免冲突。方法是选择一个顶层包名，比如&lt;code&gt;mycompany&lt;/code&gt;，按照如下目录存放：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;mycompany
├─ __init__.py
├─ abc.py
└─ xyz.py
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;引入了包以后，只要顶层的包名不与别人冲突，那所有模块都不会与别人冲突。现在，&lt;code&gt;abc.py&lt;/code&gt;模块的名字就变成了&lt;code&gt;mycompany.abc&lt;/code&gt;，类似的，&lt;code&gt;xyz.py&lt;/code&gt;的模块名变成了&lt;code&gt;mycompany.xyz&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;请注意，每一个包目录下面都会有一个&lt;code&gt;__init__.py&lt;/code&gt;的文件，这个文件是&lt;strong&gt;必须&lt;/strong&gt;存在的，否则，Python就把这个目录当成普通目录，而不是一个包。&lt;code&gt;__init__.py&lt;/code&gt;可以是空文件，也可以有Python代码，因为&lt;code&gt;__init__.py&lt;/code&gt;本身就是一个模块，而它的模块名就是&lt;code&gt;mycompany&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;类似的，可以有多级目录，组成多级层次的包结构。比如如下的目录结构：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;mycompany
├─ web
│ ├─ __init__.py
│ ├─ utils.py
│ └─ www.py
├─ __init__.py
├─ abc.py
└─ xyz.py
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;文件&lt;code&gt;www.py&lt;/code&gt;的模块名就是&lt;code&gt;mycompany.web.www&lt;/code&gt;，两个文件&lt;code&gt;utils.py&lt;/code&gt;的模块名分别是&lt;code&gt;mycompany.utils&lt;/code&gt;和&lt;code&gt;mycompany.web.utils&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;自己创建模块时要注意命名，不能和Python自带的模块名称冲突。例如，系统自带了sys模块，自己的模块就不可命名为sys.py，否则将无法导入系统自带的sys模块。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mycompany.web&lt;/code&gt;也是一个模块，请指出该模块对应的.py文件。&lt;/p&gt;
&lt;p&gt;总结&lt;/p&gt;
&lt;p&gt;模块是一组Python代码的集合，可以使用其他模块，也可以被其他模块使用。&lt;/p&gt;
&lt;p&gt;创建自己的模块时，要注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模块名要遵循Python变量命名规范，不要使用中文、特殊字符；&lt;/li&gt;
&lt;li&gt;模块名不要和系统模块名冲突，最好先查看系统是否已存在该模块，检查方法是在Python交互环境执行&lt;code&gt;import abc&lt;/code&gt;，若成功则说明系统存在此模块。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Python偏函数</title><link>/2016/05/10/python%E5%81%8F%E5%87%BD%E6%95%B0/</link><pubDate>Tue, 10 May 2016 00:00:00 +0000</pubDate><guid>/2016/05/10/python%E5%81%8F%E5%87%BD%E6%95%B0/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;Python的&lt;code&gt;functools&lt;/code&gt;模块提供了很多有用的功能，其中一个就是偏函数（Partial function）。要注意，这里的偏函数和数学意义上的偏函数不一样。&lt;/p&gt;
&lt;p&gt;在介绍函数参数的时候，我们讲到，通过设定参数的默认值，可以降低函数调用的难度。而偏函数也可以做到这一点。举例如下：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;int()&lt;/code&gt;函数可以把字符串转换为整数，当仅传入字符串时，&lt;code&gt;int()&lt;/code&gt;函数默认按十进制转换：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; int(&amp;#39;12345&amp;#39;)
12345
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但&lt;code&gt;int()&lt;/code&gt;函数还提供额外的&lt;code&gt;base&lt;/code&gt;参数，默认值为&lt;code&gt;10&lt;/code&gt;。如果传入&lt;code&gt;base&lt;/code&gt;参数，就可以做N进制的转换：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; int(&amp;#39;12345&amp;#39;, base=8)
5349
&amp;gt;&amp;gt;&amp;gt; int(&amp;#39;12345&amp;#39;, 16)
74565
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;假设要转换大量的二进制字符串，每次都传入&lt;code&gt;int(x, base=2)&lt;/code&gt;非常麻烦，于是，我们想到，可以定义一个&lt;code&gt;int2()&lt;/code&gt;的函数，默认把&lt;code&gt;base=2&lt;/code&gt;传进去：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def int2(x, base=2):
return int(x, base)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这样，我们转换二进制就非常方便了：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; int2(&amp;#39;1000000&amp;#39;)
64
&amp;gt;&amp;gt;&amp;gt; int2(&amp;#39;1010101&amp;#39;)
85
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;functools.partial&lt;/code&gt;就是帮助我们创建一个偏函数的，不需要我们自己定义&lt;code&gt;int2()&lt;/code&gt;，可以直接使用下面的代码创建一个新的函数&lt;code&gt;int2&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import functools
&amp;gt;&amp;gt;&amp;gt; int2 = functools.partial(int, base=2)
&amp;gt;&amp;gt;&amp;gt; int2(&amp;#39;1000000&amp;#39;)
64
&amp;gt;&amp;gt;&amp;gt; int2(&amp;#39;1010101&amp;#39;)
85
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;所以，简单总结&lt;code&gt;functools.partial&lt;/code&gt;的作用就是，把一个函数的某些参数给固定住（也就是设置默认值），返回一个新的函数，调用这个新函数会更简单。&lt;/p&gt;
&lt;p&gt;注意到上面的新的&lt;code&gt;int2&lt;/code&gt;函数，仅仅是把&lt;code&gt;base&lt;/code&gt;参数重新设定默认值为&lt;code&gt;2&lt;/code&gt;，但也可以在函数调用时传入其他值：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; int2(&amp;#39;1000000&amp;#39;, base=10)
1000000
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最后，创建偏函数时，实际上可以接收函数对象、&lt;code&gt;*args&lt;/code&gt;和&lt;code&gt;**kw&lt;/code&gt;这3个参数，当传入：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;int2 = functools.partial(int, base=2)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;实际上固定了int()函数的关键字参数&lt;code&gt;base&lt;/code&gt;，也就是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;int2(&amp;#39;10010&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;相当于：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kw = { &amp;#39;base&amp;#39;: 2 }
int(&amp;#39;10010&amp;#39;, **kw)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当传入：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;max2 = functools.partial(max, 10)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;实际上会把&lt;code&gt;10&lt;/code&gt;作为&lt;code&gt;*args&lt;/code&gt;的一部分自动加到左边，也就是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;max2(5, 6, 7)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;相当于：&lt;/p&gt;</description></item><item><title>Python装饰器</title><link>/2016/04/30/python%E8%A3%85%E9%A5%B0%E5%99%A8/</link><pubDate>Sat, 30 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/30/python%E8%A3%85%E9%A5%B0%E5%99%A8/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h1 id="装饰器定义"&gt;装饰器定义&lt;/h1&gt;
&lt;p&gt;在代码运行期间动态增加功能的方式，称之为“装饰器”（Decorator）。&lt;/p&gt;
&lt;p&gt;由于函数也是一个对象，而且函数对象可以被赋值给变量，所以，通过变量也能调用该函数。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; def now():
... print(&amp;#39;2015-3-25&amp;#39;)
...
&amp;gt;&amp;gt;&amp;gt; f = now
&amp;gt;&amp;gt;&amp;gt; f()
2015-3-25
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;函数对象有一个&lt;code&gt;__name__&lt;/code&gt;属性，可以拿到函数的名字：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; now.__name__
&amp;#39;now&amp;#39;
&amp;gt;&amp;gt;&amp;gt; f.__name__
&amp;#39;now&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在，假设我们要增强&lt;code&gt;now()&lt;/code&gt;函数的功能，比如，在函数调用前后自动打印日志，但又不希望修改&lt;code&gt;now()&lt;/code&gt;函数的定义,这种情况就可以使用装饰器。&lt;/p&gt;
&lt;p&gt;本质上，decorator就是一个返回函数的高阶函数。所以，我们要定义一个能打印日志的decorator，可以定义如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def log(func):
def wrapper(*args, **kw):
print(&amp;#39;call %s():&amp;#39; % func.__name__)
return func(*args, **kw)
return wrapper
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;观察上面的&lt;code&gt;log&lt;/code&gt;，因为它是一个decorator，所以接受一个函数作为参数，并返回一个函数。我们要借助Python的@语法，把decorator置于函数的定义处：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;@log
def now():
print(&amp;#39;2015-3-25&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;调用&lt;code&gt;now()&lt;/code&gt;函数，不仅会运行&lt;code&gt;now()&lt;/code&gt;函数本身，还会在运行&lt;code&gt;now()&lt;/code&gt;函数前打印一行日志：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; now()
call now():
2015-3-25
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;把&lt;code&gt;@log&lt;/code&gt;放到&lt;code&gt;now()&lt;/code&gt;函数的定义处，相当于执行了语句：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;now = log(now)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由于&lt;code&gt;log()&lt;/code&gt;是一个decorator，返回一个函数，所以，原来的&lt;code&gt;now()&lt;/code&gt;函数仍然存在，只是现在同名的&lt;code&gt;now&lt;/code&gt;变量指向了新的函数，于是调用&lt;code&gt;now()&lt;/code&gt;将执行新函数，即在&lt;code&gt;log()&lt;/code&gt;函数中返回的&lt;code&gt;wrapper()&lt;/code&gt;函数。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wrapper()&lt;/code&gt;函数的参数定义是&lt;code&gt;(*args, **kw)&lt;/code&gt;，因此，&lt;code&gt;wrapper()&lt;/code&gt;函数可以接受任意参数的调用。在&lt;code&gt;wrapper()&lt;/code&gt;函数内，首先打印日志，再紧接着调用原始函数。&lt;/p&gt;
&lt;p&gt;如果decorator本身需要传入参数，那就需要编写一个返回decorator的高阶函数，写出来会更复杂。比如，要自定义log的文本：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def log(text):
def decorator(func):
def wrapper(*args, **kw):
print(&amp;#39;%s %s():&amp;#39; % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个3层嵌套的decorator用法如下：&lt;/p&gt;</description></item><item><title>Python匿名函数</title><link>/2016/04/28/python%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0/</link><pubDate>Thu, 28 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/28/python%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;当我们在传入函数时，有些时候，不需要显式地定义函数，直接传入匿名函数更方便。&lt;/p&gt;
&lt;p&gt;在Python中，对匿名函数提供了有限支持。还是以&lt;code&gt;map()&lt;/code&gt;函数为例，计算f(x)=x2时，除了定义一个&lt;code&gt;f(x)&lt;/code&gt;的函数外，还可以直接传入匿名函数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;通过对比可以看出，匿名函数&lt;code&gt;lambda x: x * x&lt;/code&gt;实际上就是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def f(x):
return x * x
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;关键字&lt;code&gt;lambda&lt;/code&gt;表示匿名函数，冒号前面的&lt;code&gt;x&lt;/code&gt;表示函数参数。&lt;/p&gt;
&lt;p&gt;匿名函数有个限制，就是只能有一个表达式，不用写&lt;code&gt;return&lt;/code&gt;，返回值就是该表达式的结果。&lt;/p&gt;
&lt;p&gt;用匿名函数有个好处，因为函数没有名字，不必担心函数名冲突。此外，匿名函数也是一个函数对象，也可以把匿名函数赋值给一个变量，再利用变量来调用该函数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f = lambda x: x * x
&amp;gt;&amp;gt;&amp;gt; f
&amp;lt;function &amp;lt;lambda&amp;gt; at 0x101c6ef28&amp;gt;
&amp;gt;&amp;gt;&amp;gt; f(5)
25
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;同样，也可以把匿名函数作为返回值返回，比如：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def build(x, y):
return lambda: x * x + y * y
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="try-it-"&gt;try it ?&lt;/h3&gt;
&lt;p&gt;请用匿名函数改造下面的代码：&lt;/p&gt;</description></item><item><title>Python返回函数</title><link>/2016/04/27/python%E8%BF%94%E5%9B%9E%E5%87%BD%E6%95%B0/</link><pubDate>Wed, 27 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/27/python%E8%BF%94%E5%9B%9E%E5%87%BD%E6%95%B0/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="函数作为返回值"&gt;函数作为返回值&lt;/h3&gt;
&lt;p&gt;高阶函数除了可以接受函数作为参数外，还可以把函数作为结果值返回。&lt;/p&gt;
&lt;p&gt;我们来实现一个可变参数的求和。通常情况下，求和的函数是这样 定义的：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是，如果不需要立刻求和，而是在后面的代码中，根据需要再计算怎么办？可以不返回求和的结果，而是返回求和的函数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当我们调用&lt;code&gt;lazy_sum()&lt;/code&gt;时，返回的并不是求和结果，而是求和函数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f = lazy_sum(1, 3, 5, 7, 9)
&amp;gt;&amp;gt;&amp;gt; f
&amp;lt;function lazy_sum.&amp;lt;locals&amp;gt;.sum at 0x101c6ed90&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;调用函数&lt;code&gt;f&lt;/code&gt;时，才真正计算求和的结果：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f()
25
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在这个例子中，我们在函数&lt;code&gt;lazy_sum&lt;/code&gt;中又定义了函数&lt;code&gt;sum&lt;/code&gt;，并且，内部函数&lt;code&gt;sum&lt;/code&gt;可以引用外部函数&lt;code&gt;lazy_sum&lt;/code&gt;的参数和局部变量，当&lt;code&gt;lazy_sum&lt;/code&gt;返回函数&lt;code&gt;sum&lt;/code&gt;时，相关参数和变量都保存在返回的函数中，这种称为“闭包（Closure）”的程序结构拥有极大的威力。&lt;/p&gt;
&lt;p&gt;请再注意一点，当我们调用&lt;code&gt;lazy_sum()&lt;/code&gt;时，每次调用都会返回一个新的函数，即使传入相同的参数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f1 = lazy_sum(1, 3, 5, 7, 9)
&amp;gt;&amp;gt;&amp;gt; f2 = lazy_sum(1, 3, 5, 7, 9)
&amp;gt;&amp;gt;&amp;gt; f1==f2
False
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;f1()&lt;/code&gt;和&lt;code&gt;f2()&lt;/code&gt;的调用结果互不影响。&lt;/p&gt;</description></item><item><title>Python高阶函数之sorted</title><link>/2016/04/24/python%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E4%B9%8Bsorted/</link><pubDate>Sun, 24 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/24/python%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E4%B9%8Bsorted/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="排序算法"&gt;排序算法&lt;/h3&gt;
&lt;p&gt;排序也是在程序中经常用到的算法。无论使用冒泡排序还是快速排序，排序的核心是比较两个元素的大小。如果是数字，我们可以直接比较，但如果是字符串或者两个dict呢？直接比较数学上的大小是没有意义的，因此，比较的过程必须通过函数抽象出来。&lt;/p&gt;
&lt;p&gt;Python内置的&lt;code&gt;sorted()&lt;/code&gt;函数就可以对list进行排序：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;此外，&lt;code&gt;sorted()&lt;/code&gt;函数也是一个高阶函数，它还可以接收一个&lt;code&gt;key&lt;/code&gt;函数来实现自定义的排序，例如按绝对值大小排序：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;key指定的函数将作用于list的每一个元素上，并根据key函数返回的结果进行排序。对比原始的list和经过&lt;code&gt;key=abs&lt;/code&gt;处理过的list：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;list = [36, 5, -12, 9, -21]
keys = [36, 5, 12, 9, 21]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后&lt;code&gt;sorted()&lt;/code&gt;函数按照keys进行排序，并按照对应关系返回list相应的元素：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;keys排序结果 =&amp;gt; [5, 9, 12, 21, 36]
| | | | |
最终结果 =&amp;gt; [5, 9, -12, -21, 36]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们再看一个字符串排序的例子：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; sorted([&amp;#39;bob&amp;#39;, &amp;#39;about&amp;#39;, &amp;#39;Zoo&amp;#39;, &amp;#39;Credit&amp;#39;])
[&amp;#39;Credit&amp;#39;, &amp;#39;Zoo&amp;#39;, &amp;#39;about&amp;#39;, &amp;#39;bob&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;默认情况下，对字符串排序，是按照ASCII的大小比较的，由于&lt;code&gt;'Z' &amp;lt; 'a'&lt;/code&gt;，结果，大写字母&lt;code&gt;Z&lt;/code&gt;会排在小写字母&lt;code&gt;a&lt;/code&gt;的前面。&lt;/p&gt;</description></item><item><title>Python高阶函数之filter</title><link>/2016/04/23/python%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E4%B9%8Bfilter/</link><pubDate>Sat, 23 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/23/python%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E4%B9%8Bfilter/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="filter介绍"&gt;filter介绍&lt;/h2&gt;
&lt;p&gt;Python内建的&lt;code&gt;filter()&lt;/code&gt;函数用于过滤序列。&lt;/p&gt;
&lt;p&gt;和&lt;code&gt;map()&lt;/code&gt;类似，&lt;code&gt;filter()&lt;/code&gt;也接收一个函数和一个序列。和&lt;code&gt;map()&lt;/code&gt;不同的是，&lt;code&gt;filter()&lt;/code&gt;把传入的函数依次作用于每个元素，然后根据返回值是&lt;code&gt;True&lt;/code&gt;还是&lt;code&gt;False&lt;/code&gt;决定保留还是丢弃该元素。&lt;/p&gt;
&lt;p&gt;例如，在一个list中，删掉偶数，只保留奇数，可以这么写：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;把一个序列中的空字符串删掉，可以这么写：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def not_empty(s):
return s and s.strip()
#str.strip([chars]); 去除字符串首位的字符(chars)
list(filter(not_empty, [&amp;#39;A&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;B&amp;#39;, None, &amp;#39;C&amp;#39;, &amp;#39; &amp;#39;]))
# 结果: [&amp;#39;A&amp;#39;, &amp;#39;B&amp;#39;, &amp;#39;C&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可见用&lt;code&gt;filter()&lt;/code&gt;这个高阶函数，关键在于正确实现一个“筛选”函数。&lt;/p&gt;
&lt;p&gt;注意到&lt;code&gt;filter()&lt;/code&gt;函数返回的是一个&lt;code&gt;Iterator&lt;/code&gt;，也就是一个惰性序列，所以要强迫&lt;code&gt;filter()&lt;/code&gt;完成计算结果，需要用&lt;code&gt;list()&lt;/code&gt;函数获得所有结果并返回list。&lt;/p&gt;
&lt;h2 id="filter求素数"&gt;filter求素数&lt;/h2&gt;
&lt;p&gt;计算&lt;a href="http://baike.baidu.com/view/10626.htm"&gt;素数&lt;/a&gt;的一个方法是&lt;a href="http://baike.baidu.com/view/3784258.htm"&gt;埃氏筛法&lt;/a&gt;，它的算法理解起来非常简单：&lt;/p&gt;
&lt;p&gt;首先，列出从&lt;code&gt;2&lt;/code&gt;开始的所有自然数，构造一个序列：&lt;/p&gt;
&lt;p&gt;2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, &amp;hellip;&lt;/p&gt;</description></item><item><title>Python高阶函数之map和reduce</title><link>/2016/04/19/python%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E4%B9%8Bmap%E5%92%8Creduce/</link><pubDate>Tue, 19 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/19/python%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E4%B9%8Bmap%E5%92%8Creduce/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;Python内建了&lt;code&gt;map()&lt;/code&gt;和&lt;code&gt;reduce()&lt;/code&gt;函数。&lt;/p&gt;
&lt;p&gt;如果你读过Google的那篇大名鼎鼎的论文“&lt;a href="http://research.google.com/archive/mapreduce.html"&gt;MapReduce: Simplified Data Processing on Large Clusters&lt;/a&gt;”，你就能大概明白map/reduce的概念。&lt;/p&gt;
&lt;h2 id="map"&gt;map&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;map()&lt;/code&gt;函数接收两个参数，一个是函数，一个是&lt;code&gt;Iterable&lt;/code&gt;，&lt;code&gt;map&lt;/code&gt;将传入的函数依次作用到序列的每个元素，并把结果作为新的&lt;code&gt;Iterator&lt;/code&gt;返回。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;map(fun, Iteratble)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;举例说明，比如我们有一个函数&lt;code&gt;f(x) = x * x&lt;/code&gt;，要把这个函数作用在一个list &lt;code&gt;[1, 2, 3, 4, 5, 6, 7, 8, 9]&lt;/code&gt;上，就可以用&lt;code&gt;map()&lt;/code&gt;实现如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; f(x) = x * x
│
│
┌───┬───┬───┬───┼───┬───┬───┬───┐
│ │ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
[ 1 2 3 4 5 6 7 8 9 ]
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
[ 1 4 9 16 25 36 49 64 81 ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在，我们用Python代码实现：&lt;/p&gt;</description></item><item><title>Python高阶函数</title><link>/2016/04/18/python%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/</link><pubDate>Mon, 18 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/18/python%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="高阶函数"&gt;高阶函数&lt;/h2&gt;
&lt;p&gt;高阶函数英文叫Higher-order function。把函数作为参数传入，这样的函数称为高阶函数，编写高阶函数，就是让函数的参数能够接收别的函数。&lt;/p&gt;
&lt;h3 id="变量可以指向函数"&gt;变量可以指向函数&lt;/h3&gt;
&lt;p&gt;以Python内置的求绝对值的函数&lt;code&gt;abs()&lt;/code&gt;为例，调用该函数用以下代码：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; abs(-10)
10
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是，如果只写&lt;code&gt;abs&lt;/code&gt;呢？&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; abs
&amp;lt;built-in function abs&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可见，&lt;code&gt;abs(-10)&lt;/code&gt;是函数调用，而&lt;code&gt;abs&lt;/code&gt;是函数本身。&lt;/p&gt;
&lt;p&gt;要获得函数调用结果，我们可以把结果赋值给变量：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; x = abs(-10)
&amp;gt;&amp;gt;&amp;gt; x
10
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是，如果把函数本身赋值给变量呢？&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f = abs
&amp;gt;&amp;gt;&amp;gt; f
&amp;lt;built-in function abs&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;结论：函数本身也可以赋值给变量，即：变量可以指向函数。&lt;/p&gt;
&lt;p&gt;如果一个变量指向了一个函数，那么，可否通过该变量来调用这个函数？用代码验证一下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; f = abs
&amp;gt;&amp;gt;&amp;gt; f(-10)
10
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;成功！说明变量&lt;code&gt;f&lt;/code&gt;现在已经指向了&lt;code&gt;abs&lt;/code&gt;函数本身。直接调用&lt;code&gt;abs()&lt;/code&gt;函数和调用变量&lt;code&gt;f()&lt;/code&gt;完全相同。&lt;/p&gt;
&lt;h3 id="函数名也是变量"&gt;函数名也是变量&lt;/h3&gt;
&lt;p&gt;那么函数名是什么呢？函数名其实就是指向函数的变量！对于&lt;code&gt;abs()&lt;/code&gt;这个函数，完全可以把函数名&lt;code&gt;abs&lt;/code&gt;看成变量，它指向一个可以计算绝对值的函数！&lt;/p&gt;
&lt;p&gt;如果把&lt;code&gt;abs&lt;/code&gt;指向其他对象，会有什么情况发生？&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; abs = 10
&amp;gt;&amp;gt;&amp;gt; abs(-10)
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
TypeError: &amp;#39;int&amp;#39; object is not callable
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;把&lt;code&gt;abs&lt;/code&gt;指向&lt;code&gt;10&lt;/code&gt;后，就无法通过&lt;code&gt;abs(-10)&lt;/code&gt;调用该函数了！因为&lt;code&gt;abs&lt;/code&gt;这个变量已经不指向求绝对值函数而是指向一个整数&lt;code&gt;10&lt;/code&gt;！&lt;/p&gt;
&lt;p&gt;当然实际代码绝对不能这么写，这里是为了说明函数名也是变量。要恢复&lt;code&gt;abs&lt;/code&gt;函数，请重启Python交互环境。&lt;/p&gt;
&lt;p&gt;注：由于&lt;code&gt;abs&lt;/code&gt;函数实际上是定义在&lt;code&gt;import builtins&lt;/code&gt;模块中的，所以要让修改&lt;code&gt;abs&lt;/code&gt;变量的指向在其它模块也生效，要用&lt;code&gt;import builtins; builtins.abs = 10&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>Python常见问题总结</title><link>/2016/04/16/python%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93/</link><pubDate>Sat, 16 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/16/python%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h1 id="1lambda"&gt;1.lambda&lt;/h1&gt;
&lt;p&gt;Python 内置函数&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="描述"&gt;描述&lt;/h2&gt;
&lt;p&gt;python 使用 lambda 来创建匿名函数。&lt;/p&gt;
&lt;h2 id="语法"&gt;语法&lt;/h2&gt;
&lt;p&gt;lambda 函数的语法只包含一个语句，如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;lambda [arg1 [,arg2,.....argn]]:expression
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="注意"&gt;注意&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;lambda (x, y): x + y
# tuple parameter unpacking is not supported in python3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这样的使用在python3中已经被废弃了，会提示上面注释中的错误&lt;/p&gt;
&lt;p&gt;那么元组tuple如何作为参数呢，will be translated into:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;lambda x_y: x_y[0] + x_y[1]
# 即在传入参数的时候，整个变量作为元组的参数，使用的时候，引用整个元组的位置参数
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id="2map"&gt;2.map()&lt;/h1&gt;
&lt;p&gt;Python 内置函数&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="描述-1"&gt;描述&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;map()&lt;/strong&gt; 会根据提供的函数对指定序列做映射。&lt;/p&gt;
&lt;p&gt;第一个参数 function 以参数序列中的每一个元素调用 function 函数，返回包含每次 function 函数返回值的新列表。&lt;/p&gt;
&lt;h2 id="语法-1"&gt;语法&lt;/h2&gt;
&lt;p&gt;map() 函数语法：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;map(function, iterable, ...)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="参数"&gt;参数&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;function &amp;ndash; 函数，有两个参数&lt;/li&gt;
&lt;li&gt;iterable &amp;ndash; 一个或多个序列&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="返回值"&gt;返回值&lt;/h2&gt;
&lt;p&gt;Python 2.x 返回列表。&lt;/p&gt;</description></item><item><title>Python sdk打包</title><link>/2016/04/14/python-sdk%E6%89%93%E5%8C%85/</link><pubDate>Thu, 14 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/14/python-sdk%E6%89%93%E5%8C%85/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h1 id="setuptools"&gt;setuptools&lt;/h1&gt;
&lt;p&gt;setuptools 是一个优秀的，可靠的 Pthon 包安装与分发工具。&lt;/p&gt;
&lt;h2 id="包格式"&gt;包格式&lt;/h2&gt;
&lt;p&gt;Python 库打包的格式包括 &lt;code&gt;Wheel&lt;/code&gt; 和 &lt;code&gt;Egg&lt;/code&gt;。Egg 格式是由 setuptools 在 2004 年引入，而 Wheel 格式是由 PEP427 在 2012 年定义。使用 &lt;code&gt;Wheel&lt;/code&gt; 和 &lt;code&gt;Egg&lt;/code&gt; 安装都不需要重新构建和编译，其在发布之前就应该完成测试和构建。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Egg&lt;/code&gt; 和 &lt;code&gt;Wheel&lt;/code&gt; 本质上都是一个 zip 格式包，Egg 文件使用 &lt;code&gt;.egg&lt;/code&gt; 扩展名，Wheel 使用 &lt;code&gt;.whl&lt;/code&gt; 扩展名。Wheel 的出现是为了替代 Egg，其现在被认为是 Python 的二进制包的标准格式。&lt;/p&gt;
&lt;p&gt;以下是 Wheel 和 Egg 的主要区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wheel 有一个官方的 PEP427 来定义，而 Egg 没有 PEP 定义&lt;/li&gt;
&lt;li&gt;Wheel 是一种分发格式，即打包格式。而 Egg 既是一种分发格式，也是一种运行时安装的格式，并且是可以被直接 import&lt;/li&gt;
&lt;li&gt;Wheel 文件不会包含 .pyc 文件&lt;/li&gt;
&lt;li&gt;Wheel 使用和 PEP376 兼容的 .dist-info 目录，而 Egg 使用 .egg-info 目录&lt;/li&gt;
&lt;li&gt;Wheel 有着更丰富的命名规则。&lt;/li&gt;
&lt;li&gt;Wheel 是有版本的。每个 Wheel 文件都包含 wheel 规范的版本和打包的实现&lt;/li&gt;
&lt;li&gt;Wheel 在内部被 sysconfig path type 管理，因此转向其他格式也更容易&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;详细描述可见：&lt;a href="https://packaging.python.org/discussions/wheel-vs-egg/"&gt;Wheel vs Egg&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Python函数式编程</title><link>/2016/04/10/python%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/</link><pubDate>Sun, 10 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/10/python%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h1 id="函数式编程概念"&gt;函数式编程概念&lt;/h1&gt;
&lt;p&gt;函数式编程就是指高度抽象的编程范式。&lt;/p&gt;
&lt;p&gt;函数是Python内建支持的一种封装，我们通过把大段代码拆成函数，通过一层一层的函数调用，就可以把复杂任务分解成简单的任务，这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。&lt;/p&gt;
&lt;p&gt;而函数式编程（请注意多了一个“式”字）——Functional Programming，虽然也可以归结到面向过程的程序设计，但其思想更接近数学计算。&lt;/p&gt;
&lt;p&gt;我们首先要搞明白计算机（Computer）和计算（Compute）的概念。&lt;/p&gt;
&lt;p&gt;在计算机的层次上，CPU执行的是加减乘除的指令代码，以及各种条件判断和跳转指令，所以，汇编语言是最贴近计算机的语言。&lt;/p&gt;
&lt;p&gt;而计算则指数学意义上的计算，越是抽象的计算，离计算机硬件越远。&lt;/p&gt;
&lt;p&gt;对应到编程语言，就是越低级的语言，越贴近计算机，抽象程度低，执行效率高，比如C语言；越高级的语言，越贴近计算，抽象程度高，执行效率低，比如Lisp语言。&lt;/p&gt;
&lt;p&gt;函数式编程就是一种抽象程度很高的编程范式，纯粹的函数式编程语言编写的函数没有变量，因此，任意一个函数，只要输入是确定的，输出就是确定的，这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言，由于函数内部的变量状态不确定，同样的输入，可能得到不同的输出，因此，这种函数是有副作用的。&lt;/p&gt;
&lt;p&gt;函数式编程的一个特点就是，允许把函数本身作为参数传入另一个函数，还允许返回一个函数！&lt;/p&gt;
&lt;p&gt;Python对函数式编程提供部分支持。由于Python允许使用变量，因此，Python不是纯函数式编程语言。&lt;/p&gt;
&lt;h1 id="函数式编程内容"&gt;函数式编程内容&lt;/h1&gt;
&lt;p&gt;Python里面的函数式编程有:&lt;/p&gt;
&lt;p&gt;1.高阶函数&lt;/p&gt;
&lt;p&gt;2.返回函数&lt;/p&gt;
&lt;p&gt;3.匿名函数&lt;/p&gt;
&lt;p&gt;4.装饰器&lt;/p&gt;
&lt;p&gt;5.偏函数&lt;/p&gt;
&lt;p&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;后面会吧这几个分别写出来.&lt;/p&gt;</description></item><item><title>Python之sort和sorted</title><link>/2016/04/02/python%E4%B9%8Bsort%E5%92%8Csorted/</link><pubDate>Sat, 02 Apr 2016 00:00:00 +0000</pubDate><guid>/2016/04/02/python%E4%B9%8Bsort%E5%92%8Csorted/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="sort-or-sorted-"&gt;sort or sorted ?&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sort 与 sorted 区别：
sort 是应用在 list 上的方法，sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作，而内建函数 sorted 方法返回的是一个新的 list，而不是在原来的基础上进行的操作。
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="listsorted的用法"&gt;list.sorted的用法&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sorted(iterable)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;----------------------------------------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; b &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sorted(a) &lt;span style="color:#75715e"&gt;# 保留原列表&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; b
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;----------------------------------------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sorted(iterable, cmp)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sorted(iterable, key)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sorted(iterable, cmp, key)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sorted(iterable, cmp, key, reverse&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;----------------------------------------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; L&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[(&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; sorted(L, cmp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;lambda&lt;/span&gt; x,y:cmp(x[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;],y[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;])) &lt;span style="color:#75715e"&gt;# 利用cmp函数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[(&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; sorted(L, key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;lambda&lt;/span&gt; x:x[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]) &lt;span style="color:#75715e"&gt;# 利用key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[(&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; students &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [(&lt;span style="color:#e6db74"&gt;&amp;#39;john&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;jane&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;B&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;dave&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;B&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; sorted(students, key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;lambda&lt;/span&gt; s: s[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]) &lt;span style="color:#75715e"&gt;# 按年龄排序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[(&lt;span style="color:#e6db74"&gt;&amp;#39;dave&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;B&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;jane&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;B&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;john&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; sorted(students, key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;lambda&lt;/span&gt; s: s[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;], reverse&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# 按降序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[(&lt;span style="color:#e6db74"&gt;&amp;#39;john&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;jane&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;B&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;dave&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;B&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;----------------------------------------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="与listsort-的使用"&gt;与list.sort 的使用&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sort(self, key=None, reverse=False)
if __name__ == &amp;#39;__main__&amp;#39;:
a = [5, 7, 6, 3, 4, 1, 2]
b = [(&amp;#39;dave&amp;#39;, &amp;#39;B&amp;#39;, 10), (&amp;#39;jane&amp;#39;, &amp;#39;B&amp;#39;, 12), (&amp;#39;john&amp;#39;, &amp;#39;A&amp;#39;, 15)]
a.sort(reverse=True)
print(a)
b.sort(key=lambda x:x[0])
print(b)
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Python特性之迭代器</title><link>/2016/03/31/python%E7%89%B9%E6%80%A7%E4%B9%8B%E8%BF%AD%E4%BB%A3%E5%99%A8/</link><pubDate>Thu, 31 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/31/python%E7%89%B9%E6%80%A7%E4%B9%8B%E8%BF%AD%E4%BB%A3%E5%99%A8/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h1 id="iterable"&gt;Iterable&lt;/h1&gt;
&lt;p&gt;我们已经知道，可以直接作用于&lt;code&gt;for&lt;/code&gt;循环的数据类型有以下几种：&lt;/p&gt;
&lt;p&gt;一类是集合数据类型，如&lt;code&gt;list&lt;/code&gt;、&lt;code&gt;tuple&lt;/code&gt;、&lt;code&gt;dict&lt;/code&gt;、&lt;code&gt;set&lt;/code&gt;、&lt;code&gt;str&lt;/code&gt;等；&lt;/p&gt;
&lt;p&gt;一类是&lt;code&gt;generator&lt;/code&gt;，包括生成器和带&lt;code&gt;yield&lt;/code&gt;的generator function。&lt;/p&gt;
&lt;p&gt;这些可以直接作用于&lt;code&gt;for&lt;/code&gt;循环的对象统称为可迭代对象：&lt;code&gt;Iterable&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;可以使用&lt;code&gt;isinstance()&lt;/code&gt;判断一个对象是否是&lt;code&gt;Iterable&lt;/code&gt;对象：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from collections import Iterable
&amp;gt;&amp;gt;&amp;gt; isinstance([], Iterable)
True
&amp;gt;&amp;gt;&amp;gt; isinstance({}, Iterable)
True
&amp;gt;&amp;gt;&amp;gt; isinstance(&amp;#39;abc&amp;#39;, Iterable)
True
&amp;gt;&amp;gt;&amp;gt; isinstance((x for x in range(10)), Iterable)
True
&amp;gt;&amp;gt;&amp;gt; isinstance(100, Iterable)
False
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id="iterator"&gt;Iterator&lt;/h1&gt;
&lt;p&gt;而生成器不但可以作用于&lt;code&gt;for&lt;/code&gt;循环，还可以被&lt;code&gt;next()&lt;/code&gt;函数不断调用并返回下一个值，直到最后抛出&lt;code&gt;StopIteration&lt;/code&gt;错误表示无法继续返回下一个值了。&lt;/p&gt;
&lt;p&gt;可以被&lt;code&gt;next()&lt;/code&gt;函数调用并不断返回下一个值的对象称为迭代器：&lt;code&gt;Iterator&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;可以使用&lt;code&gt;isinstance()&lt;/code&gt;判断一个对象是否是&lt;code&gt;Iterator&lt;/code&gt;对象：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from collections import Iterator
&amp;gt;&amp;gt;&amp;gt; isinstance((x for x in range(10)), Iterator)
True
&amp;gt;&amp;gt;&amp;gt; isinstance([], Iterator)
False
&amp;gt;&amp;gt;&amp;gt; isinstance({}, Iterator)
False
&amp;gt;&amp;gt;&amp;gt; isinstance(&amp;#39;abc&amp;#39;, Iterator)
False
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;生成器都是&lt;code&gt;Iterator&lt;/code&gt;对象，但&lt;code&gt;list&lt;/code&gt;、&lt;code&gt;dict&lt;/code&gt;、&lt;code&gt;str&lt;/code&gt;虽然是&lt;code&gt;Iterable&lt;/code&gt;，却不是&lt;code&gt;Iterator&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="iteratble转iterator"&gt;Iteratble转Iterator&lt;/h2&gt;
&lt;p&gt;把&lt;code&gt;list&lt;/code&gt;、&lt;code&gt;dict&lt;/code&gt;、&lt;code&gt;str&lt;/code&gt;等&lt;code&gt;Iterable&lt;/code&gt;变成&lt;code&gt;Iterator&lt;/code&gt;可以使用&lt;code&gt;iter()&lt;/code&gt;函数：&lt;/p&gt;</description></item><item><title>Python shutil移动文件</title><link>/2016/03/29/python-shutil%E7%A7%BB%E5%8A%A8%E6%96%87%E4%BB%B6/</link><pubDate>Tue, 29 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/29/python-shutil%E7%A7%BB%E5%8A%A8%E6%96%87%E4%BB%B6/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="python-终端输出字体设置"&gt;Python 终端输出字体设置&lt;/h2&gt;
&lt;p&gt;shutil可以实现文件的复制，移动&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 复制文件：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shutil&lt;span style="color:#f92672"&gt;.&lt;/span&gt;copyfile(&lt;span style="color:#e6db74"&gt;&amp;#34;oldfile&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;newfile&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# oldfile和newfile都只能是文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shutil&lt;span style="color:#f92672"&gt;.&lt;/span&gt;copy(&lt;span style="color:#e6db74"&gt;&amp;#34;oldfile&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;newfile&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# oldfile只能是文件夹，newfile可以是文件，也可以是目标目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 复制文件夹：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shutil&lt;span style="color:#f92672"&gt;.&lt;/span&gt;copytree(&lt;span style="color:#e6db74"&gt;&amp;#34;olddir&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;newdir&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# olddir和newdir都只能是目录，且newdir必须不存在&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 重命名文件（目录）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rename(&lt;span style="color:#e6db74"&gt;&amp;#34;oldname&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;newname&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 文件或目录都是使用这条命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 移动文件（目录）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shutil&lt;span style="color:#f92672"&gt;.&lt;/span&gt;move(&lt;span style="color:#e6db74"&gt;&amp;#34;oldpos&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;newpos&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Python特性之生成器</title><link>/2016/03/29/python%E7%89%B9%E6%80%A7%E4%B9%8B%E7%94%9F%E6%88%90%E5%99%A8/</link><pubDate>Tue, 29 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/29/python%E7%89%B9%E6%80%A7%E4%B9%8B%E7%94%9F%E6%88%90%E5%99%A8/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h1 id="生成器generator"&gt;生成器(generator)&lt;/h1&gt;
&lt;p&gt;在生成列表的过程中，根据需要动态生成列表的机制成为生成器。&lt;/p&gt;
&lt;p&gt;通过列表生成式，我们可以直接创建一个列表。但是，受到内存限制，列表容量肯定是有限的。而且，创建一个包含100万个元素的列表，不仅占用很大的存储空间，如果我们仅仅需要访问前面几个元素，那后面绝大多数元素占用的空间都白白浪费了。&lt;/p&gt;
&lt;p&gt;所以，如果列表元素可以按照某种算法推算出来，那我们是否可以在循环的过程中不断推算出后续的元素呢？这样就不必创建完整的list，从而节省大量的空间。在Python中，这种一边循环一边计算的机制，称为生成器：generator。&lt;/p&gt;
&lt;h2 id="next调用"&gt;next()调用&lt;/h2&gt;
&lt;p&gt;要创建一个generator，有很多种方法。第一种方法很简单，只要把一个列表生成式的&lt;code&gt;[]&lt;/code&gt;改成&lt;code&gt;()&lt;/code&gt;，就创建了一个generator：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; L = [x * x for x in range(6)]
&amp;gt;&amp;gt;&amp;gt; L
[0, 1, 4, 9, 16, 25]
&amp;gt;&amp;gt;&amp;gt; g = (x * x for x in range(6))
&amp;gt;&amp;gt;&amp;gt; g
&amp;lt;generator object &amp;lt;genexpr&amp;gt; at 0x1022ef630&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建&lt;code&gt;L&lt;/code&gt;和&lt;code&gt;g&lt;/code&gt;的区别仅在于最外层的&lt;code&gt;[]&lt;/code&gt;和&lt;code&gt;()&lt;/code&gt;，&lt;code&gt;L&lt;/code&gt;是一个list，而&lt;code&gt;g&lt;/code&gt;是一个generator。&lt;/p&gt;
&lt;p&gt;我们可以直接打印出list的每一个元素，但我们怎么打印出generator的每一个元素呢？&lt;/p&gt;
&lt;p&gt;如果要一个一个打印出来，可以通过&lt;code&gt;next()&lt;/code&gt;函数获得generator的下一个返回值：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; next(g)
0
&amp;gt;&amp;gt;&amp;gt; next(g)
1
&amp;gt;&amp;gt;&amp;gt; next(g)
4
&amp;gt;&amp;gt;&amp;gt; next(g)
9
&amp;gt;&amp;gt;&amp;gt; next(g)
16
&amp;gt;&amp;gt;&amp;gt; next(g)
25
&amp;gt;&amp;gt;&amp;gt; next(g)
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
StopIteration
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们讲过，generator保存的是算法，每次调用&lt;code&gt;next(g)&lt;/code&gt;，就计算出&lt;code&gt;g&lt;/code&gt;的下一个元素的值，直到计算到最后一个元素，没有更多的元素时，抛出&lt;code&gt;StopIteration&lt;/code&gt;的错误。&lt;/p&gt;</description></item><item><title>Python输出颜色</title><link>/2016/03/27/python%E8%BE%93%E5%87%BA%E9%A2%9C%E8%89%B2/</link><pubDate>Sun, 27 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/27/python%E8%BE%93%E5%87%BA%E9%A2%9C%E8%89%B2/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h2 id="python-终端输出字体设置"&gt;Python 终端输出字体设置&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;实现过程：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;​ 终端的字符颜色是用转义序列控制的，是文本模式下的系统显示功能，和具体的语言无关。&lt;/p&gt;
&lt;p&gt;​ 转义序列是以ESC开头,即用\033来完成（ESC的ASCII码用十进制表示是27，用八进制表示就是033）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;书写格式：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;​ &lt;strong&gt;开头部分&lt;/strong&gt;：\033[显示方式;前景色;背景色m + &lt;strong&gt;结尾部分：&lt;/strong&gt;\033[m&lt;/p&gt;
&lt;p&gt;​ 注意：开头部分的三个参数：显示方式，前景色，背景色是可选参数，可以只写其中的某一个；另外由于表示三个参数不同含义的数值都是唯一的没有重复的，所以三个参数的书写先后顺序没有固定要求，系统都能识别；但是，建议按照默认的格式规范书写。&lt;/p&gt;
&lt;p&gt;​ 对于结尾部分，其实也可以省略，但是为了书写规范，建议\033[***开头，\033[0m结尾。很多人在结尾部分写成\033[0m，很多文章也是这么说，多半估计他们都是直接抄的别人的blog，其实连0 都是可以省略掉的，我自己试过没有问题。&lt;/p&gt;
&lt;p&gt;那这些参数分别是什么值，又代表什么意思呢，请看下边的表，&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数值表示的参数含义：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;显示方式&lt;/th&gt;
&lt;th&gt;0（默认值）&lt;/th&gt;
&lt;th&gt;22（非粗体）&lt;/th&gt;
&lt;th&gt;4（下划线）&lt;/th&gt;
&lt;th&gt;24（非下划线）&lt;/th&gt;
&lt;th&gt;5（闪烁）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;显示方式&lt;/td&gt;
&lt;td&gt;25（非闪烁）&lt;/td&gt;
&lt;td&gt;7（反显）&lt;/td&gt;
&lt;td&gt;27（非反显）&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;前景色&lt;/td&gt;
&lt;td&gt;30（黑色）&lt;/td&gt;
&lt;td&gt;31（红色）&lt;/td&gt;
&lt;td&gt;32（绿色）&lt;/td&gt;
&lt;td&gt;33（黄色）&lt;/td&gt;
&lt;td&gt;34（蓝色）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;前景色&lt;/td&gt;
&lt;td&gt;35（洋红）&lt;/td&gt;
&lt;td&gt;36（青色）&lt;/td&gt;
&lt;td&gt;37（白色）&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;背景色&lt;/td&gt;
&lt;td&gt;40（黑色）&lt;/td&gt;
&lt;td&gt;41（红色）&lt;/td&gt;
&lt;td&gt;42（绿色）&lt;/td&gt;
&lt;td&gt;43（黄色）&lt;/td&gt;
&lt;td&gt;44（蓝色）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;背景色&lt;/td&gt;
&lt;td&gt;45（洋红）&lt;/td&gt;
&lt;td&gt;46（青色）&lt;/td&gt;
&lt;td&gt;47（白色）&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;常见开头格式&lt;/strong&gt;：
\033[m 默认字体正常显示，不高亮
\033[31m 红色字体正常显示
\033[1;32;40m 显示方式: 高亮 字体前景色：绿色 背景色：黑色
\033[31;46m 显示方式: 正常 字体前景色：红色 背景色：青色&lt;/p&gt;</description></item><item><title>Python</title><link>/2016/03/22/python/</link><pubDate>Tue, 22 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/22/python/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h1 id="什么是列表生成式"&gt;什么是列表生成式&lt;/h1&gt;
&lt;p&gt;列表生成式即List Comprehensions，是Python内置的非常简单却强大的可以用来创建list的生成式。&lt;/p&gt;
&lt;p&gt;举个例子，要生成list &lt;code&gt;[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]&lt;/code&gt;可以用&lt;code&gt;list(range(1, 11))&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但如果要生成&lt;code&gt;[1x1, 2x2, 3x3, ..., 10x10]&lt;/code&gt;怎么做？方法一是循环：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; L = []
&amp;gt;&amp;gt;&amp;gt; for x in range(1, 11):
... L.append(x * x)
...
&amp;gt;&amp;gt;&amp;gt; L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是循环太繁琐，而列表生成式则可以用一行语句代替循环生成上面的list：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;写列表生成式时，把要生成的元素&lt;code&gt;x * x&lt;/code&gt;放到前面，后面跟&lt;code&gt;for&lt;/code&gt;循环，就可以把list创建出来，十分有用，多写几次，很快就可以熟悉这种语法。&lt;/p&gt;</description></item><item><title>Python特性之迭代</title><link>/2016/03/22/python%E7%89%B9%E6%80%A7%E4%B9%8B%E8%BF%AD%E4%BB%A3/</link><pubDate>Tue, 22 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/22/python%E7%89%B9%E6%80%A7%E4%B9%8B%E8%BF%AD%E4%BB%A3/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="迭代"&gt;迭代&lt;/h3&gt;
&lt;p&gt;如果给定一个list或tuple，我们可以通过&lt;code&gt;for&lt;/code&gt;循环来遍历这个list或tuple，这种遍历我们称为迭代（Iteration）。&lt;/p&gt;
&lt;h4 id="list和tuple"&gt;list和tuple&lt;/h4&gt;
&lt;p&gt;在Python中，迭代是通过&lt;code&gt;for ... in&lt;/code&gt;来完成的，而很多语言比如C语言，迭代list是通过下标完成的，比如Java代码：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;for (i=0; i&amp;lt;list.length; i++) {
n = list[i];
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以看出，Python的&lt;code&gt;for&lt;/code&gt;循环抽象程度要高于C的&lt;code&gt;for&lt;/code&gt;循环，因为Python的&lt;code&gt;for&lt;/code&gt;循环不仅可以用在list或tuple上，还可以作用在其他可迭代对象上。&lt;/p&gt;
&lt;h4 id="dict"&gt;dict&lt;/h4&gt;
&lt;p&gt;list这种数据类型虽然有下标，但很多其他数据类型是没有下标的，但是，只要是可迭代对象，无论有无下标，都可以迭代，比如dict就可以迭代：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; d = {&amp;#39;a&amp;#39;: 1, &amp;#39;b&amp;#39;: 2, &amp;#39;c&amp;#39;: 3}
&amp;gt;&amp;gt;&amp;gt; for key in d:
... print(key)
...
a
c
b
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因为dict的存储不是按照list的方式顺序排列，所以，迭代出的结果顺序很可能不一样。&lt;/p&gt;
&lt;p&gt;默认情况下，dict迭代的是key。如果要迭代value，可以用&lt;code&gt;for value in d.values()&lt;/code&gt;，如果要同时迭代key和value，可以用&lt;code&gt;for k, v in d.items()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;由于字符串也是可迭代对象，因此，也可以作用于&lt;code&gt;for&lt;/code&gt;循环：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; for ch in &amp;#39;ABC&amp;#39;:
... print(ch)
...
A
B
C
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;所以，当我们使用&lt;code&gt;for&lt;/code&gt;循环时，只要作用于一个可迭代对象，&lt;code&gt;for&lt;/code&gt;循环就可以正常运行，而我们不太关心该对象究竟是list还是其他数据类型。&lt;/p&gt;
&lt;p&gt;那么，如何判断一个对象是可迭代对象呢？方法是通过collections模块的Iterable类型判断：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from collections import Iterable
&amp;gt;&amp;gt;&amp;gt; isinstance(&amp;#39;abc&amp;#39;, Iterable) # str是否可迭代
True
&amp;gt;&amp;gt;&amp;gt; isinstance([1,2,3], Iterable) # list是否可迭代
True
&amp;gt;&amp;gt;&amp;gt; isinstance(123, Iterable) # 整数是否可迭代
False
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="迭代索引"&gt;迭代索引&lt;/h4&gt;
&lt;p&gt;最后一个小问题，如果要对list实现类似Java那样的下标循环怎么办？Python内置的&lt;code&gt;enumerate&lt;/code&gt;函数可以把一个list变成索引-元素对，这样就可以在&lt;code&gt;for&lt;/code&gt;循环中同时迭代索引和元素本身：&lt;/p&gt;</description></item><item><title>Python特性之切片</title><link>/2016/03/20/python%E7%89%B9%E6%80%A7%E4%B9%8B%E5%88%87%E7%89%87/</link><pubDate>Sun, 20 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/20/python%E7%89%B9%E6%80%A7%E4%B9%8B%E5%88%87%E7%89%87/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h4 id="切片"&gt;切片&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;取一个list或tuple的部分元素是非常常见的操作。比如，一个list如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; L = [&amp;#39;Michael&amp;#39;, &amp;#39;Sarah&amp;#39;, &amp;#39;Tracy&amp;#39;, &amp;#39;Bob&amp;#39;, &amp;#39;Jack&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;取前3个元素，应该怎么做？&lt;/p&gt;
&lt;p&gt;笨办法：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; [L[0], L[1], L[2]]
[&amp;#39;Michael&amp;#39;, &amp;#39;Sarah&amp;#39;, &amp;#39;Tracy&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;之所以是笨办法是因为扩展一下，取前N个元素就没辙了。&lt;/p&gt;
&lt;p&gt;取前N个元素，也就是索引为0-(N-1)的元素，可以用循环：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; r = []
&amp;gt;&amp;gt;&amp;gt; n = 3
&amp;gt;&amp;gt;&amp;gt; for i in range(n):
... r.append(L[i])
...
&amp;gt;&amp;gt;&amp;gt; r
[&amp;#39;Michael&amp;#39;, &amp;#39;Sarah&amp;#39;, &amp;#39;Tracy&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对这种经常取指定索引范围的操作，用循环十分繁琐，因此，Python提供了切片（Slice）操作符，能大大简化这种操作。&lt;/p&gt;
&lt;p&gt;对应上面的问题，取前3个元素，用一行代码就可以完成切片：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; L[0:3]
[&amp;#39;Michael&amp;#39;, &amp;#39;Sarah&amp;#39;, &amp;#39;Tracy&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;L[0:3]&lt;/code&gt;表示，从索引&lt;code&gt;0&lt;/code&gt;开始取，直到索引&lt;code&gt;3&lt;/code&gt;为止，但不包括索引&lt;code&gt;3&lt;/code&gt;。即索引&lt;code&gt;0&lt;/code&gt;，&lt;code&gt;1&lt;/code&gt;，&lt;code&gt;2&lt;/code&gt;，正好是3个元素。&lt;/p&gt;
&lt;p&gt;如果第一个索引是&lt;code&gt;0&lt;/code&gt;，还可以省略：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; L[:3]
[&amp;#39;Michael&amp;#39;, &amp;#39;Sarah&amp;#39;, &amp;#39;Tracy&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;也可以从索引1开始，取出2个元素出来：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; L[1:3]
[&amp;#39;Sarah&amp;#39;, &amp;#39;Tracy&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;类似的，既然Python支持&lt;code&gt;L[-1]&lt;/code&gt;取倒数第一个元素，那么它同样支持倒数切片，试试：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; L[-2:]
[&amp;#39;Bob&amp;#39;, &amp;#39;Jack&amp;#39;]
&amp;gt;&amp;gt;&amp;gt; L[-2:-1]
[&amp;#39;Bob&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;记住倒数第一个元素的索引是&lt;code&gt;-1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;切片操作十分有用。我们先创建一个0-99的数列：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; L = list(range(100))
&amp;gt;&amp;gt;&amp;gt; L
[0, 1, 2, 3, ..., 99]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以通过切片轻松取出某一段数列。比如前10个数：&lt;/p&gt;</description></item><item><title>Python函数的参数</title><link>/2016/03/16/python%E5%87%BD%E6%95%B0%E7%9A%84%E5%8F%82%E6%95%B0/</link><pubDate>Wed, 16 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/16/python%E5%87%BD%E6%95%B0%E7%9A%84%E5%8F%82%E6%95%B0/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="函数的参数"&gt;函数的参数&lt;/h3&gt;
&lt;p&gt;定义函数的时候，我们把参数的名字和位置确定下来，函数的接口定义就完成了。对于函数的调用者来说，只需要知道如何传递正确的参数，以及函数将返回什么样的值就够了，函数内部的复杂逻辑被封装起来，调用者无需了解。&lt;/p&gt;
&lt;p&gt;Python的函数定义非常简单，但灵活度却非常大。除了正常定义的必选参数外，还可以使用默认参数、可变参数和关键字参数，使得函数定义出来的接口，不但能处理复杂的参数，还可以简化调用者的代码。&lt;/p&gt;
&lt;h3 id="位置参数"&gt;位置参数&lt;/h3&gt;
&lt;p&gt;我们先写一个计算x^2^的函数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def power(x):
return x * x
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对于&lt;code&gt;power(x)&lt;/code&gt;函数，参数&lt;code&gt;x&lt;/code&gt;就是一个位置参数。&lt;/p&gt;
&lt;p&gt;当我们调用&lt;code&gt;power&lt;/code&gt;函数时，必须传入有且仅有的一个参数&lt;code&gt;x&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; power(5)
25
&amp;gt;&amp;gt;&amp;gt; power(15)
225
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在，如果我们要计算x^3^怎么办？可以再定义一个&lt;code&gt;power3&lt;/code&gt;函数，但是如果要计算x^4^、x^5^……怎么办？我们不可能定义无限多个函数。&lt;/p&gt;
&lt;p&gt;你也许想到了，可以把&lt;code&gt;power(x)&lt;/code&gt;修改为&lt;code&gt;power(x, n)&lt;/code&gt;，用来计算x^n^，说干就干：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;def power(x, n):
s = 1
while n &amp;gt; 0:
n = n - 1
s = s * x
return s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对于这个修改后的&lt;code&gt;power(x, n)&lt;/code&gt;函数，可以计算任意n次方：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; power(5, 2)
25
&amp;gt;&amp;gt;&amp;gt; power(5, 3)
125
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;修改后的&lt;code&gt;power(x, n)&lt;/code&gt;函数有两个参数：&lt;code&gt;x&lt;/code&gt;和&lt;code&gt;n&lt;/code&gt;，这两个参数都是位置参数，调用函数时，传入的两个值按照位置顺序依次赋给参数&lt;code&gt;x&lt;/code&gt;和&lt;code&gt;n&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="默认参数"&gt;默认参数&lt;/h3&gt;
&lt;p&gt;新的&lt;code&gt;power(x, n)&lt;/code&gt;函数定义没有问题，但是，旧的调用代码失败了，原因是我们增加了一个参数，导致旧的代码因为缺少一个参数而无法正常调用：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; power(5)
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
TypeError: power() missing 1 required positional argument: &amp;#39;n&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Python的错误信息很明确：调用函数&lt;code&gt;power()&lt;/code&gt;缺少了一个位置参数&lt;code&gt;n&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>Python函数的使用</title><link>/2016/03/14/python%E5%87%BD%E6%95%B0%E7%9A%84%E4%BD%BF%E7%94%A8/</link><pubDate>Mon, 14 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/14/python%E5%87%BD%E6%95%B0%E7%9A%84%E4%BD%BF%E7%94%A8/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="调用函数"&gt;调用函数&lt;/h3&gt;
&lt;p&gt;Python内置了很多有用的函数，我们可以直接调用。&lt;/p&gt;
&lt;p&gt;要调用一个函数，需要知道函数的名称和参数，比如求绝对值的函数&lt;code&gt;abs&lt;/code&gt;，只有一个参数。可以直接从Python的官方网站查看文档：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://docs.python.org/3/library/functions.html#abs"&gt;http://docs.python.org/3/library/functions.html#abs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;也可以在交互式命令行通过&lt;code&gt;help(abs)&lt;/code&gt;查看&lt;code&gt;abs&lt;/code&gt;函数的帮助信息。&lt;/p&gt;
&lt;p&gt;调用&lt;code&gt;abs&lt;/code&gt;函数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; abs(100)
100
&amp;gt;&amp;gt;&amp;gt; abs(-20)
20
&amp;gt;&amp;gt;&amp;gt; abs(12.34)
12.34
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;调用函数的时候，如果传入的参数数量不对，会报&lt;code&gt;TypeError&lt;/code&gt;的错误，并且Python会明确地告诉你：&lt;code&gt;abs()&lt;/code&gt;有且仅有1个参数，但给出了两个：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; abs(1, 2)
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
TypeError: abs() takes exactly one argument (2 given)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果传入的参数数量是对的，但参数类型不能被函数所接受，也会报&lt;code&gt;TypeError&lt;/code&gt;的错误，并且给出错误信息：&lt;code&gt;str&lt;/code&gt;是错误的参数类型：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; abs(&amp;#39;a&amp;#39;)
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
TypeError: bad operand type for abs(): &amp;#39;str&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;而&lt;code&gt;max&lt;/code&gt;函数&lt;code&gt;max()&lt;/code&gt;可以接收任意多个参数，并返回最大的那个：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; max(1, 2)
2
&amp;gt;&amp;gt;&amp;gt; max(2, 3, 1, -5)
3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;###数据类型转换&lt;/p&gt;</description></item><item><title>Python字典dict和集set</title><link>/2016/03/02/python%E5%AD%97%E5%85%B8dict%E5%92%8C%E9%9B%86set/</link><pubDate>Wed, 02 Mar 2016 00:00:00 +0000</pubDate><guid>/2016/03/02/python%E5%AD%97%E5%85%B8dict%E5%92%8C%E9%9B%86set/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="dict"&gt;dict&lt;/h3&gt;
&lt;p&gt;Python内置了字典：dict的支持，dict全称dictionary，在其他语言中也称为map，使用键-值（key-value）存储，具有极快的查找速度。&lt;/p&gt;
&lt;p&gt;举个例子，假设要根据同学的名字查找对应的成绩，如果用list实现，需要两个list：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;names = [&amp;#39;Michael&amp;#39;, &amp;#39;Bob&amp;#39;, &amp;#39;Tracy&amp;#39;]
scores = [95, 75, 85]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;给定一个名字，要查找对应的成绩，就先要在names中找到对应的位置，再从scores取出对应的成绩，list越长，耗时越长。&lt;/p&gt;
&lt;p&gt;如果用dict实现，只需要一个“名字”-“成绩”的对照表，直接根据名字查找成绩，无论这个表有多大，查找速度都不会变慢。用Python写一个dict如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; d = {&amp;#39;Michael&amp;#39;: 95, &amp;#39;Bob&amp;#39;: 75, &amp;#39;Tracy&amp;#39;: 85}
&amp;gt;&amp;gt;&amp;gt; d[&amp;#39;Michael&amp;#39;]
95
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;为什么dict查找速度这么快？因为dict的实现原理和查字典是一样的。假设字典包含了1万个汉字，我们要查某一个字，一个办法是把字典从第一页往后翻，直到找到我们想要的字为止，这种方法就是在list中查找元素的方法，list越大，查找越慢。&lt;/p&gt;
&lt;p&gt;第二种方法是先在字典的索引表里（比如部首表）查这个字对应的页码，然后直接翻到该页，找到这个字。无论找哪个字，这种查找速度都非常快，不会随着字典大小的增加而变慢。&lt;/p&gt;
&lt;p&gt;dict就是第二种实现方式，给定一个名字，比如&lt;code&gt;'Michael'&lt;/code&gt;，dict在内部就可以直接计算出&lt;code&gt;Michael&lt;/code&gt;对应的存放成绩的“页码”，也就是&lt;code&gt;95&lt;/code&gt;这个数字存放的内存地址，直接取出来，所以速度非常快。&lt;/p&gt;
&lt;p&gt;你可以猜到，这种key-value存储方式，在放进去的时候，必须根据key算出value的存放位置，这样，取的时候才能根据key直接拿到value。&lt;/p&gt;
&lt;p&gt;把数据放入dict的方法，除了初始化时指定外，还可以通过key放入：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; d[&amp;#39;Adam&amp;#39;] = 67
&amp;gt;&amp;gt;&amp;gt; d[&amp;#39;Adam&amp;#39;]
67
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由于一个key只能对应一个value，所以，多次对一个key放入value，后面的值会把前面的值冲掉：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; d[&amp;#39;Jack&amp;#39;] = 90
&amp;gt;&amp;gt;&amp;gt; d[&amp;#39;Jack&amp;#39;]
90
&amp;gt;&amp;gt;&amp;gt; d[&amp;#39;Jack&amp;#39;] = 88
&amp;gt;&amp;gt;&amp;gt; d[&amp;#39;Jack&amp;#39;]
88
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果key不存在，dict就会报错：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; d[&amp;#39;Thomas&amp;#39;]
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
KeyError: &amp;#39;Thomas&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;要避免key不存在的错误，有两种办法，一是通过&lt;code&gt;in&lt;/code&gt;判断key是否存在：&lt;/p&gt;</description></item><item><title>Python判断和循环</title><link>/2016/02/28/python%E5%88%A4%E6%96%AD%E5%92%8C%E5%BE%AA%E7%8E%AF/</link><pubDate>Sun, 28 Feb 2016 00:00:00 +0000</pubDate><guid>/2016/02/28/python%E5%88%A4%E6%96%AD%E5%92%8C%E5%BE%AA%E7%8E%AF/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="条件判断"&gt;条件判断&lt;/h3&gt;
&lt;p&gt;计算机之所以能做很多自动化的任务，因为它可以自己做条件判断。&lt;/p&gt;
&lt;p&gt;比如，输入用户年龄，根据年龄打印不同的内容，在Python程序中，用&lt;code&gt;if&lt;/code&gt;语句实现：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;age = 20
if age &amp;gt;= 18:
print(&amp;#39;your age is&amp;#39;, age)
print(&amp;#39;adult&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;根据Python的缩进规则，如果&lt;code&gt;if&lt;/code&gt;语句判断是&lt;code&gt;True&lt;/code&gt;，就把缩进的两行print语句执行了，否则，什么也不做。&lt;/p&gt;
&lt;p&gt;也可以给&lt;code&gt;if&lt;/code&gt;添加一个&lt;code&gt;else&lt;/code&gt;语句，意思是，如果&lt;code&gt;if&lt;/code&gt;判断是&lt;code&gt;False&lt;/code&gt;，不要执行&lt;code&gt;if&lt;/code&gt;的内容，去把&lt;code&gt;else&lt;/code&gt;执行了：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;age = 3
if age &amp;gt;= 18:
print(&amp;#39;your age is&amp;#39;, age)
print(&amp;#39;adult&amp;#39;)
else:
print(&amp;#39;your age is&amp;#39;, age)
print(&amp;#39;teenager&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意不要少写了冒号&lt;code&gt;:&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;当然上面的判断是很粗略的，完全可以用&lt;code&gt;elif&lt;/code&gt;做更细致的判断：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;age = 3
if age &amp;gt;= 18:
print(&amp;#39;adult&amp;#39;)
elif age &amp;gt;= 6:
print(&amp;#39;teenager&amp;#39;)
else:
print(&amp;#39;kid&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;elif&lt;/code&gt;是&lt;code&gt;else if&lt;/code&gt;的缩写，完全可以有多个&lt;code&gt;elif&lt;/code&gt;，所以&lt;code&gt;if&lt;/code&gt;语句的完整形式就是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;if &amp;lt;条件判断1&amp;gt;:
&amp;lt;执行1&amp;gt;
elif &amp;lt;条件判断2&amp;gt;:
&amp;lt;执行2&amp;gt;
elif &amp;lt;条件判断3&amp;gt;:
&amp;lt;执行3&amp;gt;
else:
&amp;lt;执行4&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;if&lt;/code&gt;语句执行有个特点，它是从上往下判断，如果在某个判断上是&lt;code&gt;True&lt;/code&gt;，把该判断对应的语句执行后，就忽略掉剩下的&lt;code&gt;elif&lt;/code&gt;和&lt;code&gt;else&lt;/code&gt;，所以，请测试并解释为什么下面的程序打印的是&lt;code&gt;teenager&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;age = 20
if age &amp;gt;= 6:
print(&amp;#39;teenager&amp;#39;)
elif age &amp;gt;= 18:
print(&amp;#39;adult&amp;#39;)
else:
print(&amp;#39;kid&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;if&lt;/code&gt;判断条件还可以简写，比如写：&lt;/p&gt;</description></item><item><title>Python列表list和元组tuple</title><link>/2016/02/27/python%E5%88%97%E8%A1%A8list%E5%92%8C%E5%85%83%E7%BB%84tuple/</link><pubDate>Sat, 27 Feb 2016 00:00:00 +0000</pubDate><guid>/2016/02/27/python%E5%88%97%E8%A1%A8list%E5%92%8C%E5%85%83%E7%BB%84tuple/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="list"&gt;list&lt;/h3&gt;
&lt;p&gt;Python内置的一种数据类型是列表：list。list是一种有序的集合，可以随时添加和删除其中的元素。&lt;/p&gt;
&lt;p&gt;比如，列出班里所有同学的名字，就可以用一个list表示：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; classmates = [&amp;#39;Michael&amp;#39;, &amp;#39;Bob&amp;#39;, &amp;#39;Tracy&amp;#39;]
&amp;gt;&amp;gt;&amp;gt; classmates
[&amp;#39;Michael&amp;#39;, &amp;#39;Bob&amp;#39;, &amp;#39;Tracy&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;变量&lt;code&gt;classmates&lt;/code&gt;就是一个list。用&lt;code&gt;len()&lt;/code&gt;函数可以获得list元素的个数：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; len(classmates)
3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;用索引来访问list中每一个位置的元素，记得索引是从&lt;code&gt;0&lt;/code&gt;开始的：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; classmates[0]
&amp;#39;Michael&amp;#39;
&amp;gt;&amp;gt;&amp;gt; classmates[1]
&amp;#39;Bob&amp;#39;
&amp;gt;&amp;gt;&amp;gt; classmates[2]
&amp;#39;Tracy&amp;#39;
&amp;gt;&amp;gt;&amp;gt; classmates[3]
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
IndexError: list index out of range
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当索引超出了范围时，Python会报一个&lt;code&gt;IndexError&lt;/code&gt;错误，所以，要确保索引不要越界，记得最后一个元素的索引是&lt;code&gt;len(classmates) - 1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果要取最后一个元素，除了计算索引位置外，还可以用&lt;code&gt;-1&lt;/code&gt;做索引，直接获取最后一个元素：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; classmates[-1]
&amp;#39;Tracy&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以此类推，可以获取倒数第2个、倒数第3个：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; classmates[-2]
&amp;#39;Bob&amp;#39;
&amp;gt;&amp;gt;&amp;gt; classmates[-3]
&amp;#39;Michael&amp;#39;
&amp;gt;&amp;gt;&amp;gt; classmates[-4]
Traceback (most recent call last):
File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
IndexError: list index out of range
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当然，倒数第4个就越界了。&lt;/p&gt;</description></item><item><title>Python字符串和编码</title><link>/2016/02/26/python%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E7%BC%96%E7%A0%81/</link><pubDate>Fri, 26 Feb 2016 00:00:00 +0000</pubDate><guid>/2016/02/26/python%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E7%BC%96%E7%A0%81/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h3 id="字符编码"&gt;字符编码&lt;/h3&gt;
&lt;p&gt;我们已经讲过了，字符串也是一种数据类型，但是，字符串比较特殊的是还有一个编码问题。&lt;/p&gt;
&lt;p&gt;因为计算机只能处理数字，如果要处理文本，就必须先把文本转换为数字才能处理。最早的计算机在设计时采用8个比特（bit）作为一个字节（byte），所以，一个字节能表示的最大的整数就是255（二进制11111111=十进制255），如果要表示更大的整数，就必须用更多的字节。比如两个字节可以表示的最大整数是&lt;code&gt;65535&lt;/code&gt;，4个字节可以表示的最大整数是&lt;code&gt;4294967295&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;由于计算机是美国人发明的，因此，最早只有127个字符被编码到计算机里，也就是大小写英文字母、数字和一些符号，这个编码表被称为&lt;code&gt;ASCII&lt;/code&gt;编码，比如大写字母&lt;code&gt;A&lt;/code&gt;的编码是&lt;code&gt;65&lt;/code&gt;，小写字母&lt;code&gt;z&lt;/code&gt;的编码是&lt;code&gt;122&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;但是要处理中文显然一个字节是不够的，至少需要两个字节，而且还不能和ASCII编码冲突，所以，中国制定了&lt;code&gt;GB2312&lt;/code&gt;编码，用来把中文编进去。&lt;/p&gt;
&lt;p&gt;你可以想得到的是，全世界有上百种语言，日本把日文编到&lt;code&gt;Shift_JIS&lt;/code&gt;里，韩国把韩文编到&lt;code&gt;Euc-kr&lt;/code&gt;里，各国有各国的标准，就会不可避免地出现冲突，结果就是，在多语言混合的文本中，显示出来会有乱码。&lt;/p&gt;
&lt;p&gt;&lt;img alt="char-encoding-problem" loading="lazy" src="0"&gt;&lt;/p&gt;
&lt;p&gt;因此，Unicode应运而生。Unicode把所有语言都统一到一套编码里，这样就不会再有乱码问题了。&lt;/p&gt;
&lt;p&gt;Unicode标准也在不断发展，但最常用的是用两个字节表示一个字符（如果要用到非常偏僻的字符，就需要4个字节）。现代操作系统和大多数编程语言都直接支持Unicode。&lt;/p&gt;
&lt;p&gt;现在，捋一捋ASCII编码和Unicode编码的区别：ASCII编码是1个字节，而Unicode编码通常是2个字节。&lt;/p&gt;
&lt;p&gt;字母&lt;code&gt;A&lt;/code&gt;用ASCII编码是十进制的&lt;code&gt;65&lt;/code&gt;，二进制的&lt;code&gt;01000001&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;字符&lt;code&gt;0&lt;/code&gt;用ASCII编码是十进制的&lt;code&gt;48&lt;/code&gt;，二进制的&lt;code&gt;00110000&lt;/code&gt;，注意字符&lt;code&gt;'0'&lt;/code&gt;和整数&lt;code&gt;0&lt;/code&gt;是不同的；&lt;/p&gt;
&lt;p&gt;汉字&lt;code&gt;中&lt;/code&gt;已经超出了ASCII编码的范围，用Unicode编码是十进制的&lt;code&gt;20013&lt;/code&gt;，二进制的&lt;code&gt;01001110 00101101&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;你可以猜测，如果把ASCII编码的&lt;code&gt;A&lt;/code&gt;用Unicode编码，只需要在前面补0就可以，因此，&lt;code&gt;A&lt;/code&gt;的Unicode编码是&lt;code&gt;00000000 01000001&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;新的问题又出现了：如果统一成Unicode编码，乱码问题从此消失了。但是，如果你写的文本基本上全部是英文的话，用Unicode编码比ASCII编码需要多一倍的存储空间，在存储和传输上就十分不划算。&lt;/p&gt;
&lt;p&gt;所以，本着节约的精神，又出现了把Unicode编码转化为“可变长编码”的&lt;code&gt;UTF-8&lt;/code&gt;编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节，常用的英文字母被编码成1个字节，汉字通常是3个字节，只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符，用UTF-8编码就能节省空间：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字符&lt;/th&gt;
&lt;th&gt;ASCII&lt;/th&gt;
&lt;th&gt;Unicode&lt;/th&gt;
&lt;th&gt;UTF-8&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;01000001&lt;/td&gt;
&lt;td&gt;00000000 01000001&lt;/td&gt;
&lt;td&gt;01000001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;中&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;01001110 00101101&lt;/td&gt;
&lt;td&gt;11100100 10111000 10101101&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;从上面的表格还可以发现，UTF-8编码有一个额外的好处，就是ASCII编码实际上可以被看成是UTF-8编码的一部分，所以，大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。&lt;/p&gt;
&lt;p&gt;搞清楚了ASCII、Unicode和UTF-8的关系，我们就可以总结一下现在计算机系统通用的字符编码工作方式：&lt;/p&gt;
&lt;p&gt;在计算机内存中，统一使用Unicode编码，当需要保存到硬盘或者需要传输的时候，就转换为UTF-8编码。&lt;/p&gt;
&lt;p&gt;用记事本编辑的时候，从文件读取的UTF-8字符被转换为Unicode字符到内存里，编辑完成后，保存的时候再把Unicode转换为UTF-8保存到文件：&lt;/p&gt;
&lt;p&gt;&lt;img alt="rw-file-utf-8" loading="lazy" src="0"&gt;&lt;/p&gt;
&lt;p&gt;浏览网页的时候，服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器：&lt;/p&gt;
&lt;p&gt;&lt;img alt="web-utf-8" loading="lazy" src="0"&gt;&lt;/p&gt;
&lt;p&gt;所以你看到很多网页的源码上会有类似&lt;code&gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;gt;&lt;/code&gt;的信息，表示该网页正是用的UTF-8编码。&lt;/p&gt;
&lt;h3 id="python的字符串"&gt;Python的字符串&lt;/h3&gt;
&lt;p&gt;搞清楚了令人头疼的字符编码问题后，我们再来研究Python的字符串。&lt;/p&gt;
&lt;p&gt;在最新的Python 3版本中，字符串是以Unicode编码的，也就是说，Python的字符串支持多语言，例如：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print(&amp;#39;包含中文的str&amp;#39;)
包含中文的str
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对于单个字符的编码，Python提供了&lt;code&gt;ord()&lt;/code&gt;函数获取字符的整数表示，&lt;code&gt;chr()&lt;/code&gt;函数把编码转换为对应的字符：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; ord(&amp;#39;A&amp;#39;)
65
&amp;gt;&amp;gt;&amp;gt; chr(66)
&amp;#39;B&amp;#39;
#注意下面两个在jupyter notebook中会报错，但是在python命令行中却不会错, 看看你的locale charmap是否为utf-8
&amp;gt;&amp;gt;&amp;gt; ord(&amp;#39;中&amp;#39;)
20013
&amp;gt;&amp;gt;&amp;gt; chr(25991)
&amp;#39;文&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果知道字符的整数编码，还可以用十六进制这么写&lt;code&gt;str&lt;/code&gt;：&lt;/p&gt;</description></item><item><title>python数据类型和变量</title><link>/2016/02/25/python%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%8F%98%E9%87%8F/</link><pubDate>Thu, 25 Feb 2016 00:00:00 +0000</pubDate><guid>/2016/02/25/python%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%8F%98%E9%87%8F/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;p&gt;在Python中，能够直接处理的数据类型有以下几种：&lt;/p&gt;
&lt;h3 id="整数"&gt;整数&lt;/h3&gt;
&lt;p&gt;Python可以处理任意大小的整数，当然包括负整数，在程序中的表示方法和数学上的写法一模一样，例如：&lt;code&gt;1&lt;/code&gt;，&lt;code&gt;100&lt;/code&gt;，&lt;code&gt;-8080&lt;/code&gt;，&lt;code&gt;0&lt;/code&gt;，等等。&lt;/p&gt;
&lt;p&gt;计算机由于使用二进制，所以，有时候用十六进制表示整数比较方便，十六进制用&lt;code&gt;0x&lt;/code&gt;前缀和0-9，a-f表示，例如：&lt;code&gt;0xff00&lt;/code&gt;，&lt;code&gt;0xa5b4c3d2&lt;/code&gt;，等等。&lt;/p&gt;
&lt;h3 id="浮点数"&gt;浮点数&lt;/h3&gt;
&lt;p&gt;浮点数也就是小数，之所以称为浮点数，是因为按照科学记数法表示时，一个浮点数的小数点位置是可变的，比如，1.23x109和12.3x108是完全相等的。浮点数可以用数学写法，如&lt;code&gt;1.23&lt;/code&gt;，&lt;code&gt;3.14&lt;/code&gt;，&lt;code&gt;-9.01&lt;/code&gt;，等等。但是对于很大或很小的浮点数，就必须用科学计数法表示，把10用e替代，1.23x109就是&lt;code&gt;1.23e9&lt;/code&gt;，或者&lt;code&gt;12.3e8&lt;/code&gt;，0.000012可以写成&lt;code&gt;1.2e-5&lt;/code&gt;，等等。&lt;/p&gt;
&lt;p&gt;整数和浮点数在计算机内部存储的方式是不同的，整数运算永远是精确的（除法难道也是精确的？是的！），而浮点数运算则可能会有四舍五入的误差。&lt;/p&gt;
&lt;h3 id="字符串"&gt;字符串&lt;/h3&gt;
&lt;p&gt;字符串是以单引号&lt;code&gt;'&lt;/code&gt;或双引号&lt;code&gt;&amp;quot;&lt;/code&gt;括起来的任意文本，比如&lt;code&gt;'abc'&lt;/code&gt;，&lt;code&gt;&amp;quot;xyz&amp;quot;&lt;/code&gt;等等。请注意，&lt;code&gt;''&lt;/code&gt;或&lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;本身只是一种表示方式，不是字符串的一部分，因此，字符串&lt;code&gt;'abc'&lt;/code&gt;只有&lt;code&gt;a&lt;/code&gt;，&lt;code&gt;b&lt;/code&gt;，&lt;code&gt;c&lt;/code&gt;这3个字符。如果&lt;code&gt;'&lt;/code&gt;本身也是一个字符，那就可以用&lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;括起来，比如&lt;code&gt;&amp;quot;I'm OK&amp;quot;&lt;/code&gt;包含的字符是&lt;code&gt;I&lt;/code&gt;，&lt;code&gt;'&lt;/code&gt;，&lt;code&gt;m&lt;/code&gt;，空格，&lt;code&gt;O&lt;/code&gt;，&lt;code&gt;K&lt;/code&gt;这6个字符。&lt;/p&gt;
&lt;p&gt;如果字符串内部既包含&lt;code&gt;'&lt;/code&gt;又包含&lt;code&gt;&amp;quot;&lt;/code&gt;怎么办？可以用转义字符&lt;code&gt;\&lt;/code&gt;来标识，比如：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;#39;I\&amp;#39;m \&amp;#34;OK\&amp;#34;!&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;表示的字符串内容是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;I&amp;#39;m &amp;#34;OK&amp;#34;!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;转义字符&lt;code&gt;\&lt;/code&gt;可以转义很多字符，比如&lt;code&gt;\n&lt;/code&gt;表示换行，&lt;code&gt;\t&lt;/code&gt;表示制表符，字符&lt;code&gt;\&lt;/code&gt;本身也要转义，所以&lt;code&gt;\\&lt;/code&gt;表示的字符就是&lt;code&gt;\&lt;/code&gt;，可以在Python的交互式命令行用&lt;code&gt;print()&lt;/code&gt;打印字符串看看：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print(&amp;#39;I\&amp;#39;m ok.&amp;#39;)
I&amp;#39;m ok.
&amp;gt;&amp;gt;&amp;gt; print(&amp;#39;I\&amp;#39;m learning\nPython.&amp;#39;)
I&amp;#39;m learning
Python.
&amp;gt;&amp;gt;&amp;gt; print(&amp;#39;\\\n\\&amp;#39;)
\
\
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果字符串里面有很多字符都需要转义，就需要加很多&lt;code&gt;\&lt;/code&gt;，为了简化，Python还允许用&lt;code&gt;r''&lt;/code&gt;表示&lt;code&gt;''&lt;/code&gt;内部的字符串默认不转义，可以自己试试：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print(&amp;#39;\\\t\\&amp;#39;)
\ \
&amp;gt;&amp;gt;&amp;gt; print(r&amp;#39;\\\t\\&amp;#39;)
\\\t\\
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果字符串内部有很多换行，用&lt;code&gt;\n&lt;/code&gt;写在一行里不好阅读，为了简化，Python允许用&lt;code&gt;'''...'''&lt;/code&gt;的格式表示多行内容，可以自己试试：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print(&amp;#39;&amp;#39;&amp;#39;line1
... line2
... line3&amp;#39;&amp;#39;&amp;#39;)
line1
line2
line3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上面是在交互式命令行内输入，注意在输入多行内容时，提示符由&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;变为&lt;code&gt;...&lt;/code&gt;，提示你可以接着上一行输入，注意&lt;code&gt;...&lt;/code&gt;是提示符，不是代码的一部分：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌────────────────────────────────────────────────────────┐
│Command Prompt - python _ □ x │
├────────────────────────────────────────────────────────┤
│&amp;gt;&amp;gt;&amp;gt; print(&amp;#39;&amp;#39;&amp;#39;line1 │
│... line2 │
│... line3&amp;#39;&amp;#39;&amp;#39;) │
│line1 │
│line2 │
│line3 │
│ │
│&amp;gt;&amp;gt;&amp;gt; _
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当输入完结束符```` &lt;code&gt;和括号&lt;/code&gt;)`后，执行该语句并打印结果。&lt;/p&gt;</description></item><item><title>Python基础</title><link>/2016/02/24/python%E5%9F%BA%E7%A1%80/</link><pubDate>Wed, 24 Feb 2016 00:00:00 +0000</pubDate><guid>/2016/02/24/python%E5%9F%BA%E7%A1%80/</guid><description>&lt;!-- toc --&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h1 id="python简介"&gt;Python简介&lt;/h1&gt;
&lt;p&gt;Python由荷兰数学和计算机科学研究学会的Guido van Rossum 于1990 年代初设计，作为一门叫做ABC语言的替代品。Python提供了高效的高级数据结构，还能简单有效地面向对象编程。Python语法和动态类型，以及解释型语言的本质，使它成为多数平台上写脚本和快速开发应用的编程语言，随着版本的不断更新和语言新功能的添加，逐渐被用于独立的、大型项目的开发。
Python解释器易于扩展，可以使用C或C++（或者其他可以通过C调用的语言）扩展新的功能和数据类型。Python 也可用于可定制化软件中的扩展程序语言。Python丰富的标准库，提供了适用于各个主要系统平台的源码或机器码。&lt;/p&gt;
&lt;p&gt;Python的语法比较简单，采用缩进方式，写出来的代码就像下面的样子：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# print absolute value of an integer:
a = 100
if a &amp;gt;= 0:
print(a)
else:
print(-a)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以&lt;code&gt;#&lt;/code&gt;开头的语句是注释，注释是给人看的，可以是任意内容，解释器会忽略掉注释。其他每一行都是一个语句，当语句以冒号&lt;code&gt;:&lt;/code&gt;结尾时，缩进的语句视为代码块。&lt;/p&gt;
&lt;p&gt;缩进有利有弊。好处是强迫你写出格式化的代码，但没有规定缩进是几个空格还是Tab。按照约定俗成的管理，应该始终坚持使用4个空格的缩进。&lt;/p&gt;
&lt;p&gt;缩进的另一个好处是强迫你写出缩进较少的代码，你会倾向于把一段很长的代码拆分成若干函数，从而得到缩进较少的代码。&lt;/p&gt;
&lt;p&gt;缩进的坏处就是“复制－粘贴”功能失效了，这是最坑爹的地方。当你重构代码时，粘贴过去的代码必须重新检查缩进是否正确。此外，IDE很难像格式化Java代码那样格式化Python代码。&lt;/p&gt;
&lt;p&gt;最后，请务必注意，Python程序是大小写敏感的，如果写错了大小写，程序会报错。&lt;/p&gt;</description></item></channel></rss>