-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
169 lines (99 loc) · 145 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>npm安装后模块后在node_modules找不到Cannot find in node_modules</title>
<link href="/2018/09/06/npm%E5%AE%89%E8%A3%85%E6%A8%A1%E5%9D%97%E5%90%8E%E5%9C%A8node-modules%E6%89%BE%E4%B8%8D%E5%88%B0cant%20find%20in%20node_modules/"/>
<url>/2018/09/06/npm%E5%AE%89%E8%A3%85%E6%A8%A1%E5%9D%97%E5%90%8E%E5%9C%A8node-modules%E6%89%BE%E4%B8%8D%E5%88%B0cant%20find%20in%20node_modules/</url>
<content type="html"><![CDATA[<h4 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h4><p>最近通过npm安装mocha,运行命令提示 『 Error: Cannot find test framework “mocha” in /Users/xxx/node_modules 』,这时候看node_modules文件夹下确实没有<strong>mocha</strong><br><a id="more"></a></p><h4 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h4><p>我们可以通过在node_modules文件夹里增加全局模块的快捷方式或者链接,解决方法如下:</p><blockquote><p>npm link mocha</p></blockquote><p>OK,正常啦</p><p><section style="text-align: center; font-size: 1em; font-weight: inherit; text-decoration: inherit; color: rgb(255, 255, 255); border-color: rgb(117, 117, 118); box-sizing: border-box;"><section data-width="2em" style="width: 2em; height: 2em; margin-right: auto; margin-left: auto; border-radius: 100%; box-sizing: border-box; background-color: rgb(117, 117, 118);"><section style="display: inline-block; padding-right: 0.5em; padding-left: 0.5em; font-size: 1em; line-height: 2; box-sizing: border-box; color: inherit;"><section class="135brush" data-brushtype="text" style="box-sizing: border-box; color: inherit;">完</section></section></section><section style="margin-top: -1em; margin-bottom: 1em; box-sizing: border-box; color: inherit;"><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: left; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: right; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section></section></section><br><br></p>]]></content>
<tags>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>使用 supervisor 管理进程</title>
<link href="/2018/09/04/%E4%BD%BF%E7%94%A8-supervisor-%E7%AE%A1%E7%90%86%E8%BF%9B%E7%A8%8B/"/>
<url>/2018/09/04/%E4%BD%BF%E7%94%A8-supervisor-%E7%AE%A1%E7%90%86%E8%BF%9B%E7%A8%8B/</url>
<content type="html"><![CDATA[<blockquote><p>Supervisor (<a href="http://supervisord.org/" target="_blank" rel="noopener">http://supervisord.org</a>) 是一个用 Python 写的进程管理工具,可以很方便的用来启动、重启、关闭进程(不仅仅是 Python 进程)。除了对单个进程的控制,还可以同时启动、关闭多个进程,比如很不幸的服务器出问题导致所有应用程序都被杀死,此时可以用 supervisor 同时启动所有应用程序而不是一个一个地敲命令启动。<br><a id="more"></a></p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>Supervisor 可以运行在 Linux、Mac OS X 上。如前所述,supervisor 是 Python 编写的,所以安装起来也很方便,可以直接用 pip :</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> sudo pip install supervisor</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><p>如果是 Ubuntu 系统,还可以使用 apt-get 安装。</p><h2 id="supervisord-配置"><a href="#supervisord-配置" class="headerlink" title="supervisord 配置"></a>supervisord 配置</h2><p>Supervisor 相当强大,提供了很丰富的功能,不过我们可能只需要用到其中一小部分。安装完成之后,可以编写配置文件,来满足自己的需求。为了方便,我们把配置分成两部分:supervisord(supervisor 是一个 C/S 模型的程序,这是 server 端,对应的有 client 端:supervisorctl)和应用程序(即我们要管理的程序)。</p><p>首先来看 supervisord 的配置文件。安装完 supervisor 之后,可以运行<code>echo_supervisord_conf</code> 命令输出默认的配置项,也可以重定向到一个配置文件里:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> echo_supervisord_conf > /etc/supervisord.conf</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><p>去除里面大部分注释和“不相关”的部分,我们可以先看这些配置:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">> [unix_http_server]</span><br><span class="line">> file=/tmp/supervisor.sock ; UNIX socket 文件,supervisorctl 会使用</span><br><span class="line">> ;chmod=0700 ; socket 文件的 mode,默认是 0700</span><br><span class="line">> ;chown=nobody:nogroup ; socket 文件的 owner,格式: uid:gid</span><br><span class="line">> </span><br><span class="line">> ;[inet_http_server] ; HTTP 服务器,提供 web 管理界面</span><br><span class="line">> ;port=127.0.0.1:9001 ; Web 管理后台运行的 IP 和端口,如果开放到公网,需要注意安全性</span><br><span class="line">> ;username=user ; 登录管理后台的用户名</span><br><span class="line">> ;password=123 ; 登录管理后台的密码</span><br><span class="line">> </span><br><span class="line">> [supervisord]</span><br><span class="line">> logfile=/tmp/supervisord.log ; 日志文件,默认是 $CWD/supervisord.log</span><br><span class="line">> logfile_maxbytes=50MB ; 日志文件大小,超出会 rotate,默认 50MB</span><br><span class="line">> logfile_backups=10 ; 日志文件保留备份数量默认 10</span><br><span class="line">> loglevel=info ; 日志级别,默认 info,其它: debug,warn,trace</span><br><span class="line">> pidfile=/tmp/supervisord.pid ; pid 文件</span><br><span class="line">> nodaemon=false ; 是否在前台启动,默认是 false,即以 daemon 的方式启动</span><br><span class="line">> minfds=1024 ; 可以打开的文件描述符的最小值,默认 1024</span><br><span class="line">> minprocs=200 ; 可以打开的进程数的最小值,默认 200</span><br><span class="line">> </span><br><span class="line">> ; the below section must remain in the config file for RPC</span><br><span class="line">> ; (supervisorctl/web interface) to work, additional interfaces may be</span><br><span class="line">> ; added by defining them in separate rpcinterface: sections</span><br><span class="line">> [rpcinterface:supervisor]</span><br><span class="line">> supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface</span><br><span class="line">> </span><br><span class="line">> [supervisorctl]</span><br><span class="line">> serverurl=unix:///tmp/supervisor.sock ; 通过 UNIX socket 连接 supervisord,路径与 unix_http_server 部分的 file 一致</span><br><span class="line">> ;serverurl=http://127.0.0.1:9001 ; 通过 HTTP 的方式连接 supervisord</span><br><span class="line">> </span><br><span class="line">> ; 包含其他的配置文件</span><br><span class="line">> [include]</span><br><span class="line">> files = relative/directory/*.ini ; 可以是 *.conf 或 *.ini</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><p>我们把上面这部分配置保存到 /etc/supervisord.conf(或其他任意有权限访问的文件),然后启动 supervisord(通过 -c 选项指定配置文件路径,如果不指定会按照这个顺序查找配置文件:$CWD/supervisord.conf, $CWD/etc/supervisord.conf, /etc/supervisord.conf):</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> supervisord -c /etc/supervisord.conf</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><p>查看 supervisord 是否在运行:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> ps aux | grep supervisord</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><h2 id="program-配置"><a href="#program-配置" class="headerlink" title="program 配置"></a>program 配置</h2><p>上面我们已经把 supervisrod 运行起来了,现在可以添加我们要管理的进程的配置文件。可以把所有配置项都写到 supervisord.conf 文件里,但并不推荐这样做,而是通过 include 的方式把不同的程序(组)写到不同的配置文件里。</p><p>为了举例,我们新建一个目录 /etc/supervisor/ 用于存放这些配置文件,相应的,把 /etc/supervisord.conf 里 include 部分的的配置修改一下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">> [include]</span><br><span class="line">> files = /etc/supervisor/*.conf</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><p>假设有个用 Python 和 Flask 框架编写的用户中心系统,取名 usercenter,用 gunicorn (<a href="http://gunicorn.org/" target="_blank" rel="noopener">http://gunicorn.org/</a>) 做 web 服务器。项目代码位于 <code>/home/leon/projects/usercenter</code>,gunicorn 配置文件为 <code>gunicorn.py</code>,WSGI callable 是 wsgi.py 里的 app 属性。所以直接在命令行启动的方式可能是这样的:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">> cd /home/leon/projects/usercenter</span><br><span class="line">> gunicorn -c gunicorn.py wsgi:app</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><p>现在编写一份配置文件来管理这个进程(<strong>需要注意:用 supervisord 管理时,gunicorn 的 daemon 选项需要设置为 False</strong>):</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">> [program:usercenter]</span><br><span class="line">> directory = /home/leon/projects/usercenter ; 程序的启动目录</span><br><span class="line">> command = gunicorn -c gunicorn.py wsgi:app ; 启动命令,可以看出与手动在命令行启动的命令是一样的</span><br><span class="line">> autostart = true ; 在 supervisord 启动的时候也自动启动</span><br><span class="line">> startsecs = 5 ; 启动 5 秒后没有异常退出,就当作已经正常启动了</span><br><span class="line">> autorestart = true ; 程序异常退出后自动重启</span><br><span class="line">> startretries = 3 ; 启动失败自动重试次数,默认是 3</span><br><span class="line">> user = leon ; 用哪个用户启动</span><br><span class="line">> redirect_stderr = true ; 把 stderr 重定向到 stdout,默认 false</span><br><span class="line">> stdout_logfile_maxbytes = 20MB ; stdout 日志文件大小,默认 50MB</span><br><span class="line">> stdout_logfile_backups = 20 ; stdout 日志文件备份数</span><br><span class="line">> ; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)</span><br><span class="line">> stdout_logfile = /data/logs/usercenter_stdout.log</span><br><span class="line">> </span><br><span class="line">> ; 可以通过 environment 来添加需要的环境变量,一种常见的用法是修改 PYTHONPATH</span><br><span class="line">> ; environment=PYTHONPATH=$PYTHONPATH:/path/to/somewhere</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><p>一份配置文件至少需要一个 <code>[program:x]</code> 部分的配置,来告诉 supervisord 需要管理那个进程。<code>[program:x]</code> 语法中的 <code>x</code> 表示 program name,会在客户端(supervisorctl 或 web 界面)显示,在 supervisorctl 中通过这个值来对程序进行 start、restart、stop 等操作。</p><h2 id="使用-supervisorctl"><a href="#使用-supervisorctl" class="headerlink" title="使用 supervisorctl"></a>使用 supervisorctl</h2><p>Supervisorctl 是 supervisord 的一个命令行客户端工具,启动时需要指定与 supervisord 使用同一份配置文件,否则与 supervisord 一样按照顺序查找配置文件。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> supervisorctl -c /etc/supervisord.conf</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><p>上面这个命令会进入 supervisorctl 的 shell 界面,然后可以执行不同的命令了:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">> > status # 查看程序状态</span><br><span class="line">> > stop usercenter # 关闭 usercenter 程序</span><br><span class="line">> > start usercenter # 启动 usercenter 程序</span><br><span class="line">> > restart usercenter # 重启 usercenter 程序</span><br><span class="line">> > reread # 读取有更新(增加)的配置文件,不会启动新添加的程序</span><br><span class="line">> > update # 重启配置文件修改过的程序</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><p>上面这些命令都有相应的输出,除了进入 supervisorctl 的 shell 界面,也可以直接在 bash 终端运行:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">> $ supervisorctl status</span><br><span class="line">> $ supervisorctl stop usercenter</span><br><span class="line">> $ supervisorctl start usercenter</span><br><span class="line">> $ supervisorctl restart usercenter</span><br><span class="line">> $ supervisorctl reread</span><br><span class="line">> $ supervisorctl update</span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><p>></p><blockquote><h2 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h2><p>除了 supervisorctl 之外,还可以配置 supervisrod 启动 web 管理界面,这个 web 后台使用 Basic Auth 的方式进行身份认证。</p><p>除了单个进程的控制,还可以配置 group,进行分组管理。</p><p>经常查看日志文件,包括 supervisord 的日志和各个 pragram 的日志文件,程序 crash 或抛出异常的信息一半会输出到 stderr,可以查看相应的日志文件来查找问题。</p><p>Supervisor 有很丰富的功能,还有其他很多项配置,可以在官方文档获取更多信息:<a href="http://supervisord.org/index.html" target="_blank" rel="noopener">http://supervisord.org/index.html</a></p><blockquote><p>转载自<a href="http://liyangliang.me/posts/2015/06/using-supervisor/" target="_blank" rel="noopener">李阳良的博客</a></p></blockquote></blockquote><p><section style="text-align: center; font-size: 1em; font-weight: inherit; text-decoration: inherit; color: rgb(255, 255, 255); border-color: rgb(117, 117, 118); box-sizing: border-box;"><section data-width="2em" style="width: 2em; height: 2em; margin-right: auto; margin-left: auto; border-radius: 100%; box-sizing: border-box; background-color: rgb(117, 117, 118);"><section style="display: inline-block; padding-right: 0.5em; padding-left: 0.5em; font-size: 1em; line-height: 2; box-sizing: border-box; color: inherit;"><section class="135brush" data-brushtype="text" style="box-sizing: border-box; color: inherit;">完</section></section></section><section style="margin-top: -1em; margin-bottom: 1em; box-sizing: border-box; color: inherit;"><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: left; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: right; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section></section></section><br><br></p>]]></content>
<tags>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>复制命令行输出到系统剪贴板上</title>
<link href="/2018/09/04/%E5%A4%8D%E5%88%B6%E5%91%BD%E4%BB%A4%E8%A1%8C%E8%BE%93%E5%87%BA%E5%88%B0%E7%B3%BB%E7%BB%9F%E5%89%AA%E8%B4%B4%E6%9D%BF%E4%B8%8A/"/>
<url>/2018/09/04/%E5%A4%8D%E5%88%B6%E5%91%BD%E4%BB%A4%E8%A1%8C%E8%BE%93%E5%87%BA%E5%88%B0%E7%B3%BB%E7%BB%9F%E5%89%AA%E8%B4%B4%E6%9D%BF%E4%B8%8A/</url>
<content type="html"><![CDATA[<h1 id="为什么要这么做?"><a href="#为什么要这么做?" class="headerlink" title="为什么要这么做?"></a>为什么要这么做?</h1><ul><li><p>直接把命令的输出(比如grep/awk/sed/find或是你的程序输出结果)放到剪切板上,这么就可以在IM中CTRL + V粘贴后发出去。<br>避免操作的繁琐和跳跃:把结果输出到文件、用文本编辑器打开文件、选中文本、CTRL + C。</p></li><li><p>通过命令将文件内容拷贝到剪切板,以避免拷贝错误、操作的跳跃(跳到文件编辑器)</p><a id="more"></a></li></ul><h1 id="Windows下"><a href="#Windows下" class="headerlink" title="Windows下"></a>Windows下</h1><p>使用系统自带的<code>clip</code>命令。<br># 位于<code>C:\Windows\system32\clip.exe</code>。</p><p>示例:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">echo Hello | clip</span><br><span class="line"># 将字符串Hello放入Windows剪贴板</span><br><span class="line"></span><br><span class="line">dir | clip</span><br><span class="line"># 将dir命令输出(当前目录列表)放入Windows剪贴板</span><br><span class="line"></span><br><span class="line">clip < README.TXT</span><br><span class="line"># 将readme.txt的文本放入Windows剪贴板</span><br><span class="line"></span><br><span class="line">echo | clip</span><br><span class="line"># 将一个空行放入Windows剪贴板,即清空Windows剪贴板</span><br></pre></td></tr></table></figure><h1 id="Linux下"><a href="#Linux下" class="headerlink" title="Linux下"></a>Linux下</h1><p>使用<code>xsel</code>命令。</p><p>示例:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">cat README.TXT | xsel</span><br><span class="line">cat README.TXT | xsel -b # 如有问题可以试试-b选项</span><br><span class="line">xsel < README.TXT</span><br><span class="line"># 将readme.txt的文本放入剪贴板</span><br><span class="line"></span><br><span class="line">xsel -c</span><br><span class="line"># 清空剪贴板</span><br></pre></td></tr></table></figure><h1 id="Mac下"><a href="#Mac下" class="headerlink" title="Mac下"></a>Mac下</h1><p>使用<code>pbcopy</code>命令。 # 对应有个<code>pbpaste</code>命令。</p><p>示例:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">echo 'Hello World!' | pbcopy</span><br><span class="line"># 将字符串Hello World放入剪贴板</span><br></pre></td></tr></table></figure><h1 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h1><h2 id="要复制结果又想看到命令的输出"><a href="#要复制结果又想看到命令的输出" class="headerlink" title="要复制结果又想看到命令的输出"></a>要复制结果又想看到命令的输出</h2><p>命令的结果输出时,如果给复制命令(即上面提到的命令clip、xsel、pbcopy)那么命令输出就看不到了。如果你想先看到命令的输出,可以下面这么做。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ echo 'Hello World!' | tee tmp.file.txt</span><br><span class="line">Hello World!</span><br><span class="line">$ xsel < tmp.file.txt</span><br><span class="line">$ rm tmp.file.txt</span><br></pre></td></tr></table></figure><p>即先使用<code>tee</code>命令把输出输到控制台和一个文件中。</p><p>命令执行完成后,再把输出的内容放到剪贴板中。</p><h2 id="复制SSH的公有KEY"><a href="#复制SSH的公有KEY" class="headerlink" title="复制SSH的公有KEY"></a>复制SSH的公有KEY</h2><p>使用下面的命令:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ pbcopy < ~/.ssh/id_rsa.pub</span><br></pre></td></tr></table></figure><p>注:不同系统使用不同的复制命令</p><p>避免用文本编辑器打开这个文件、选中文本、CTRL + C这样繁琐操作。</p><h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><ul><li><a href="http://www.cnblogs.com/mattmonkey/archive/2011/08/20/2301554.html" target="_blank" rel="noopener">Windows下把命令行结果存放在剪贴板</a></li><li><a href="http://linux.die.net/man/1/xsel" target="_blank" rel="noopener">xsel(1) - Linux man page</a></li><li><a href="http://www.worldhello.net/gotgithub/02-join-github/010-account-setup.html#id4" target="_blank" rel="noopener">命令行下可直接用pbcopy命令将文件内容拷贝到剪切板以避免拷贝错误</a></li><li><a href="http://langui.sh/2010/11/14/pbpaste-pbcopy-in-mac-os-x-or-terminal-clipboard-fun/" target="_blank" rel="noopener">pbpaste & pbcopy in Mac OS X (or: Terminal + Clipboard = Fun!)</a></li></ul><h1 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h1><p>还在用的Windows、吐槽弱暴命令行cmd的程序猿们,推荐使用<a href="http://www.cygwin.com/" target="_blank" rel="noopener">cygwin</a>,可以看看我的博文<a href="http://oldratlee.com/post/2012-12-22/stunning-cygwin" target="_blank" rel="noopener">惊艳的cygwin——Windows下的Linux命令行环境</a>。</p><blockquote><p>转载自<a href="http://oldratlee.com/" target="_blank" rel="noopener">李鼎的博客</a></p></blockquote><p><section style="text-align: center; font-size: 1em; font-weight: inherit; text-decoration: inherit; color: rgb(255, 255, 255); border-color: rgb(117, 117, 118); box-sizing: border-box;"><section data-width="2em" style="width: 2em; height: 2em; margin-right: auto; margin-left: auto; border-radius: 100%; box-sizing: border-box; background-color: rgb(117, 117, 118);"><section style="display: inline-block; padding-right: 0.5em; padding-left: 0.5em; font-size: 1em; line-height: 2; box-sizing: border-box; color: inherit;"><section class="135brush" data-brushtype="text" style="box-sizing: border-box; color: inherit;">完</section></section></section><section style="margin-top: -1em; margin-bottom: 1em; box-sizing: border-box; color: inherit;"><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: left; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: right; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section></section></section><br><br></p>]]></content>
<tags>
<tag> 效率 </tag>
</tags>
</entry>
<entry>
<title>兔子和兔子窝--RabbitMQ+Python入门经典</title>
<link href="/2018/09/04/%E5%85%94%E5%AD%90%E5%92%8C%E5%85%94%E5%AD%90%E7%AA%9D-RabbitMQ-Python%E5%85%A5%E9%97%A8%E7%BB%8F%E5%85%B8/"/>
<url>/2018/09/04/%E5%85%94%E5%AD%90%E5%92%8C%E5%85%94%E5%AD%90%E7%AA%9D-RabbitMQ-Python%E5%85%A5%E9%97%A8%E7%BB%8F%E5%85%B8/</url>
<content type="html"><![CDATA[<p>RabbitMQ作为一个工业级的消息队列服务器,在其客户端手册列表的Python段当中推荐了一篇blog,作为RabbitMQ+Python的入门手册再合适不过了。<br><a id="more"></a><br>不过,正如其标题Rabbit and Warrens(兔子和养兔场)一样,这篇英文写的相当俏皮,以至于对于我等非英文读者来说不像一般的技术文档那么好懂,所以,翻译一下吧。翻译过了,希望其他人可以少用一些时间。翻译水平有限,不可能像原文一样俏皮,部分地方可能就意译了,希望以容易懂为准。想看看老外的幽默的,推荐去看原文,其实,也不是那么难理解……</p><p><strong>原文</strong>:<a href="http://web.archive.org/web/20160403195615/http://blogs.digitar.com/jjww/2009/01/rabbits-and-warrens/" target="_blank" rel="noopener">http://web.archive.org/web/20160403195615/http://blogs.digitar.com/jjww/2009/01/rabbits-and-warrens/</a></p><h4 id="兔子和兔子窝"><a href="#兔子和兔子窝" class="headerlink" title="兔子和兔子窝"></a>兔子和兔子窝</h4><p> 当时我们的动机很简单:从生产环境的电子邮件处理流程当中分支出一个特定的离线分析流程。我们开始用的MySQL,将要处理的东西放在表里面,另一个程序从中取。不过很快,这种设计的丑陋之处就显现出来了…… 你想要多个程序从一个队列当中取数据来处理?没问题,我们硬编码程序的个数好了……什么?还要能够允许程序动态地增加和减少的时候动态进行压力分配?</p><p> 是的,当年我们想的简单的东西(做一个分支处理)逐渐变成了一个棘手的问题。以前拿着锤子(MySQL)看所有东西都是钉子(表)的年代是多么美好……</p><p> 在搜索了一下之后,我们走进了消息队列(message queue)的大门。不不,我们当然知道消息队列是什么,我们可是以做电子邮件程序谋生的。我们实现过各种各样的专业的,高速的内存队列用来做电子邮件处理。我们不知道的是那一大类现成的、通用的消息队列(MQ)服务器——无论是用什么语言写出的,不需要复杂的装配的,可以自然的在网络上的应用程序之间传送数据的一类程序。这种消息队列还不用我们自己写?先看看再说。</p><p>让大家看看你们的Queue吧……</p><p> 过去的4年里,人们写了有好多好多的开源的MQ服务器啊。其中大多数都是某公司例如LiveJournal写出来用来解决特定问题的。它们的确不关心上面跑的是什么类型的消息,不过他们的设计思想通常是和创建者息息相关的(消息的持久化,崩溃恢复等通常不在他们考虑范围内)。不过,有三个专门设计用来做及其灵活的消息队列的程序值得关注:</p><p>· Apache ActiveMQ</p><p>· ZeroMQ</p><p>· RabbitMQ</p><p>Apache ActiveMQ 曝光率最高,不过看起来它有些问题,可能会造成丢消息。不可接受,下一个。</p><p>ZeroMQ 和 RabbitMQ 都支持一个开源的消息协议,称为AMQP。AMQP的一个优点是它是一个灵活和开放的协议,以便和另外两个商业化的Message Queue (IBM和Tibco)竞争,很好。不过ZeroMQ不支持消息持久化和崩溃恢复,不太好。剩下的只有RabbitMQ了。如果你不在意消息持久化和崩溃恢复,试试ZeroMQ吧,延迟很低,而且支持灵活的拓扑。</p><p>剩下的只有这个吃胡萝卜的家伙了……<br><a href="https://www.rabbitmq.com/img/rabbitmq_logo_strap.png" target="_blank" rel="noopener"><img src="https://www.rabbitmq.com/img/rabbitmq_logo_strap.png" alt="img"></a></p><p> 当我读到它是用Erlang写的时候,RabbitMQ震了我一下。Erlang 是爱立信开发的高度并行的语言,用来跑在电话交换机上。是的,那些要求6个9的在线时间的东西。在Erlang当中,充斥着大量轻量进程,它们之间用消息传递来通信。听起来思路和我们用消息队列的思路是一样的,不是么?</p><p> 而且,RabbitMQ支持持久化。是的,如果RabbitMQ死掉了,消息并不会丢失,当队列重启,一切都会回来。而且,正如在DigiTar(注:原文作者的公司)做事情期望的那样,它可以和Python无缝结合。除此之外,RabbitMQ的文档相当的……恐怖。如果你懂AMQP,这些文档还好,但是有多少人懂AMQP?这些文档就像MySQL的文档假设你已经懂了SQL一样……不过这也没关系啦。</p><p> 好了,废话少说。这里是花了一周时间阅读关于AMQP和关于它如何在RabbitMQ上工作的文档之后的一个总结,还有,怎么在Python当中使用。</p><p>让我们开始吧</p><p> AMQP当中有四个概念非常重要:虚拟主机(virtual host),交换机(exchange),队列(queue)和绑定(binding)。一个虚拟主机持有一组交换机、队列和绑定。为什么需要多个虚拟主机呢?很简单,RabbitMQ当中,用户只能在虚拟主机的粒度进行权限控制。因此,如果需要禁止A组访问B组的交换机/队列/绑定,必须为A和B分别创建一个虚拟主机。每一个RabbitMQ服务器都有一个默认的虚拟主机“/”。如果这些正是你想要的,那现在就可以开始了。</p><p>交换机,队列,还有绑定……天哪!</p><p>刚开始我思维的列车就是在这里脱轨的…… 这些鬼东西怎么结合起来的?</p><p> 队列(Queues)是你的消息(messages)的终点,可以理解成装消息的容器。消息就一直在里面,直到有客户端(也就是消费者,Consumer)连接到这个队列并且将其取走为止。当然,你也可以将一个队列配置成这样的:一旦消息进入这个队列,biu~,它就烟消云散了。这个有点跑题了……</p><p> 需要记住的是,队列是由消费者(Consumer)通过程序建立的,不是通过配置文件或者命令行工具。这没什么问题,如果一个消费者试图创建一个已经存在的队列,RabbitMQ就会起来拍拍他的脑袋,笑一笑,然后忽略这个请求。因此你可以将消息队列的配置写在应用程序的代码里面。这个概念不错。</p><p> OK,你已经创建并且连接到了你的队列,你的消费者程序正在百无聊赖的敲着手指等待消息的到来,敲啊,敲啊…… 没有消息,发生了什么?你当然需要先把一个消息放进队列才行。不过要做这个,你需要一个交换机(Exchange)……</p><p> 交换机可以理解成具有路由表的路由程序,仅此而已。每个消息都有一个称为路由键(routing key)的属性,就是一个简单的字符串。交换机当中有一系列的绑定(binding),即路由规则(routes),例如,指明具有路由键 “X” 的消息要到名为timbuku的队列当中去。先不讨论这个,我们有点超前了。</p><p> 你的消费者程序要负责创建你的交换机们(复数)。啥?你是说你可以有多个交换机?是的,这个可以有,不过为啥?很简单,每个交换机在自己独立的进程当中执行,因此增加多个交换机就是增加多个进程,可以充分利用服务器上的CPU核以便达到更高的效率。例如,在一个8核的服务器上,可以创建5个交换机来用5个核,另外3个核留下来做消息处理。类似的,在RabbitMQ的集群当中,你可以用类似的思路来扩展交换机,以便获取更高的吞吐量。</p><p> OK,你已经创建了一个交换机。但是他并不知道要把消息送到哪个队列。你需要路由规则,即绑定(binding)。一个绑定就是一个类似这样的规则:将交换机“desert(沙漠)”当中具有路由键“阿里巴巴”的消息送到队列“hideout(山洞)”里面去。换句话说,一个绑定就是一个基于路由键将交换机和队列连接起来的路由规则。例如,具有路由键“audit”的消息需要被送到两个队列,“log-forever”和“alert-the-big-dude”。要做到这个,就需要创建两个绑定,每个都连接一个交换机和一个队列,两者都是由“audit”路由键触发。在这种情况下,交换机会复制一份消息并且把它们分别发送到两个队列当中。交换机不过就是一个由绑定构成的路由表。</p><p> 现在复杂的东西来了:交换机有多种类型。他们都是做路由的,不过接受不同类型的绑定。为什么不创建一种交换机来处理所有类型的路由规则呢?因为每种规则用来做匹配分子的CPU开销是不同的。例如,一个“topic”类型的交换机试图将消息的路由键与类似“dogs.*”的模式进行匹配。匹配这种末端的通配符比直接将路由键与“dogs”比较(“direct”类型的交换机)要消耗更多的CPU。如果你不需要“topic”类型的交换机带来的灵活性,你可以通过使用“direct”类型的交换机获取更高的处理效率。那么有哪些类型,他们又是怎么处理的呢?</p><p> Fanout Exchange – 不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。</p><p> Direct Exchange – 处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “dog”,则只有被标记为“dog”的消息才被转发,不会转发dog.puppy,也不会转发dog.guard,只会转发dog。</p><p> Topic Exchange – 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“<em>”匹配不多不少一个词。因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.</em>” 只会匹配到“audit.irs”。我在RedHat的朋友做了一张不错的图,来表明topic交换机是如何工作的:</p><p><a href="http://blogs.digitar.com/jjww/wp-content/uploads/2009/01/chapter-2_amqp_stack.png" target="_blank" rel="noopener"><img src="http://blogs.digitar.com/jjww/wp-content/uploads/2009/01/chapter-2_amqp_stack.png" alt="img"></a></p><p>Source: RabbitMQ in Action : 1.3 Topic Exchange</p><p>持久化这些小东西们</p><p> 你花了大量的时间来创建队列、交换机和绑定,然后,砰~服务器程序挂了。你的队列、交换机和绑定怎么样了?还有,放在队列里面但是尚未处理的消息们呢?</p><p> 放松~如果你是用默认参数构造的这一切的话,那么,他们,都,biu~,灰飞烟灭了。是的,RabbitMQ重启之后会干净的像个新生儿。你必须重做所有的一切,亡羊补牢,如何避免将来再度发生此类杯具?</p><p> 队列和交换机有一个创建时候指定的标志durable,直译叫做坚固的。durable的唯一含义就是具有这个标志的队列和交换机会在重启之后重新建立,它不表示说在队列当中的消息会在重启后恢复。那么如何才能做到不只是队列和交换机,还有消息都是持久的呢?</p><p> 但是首先一个问题是,你真的需要消息是持久的吗?对于一个需要在重启之后回复的消息来说,它需要被写入到磁盘上,而即使是最简单的磁盘操作也是要消耗时间的。如果和消息的内容相比,你更看重的是消息处理的速度,那么不要使用持久化的消息。不过对于我们@DigiTar来说,持久化很重要。</p><p> 当你将消息发布到交换机的时候,可以指定一个标志“Delivery Mode”(投递模式)。根据你使用的AMQP的库不同,指定这个标志的方法可能不太一样(我们后面会讨论如何用Python搞定)。简单的说,就是将Delivery Mode设置成2,也就是持久的(persistent)即可。一般的AMQP库都是将Delivery Mode设置成1,也就是非持久的。所以要持久化消息的步骤如下:</p><ol><li>将交换机设成 durable。</li><li>将队列设成 durable。</li><li>将消息的 Delivery Mode 设置成2 。</li></ol><p>就这样,不是很复杂,起码没有造火箭复杂,不过也有可能犯点小错误。</p><p>下面还要罗嗦一个东西……绑定(Bindings)怎么办?我们无法在创建绑定的时候设置成durable。没问题,如果你绑定了一个durable的队列和一个durable的交换机,RabbitMQ会自动保留这个绑定。类似的,如果删除了某个队列或交换机(无论是不是durable),依赖它的绑定都会自动删除。</p><p>注意两点:</p><p>· RabbitMQ 不允许你绑定一个非坚固(non-durable)的交换机和一个durable的队列。反之亦然。要想成功必须队列和交换机都是durable的。</p><p>· 一旦创建了队列和交换机,就不能修改其标志了。例如,如果创建了一个non-durable的队列,然后想把它改变成durable的,唯一的办法就是删除这个队列然后重现创建。因此,最好仔细检查创建的标志。</p><p>开始喂蛇了~</p><p>【译注】说喂蛇是因为Python的图标是条蛇。</p><p>AMQP的一个空白地带是如何在Python当中使用。对于其他语言有一大坨材料。</p><p>· Java – <a href="http://www.rabbitmq.com/java-client.html" target="_blank" rel="noopener">http://www.rabbitmq.com/java-client.html</a></p><p>· .NET – <a href="http://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.5.0/rabbitmq-dotnet-client-1.5.0-user-guide.pdf" target="_blank" rel="noopener">http://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.5.0/rabbitmq-dotnet-client-1.5.0-user-guide.pdf</a></p><p>· Ruby – <a href="http://somic.org/2008/06/24/ruby-amqp-rabbitmq-example/" target="_blank" rel="noopener">http://somic.org/2008/06/24/ruby-amqp-rabbitmq-example/</a></p><p>但是对Python老兄来说,你需要花点时间来挖掘一下。所以我写了这个,这样别的家伙们就不需要经历我这种抓狂的过程了。</p><p>首先,我们需要一个Python的AMQP库。有两个可选:</p><p>· py-amqplib – 通用的AMQP</p><p>· txAMQP – 使用 Twisted 框架的AMQP库,因此允许异步I/O。</p><p>根据你的需求,py-amqplib或者txAMQP都是可以的。因为是基于Twisted的,txAMQP可以保证用异步IO构建超高性能的AMQP程序。但是Twisted编程本身就是一个很大的主题……因此清晰起见,我们打算用 py-amqplib。更新:请参见Esteve Fernandez关于txAMQP的使用和代码样例的回复。</p><p>AMQP支持在一个TCP连接上启用多个MQ通信channel,每个channel都可以被应用作为通信流。每个AMQP程序至少要有一个连接和一个channel。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">from amqplib import client_0_8 as amqp </span><br><span class="line">conn = amqp.Connection(host="localhost:5672 ", userid="guest", </span><br><span class="line">password="guest", virtual_host="/", insist=False) </span><br><span class="line">chan = conn.channel()</span><br></pre></td></tr></table></figure><p>每个channel都被分配了一个整数标识,自动由Connection()类的.channel()方法维护。或者,你可以使用.channel(x)来指定channel标识,其中x是你想要使用的channel标识。通常情况下,推荐使用.channel()方法来自动分配channel标识,以便防止冲突。</p><p>现在我们已经有了一个可以用的连接和channel。现在,我们的代码将分成两个应用,生产者(producer)和消费者(consumer)。我们先创建一个消费者程序,他会创建一个叫做“po_box”的队列和一个叫“sorting_room”的交换机:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">chan.queue_declare(queue="po_box", durable=True, </span><br><span class="line">exclusive=False, auto_delete=False) </span><br><span class="line">chan.exchange_declare(exchange="sorting_room", type="direct", durable=True, </span><br><span class="line">auto_delete=False,)</span><br></pre></td></tr></table></figure><p>这段代码干了啥?首先,它创建了一个名叫“po_box”的队列,它是durable的(重启之后会重新建立),并且最后一个消费者断开的时候不会自动删除(auto_delete=False)。在创建durable的队列(或者交换机)的时候,将auto_delete设置成false是很重要的,否则队列将会在最后一个消费者断开的时候消失,与durable与否无关。如果将durable和auto_delete都设置成True,只有尚有消费者活动的队列可以在RabbitMQ意外崩溃的时候自动恢复。</p><p>(你可以注意到了另一个标志,称为“exclusive”。如果设置成True,只有创建这个队列的消费者程序才允许连接到该队列。这种队列对于这个消费者程序是私有的)。</p><p>还有另一个交换机声明,创建了一个名字叫“sorting_room”的交换机。auto_delete和durable的含义和队列是一样的。但是,.excange_declare() 还有另外一个参数叫做type,用来指定要创建的交换机的类型(如前面列出的): fanout, direct 和 topic.</p><p>到此为止,你已经有了一个可以接收消息的队列和一个可以发送消息的交换机。不过我们需要创建一个绑定,把它们连接起来。</p><p>chan.queue_bind(queue=”po_box”,exchange=”sorting_room”,<br>routing_key=”jason”)</p><p>这个绑定的过程非常直接。任何送到交换机“sorting_room”的具有路由键“jason” 的消息都被路由到名为“po_box” 的队列。</p><p>现在,你有两种方法从队列当中取出消息。第一个是调用chan.basic_get(),主动从队列当中拉出下一个消息(如果队列当中没有消息,chan.basic_get()会返回None, 因此下面代码当中print msg.body 会在没有消息的时候崩掉):</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">msg = chan.basic_get("po_box") </span><br><span class="line">print msg.body </span><br><span class="line">chan.basic_ack(msg.delivery_tag)</span><br></pre></td></tr></table></figure><p>但是如果你想要应用程序在消息到达的时候立即得到通知怎么办?这种情况下不能使用chan.basic_get(),你需要用chan.basic_consume()注册一个新消息到达的回调。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">def recv_callback(msg): </span><br><span class="line"> print 'Received: ' + msg.body </span><br><span class="line">chan.basic_consume(queue='po_box', no_ack=True, </span><br><span class="line">callback=recv_callback, consumer_tag="testtag") </span><br><span class="line">while True: </span><br><span class="line"> chan.wait() </span><br><span class="line">chan.basic_cancel("testtag")</span><br></pre></td></tr></table></figure><p>chan.wait() 放在一个无限循环里面,这个函数会等待在队列上,直到下一个消息到达队列。chan.basic_cancel() 用来注销该回调函数。参数consumer_tag 当中指定的字符串和chan.basic_consume() 注册的一直。在这个例子当中chan.basic_cancel() 不会被调用到,因为上面是个无限循环…… 不过你需要知道这个调用,所以我把它放在了代码里。</p><p>需要注意的另一个东西是no_ack参数。这个参数可以传给chan.basic_get()和chan.basic_consume(),默认是false。当从队列当中取出一个消息的时候,RabbitMQ需要应用显式地回馈说已经获取到了该消息。如果一段时间内不回馈,RabbitMQ会将该消息重新分配给另外一个绑定在该队列上的消费者。另一种情况是消费者断开连接,但是获取到的消息没有回馈,则RabbitMQ同样重新分配。如果将no_ack 参数设置为true,则py-amqplib会为下一个AMQP请求添加一个no_ack属性,告诉AMQP服务器不需要等待回馈。但是,大多数时候,你也许想要自己手工发送回馈,例如,需要在回馈之前将消息存入数据库。回馈通常是通过调用chan.basic_ack()方法,使用消息的delivery_tag属性作为参数。参见chan.basic_get() 的实例代码。</p><p>好了,这就是消费者的全部代码。(下载:amqp_consumer.py)</p><p>不过没有人发送消息的话,要消费者何用?所以需要一个生产者。下面的代码示例表明如何将一个简单消息发送到交换区“sorting_room”,并且标记为路由键“jason” :</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">msg = amqp.Message("Test message!") </span><br><span class="line">msg.properties["delivery_mode"] = 2 </span><br><span class="line">chan.basic_publish(msg,exchange="sorting_room",routing_key="jason")</span><br></pre></td></tr></table></figure><p>你也许注意到我们设置消息的delivery_mode属性为2,因为队列和交换机都设置为durable的,这个设置将保证消息能够持久化,也就是说,当它还没有送达消费者之前如果RabbitMQ重启则它能够被恢复。</p><p>剩下的最后一件事情(生产者和消费者都需要调用的)是关闭channel和连接:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">chan.close()</span><br><span class="line"></span><br><span class="line">conn.close()</span><br></pre></td></tr></table></figure><p>很简单吧。(下载:amqp_publisher.py)</p><p>来真实地跑一下吧……</p><p>现在我们已经写好了生产者和消费者,让他们跑起来吧。假设你的RabbitMQ在localhost上安装并且运行。</p><p>打开一个终端,执行python ./amqp_consumer.py让消费者运行,并且创建队列、交换机和绑定。</p><p>然后在另一个终端运行python ./amqp_publisher.py “AMQP rocks.” 。如果一切良好,你应该能够在第一个终端看到输出的消息。</p><p>付诸使用吧</p><p>我知道这个教程是非常粗浅的关于AMQP/RabbitMQ和如何使用Python访问的教程。希望这个可以说明所有的概念如何在Python当中被组合起来。如果你发现任何错误,请联系原作者([email protected]) 【译注:如果是翻译问题请联系译者】。同时,我很高兴回答我知道的问题。【译注:译者也是一样的】。接下来是,集群化(clustering)!不过我需要先把它弄懂再说。</p><p>注:关于RabbitMQ的知识我主要来自这些来源,推荐阅读:</p><p>· zeromq:消息中间件分析</p><p>· RabbitMQ .NET客户端库用户手册</p><p>· 高级消息队列协议(Advanced Message QueuingProtocol):协议规约0.8 版本</p><p>嗯, 就酱,Just enjoying!</p><p><section style="text-align: center; font-size: 1em; font-weight: inherit; text-decoration: inherit; color: rgb(255, 255, 255); border-color: rgb(117, 117, 118); box-sizing: border-box;"><section data-width="2em" style="width: 2em; height: 2em; margin-right: auto; margin-left: auto; border-radius: 100%; box-sizing: border-box; background-color: rgb(117, 117, 118);"><section style="display: inline-block; padding-right: 0.5em; padding-left: 0.5em; font-size: 1em; line-height: 2; box-sizing: border-box; color: inherit;"><section class="135brush" data-brushtype="text" style="box-sizing: border-box; color: inherit;">完</section></section></section><section style="margin-top: -1em; margin-bottom: 1em; box-sizing: border-box; color: inherit;"><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: left; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: right; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section></section></section><br><br></p>]]></content>
<tags>
<tag> RabbitMQ </tag>
<tag> 消息队列 </tag>
</tags>
</entry>
<entry>
<title>GET和POST有什么区别?及为什么网上多数答案都是错的</title>
<link href="/2016/10/14/GET%E5%92%8CPOST%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%EF%BC%9F%E5%8F%8A%E4%B8%BA%E4%BB%80%E4%B9%88%E7%BD%91%E4%B8%8A%E5%A4%9A%E6%95%B0%E7%AD%94%E6%A1%88%E9%83%BD%E6%98%AF%E9%94%99%E7%9A%84/"/>
<url>/2016/10/14/GET%E5%92%8CPOST%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%EF%BC%9F%E5%8F%8A%E4%B8%BA%E4%BB%80%E4%B9%88%E7%BD%91%E4%B8%8A%E5%A4%9A%E6%95%B0%E7%AD%94%E6%A1%88%E9%83%BD%E6%98%AF%E9%94%99%E7%9A%84/</url>
<content type="html"><![CDATA[<blockquote><p>来自:南柯之石 - 博客</p><p>作者:南柯之石</p><p>链接:<a href="http://www.cnblogs.com/nankezhishi/archive/2012/06/09/getandpost.html" target="_blank" rel="noopener">http://www.cnblogs.com/nankezhishi/archive/2012/06/09/getandpost.html</a></p></blockquote><p>如果有人问你,GET和POST,有什么区别?你会如何回答?<br><a id="more"></a></p><h4 id="我的经历"><a href="#我的经历" class="headerlink" title="我的经历"></a>我的经历</h4><p>前几天有人问我这个问题。我说GET是用于获取数据的,POST,一般用于将数据发给服务器之用。</p><p>这个答案好像并不是他想要的。于是他继续追问有没有别的区别?我说这就是个名字而已,如果服务器支持,他完全可以把GET改个名字叫GET2。他反问道,那就是单纯的名字上的区别喽?我想了想,我觉得如果说再具体的区别,只能去看RFC文档了,还要取决于服务器(指Apache,IIS)的具体实现。但我不得不承认,我的确没有仔细看过HTTP的RFC文档。于是我说,我对HTTP协议不太熟悉。这个问题也就结束了。</p><h4 id="最普遍的答案"><a href="#最普遍的答案" class="headerlink" title="最普遍的答案"></a>最普遍的答案</h4><p>回来之后寻思了很久,他到底是想问我什么?我一直就觉得GET和POST没有什么除了语义之外的区别,自打我开始学习Web编程开始就是这么理解的。</p><p>可能很多人都已经猜到了,他要的答案是:</p><p>1、GET使用URL或Cookie传参。而POST将数据放在BODY中。</p><p>2、GET的URL会有长度上的限制,则POST的数据则可以非常大。</p><p>3、POST比GET安全,因为数据在地址栏上不可见。</p><p>但是很不幸,这些区别全是错误的,更不幸的是,这个答案还是Google搜索的头版头条,然而我根本没想着这些是答案,因为在我看来他们都是错的。我来一一解释一下。</p><h4 id="GET和POST与数据如何传递没有关系"><a href="#GET和POST与数据如何传递没有关系" class="headerlink" title="GET和POST与数据如何传递没有关系"></a>GET和POST与数据如何传递没有关系</h4><p>GET和POST是由HTTP协议定义的。在HTTP协议中,Method和Data(URL, Body, Header)是正交的两个概念,也就是说,使用哪个Method与应用层的数据如何传输是没有相互关系的。</p><p>HTTP没有要求,如果Method是POST数据就要放在BODY中。也没有要求,如果Method是GET,数据(参数)就一定要放在URL中而不能放在BODY中。</p><p>那么,网上流传甚广的这个说法是从何而来的呢?我在HTML标准中,找到了相似的描述。这和网上流传的说法一致。但是这只是HTML标准对HTTP协议的用法的约定。怎么能当成GET和POST的区别呢?</p><p>而且,现代的Web Server都是支持GET中包含BODY这样的请求。虽然这种请求不可能从浏览器发出,但是现在的Web Server又不是只给浏览器用,已经完全地超出了HTML服务器的范畴了。</p><p>知道这个有什么用?我不想解释了,有时候就得自己痛一次才记得住。</p><h4 id="HTTP协议对GET和POST都没有对长度的限制"><a href="#HTTP协议对GET和POST都没有对长度的限制" class="headerlink" title="HTTP协议对GET和POST都没有对长度的限制"></a>HTTP协议对GET和POST都没有对长度的限制</h4><p>HTTP协议明确地指出了,HTTP头和Body都没有长度的要求。而对于URL长度上的限制,有两方面的原因造成:</p><ol><li>浏览器。据说早期的浏览器会对URL长度做限制。据说IE对URL长度会限制在2048个字符内(流传很广,而且无数同事都表示认同)。但我自己试了一下,我构造了90K的URL通过IE9访问live.com,是正常的。网上的东西,哪怕是Wikipedia上的,也不能信。</li><li>服务器。URL长了,对服务器处理也是一种负担。原本一个会话就没有多少数据,现在如果有人恶意地构造几个几M大小的URL,并不停地访问你的服务器。服务器的最大并发数显然会下降。另一种攻击方式是,把告诉服务器Content-Length是一个很大的数,然后只给服务器发一点儿数据,嘿嘿,服务器你就傻等着去吧。哪怕你有超时设置,这种故意的次次访问超时也能让服务器吃不了兜着走。有鉴于此,多数服务器出于安全啦、稳定啦方面的考虑,会给URL长度加限制。但是这个限制是针对所有HTTP请求的,与GET、POST没有关系。</li></ol><h4 id="安全不安全和GET、POST没有关系"><a href="#安全不安全和GET、POST没有关系" class="headerlink" title="安全不安全和GET、POST没有关系"></a>安全不安全和GET、POST没有关系</h4><p>我觉得这真是中国特色。我讲个小段子,大家应该可以体会出这个说法多么的可笑。</p><p>觉得POST数据比GET数据安全的人会说</p><blockquote><p>“防君子不防小人;中国小白多,能防小白用户就行了。”</p><p>“哼,”我不以为然,“那你怎么不说,URL参数都Encode过了,或是Base64一下,小白也看不懂啊。”</p></blockquote><p>那人反驳道,“Encode太简单了,聪明点儿的小白很容易就可以Decode并修改掉。”</p><p>我笑道,“五十步笑百步耳,再聪明点儿的小白还会截包并重发呢,Opera就有这功能。”</p><p>那人阴险地祭出神器——最终解释权,说,“这个不算小白。”</p><p>我日啊。</p><h4 id="最后一点儿感想"><a href="#最后一点儿感想" class="headerlink" title="最后一点儿感想"></a>最后一点儿感想</h4><p>我之前一直做Windows桌面应用,对Web开发无甚了解,直到一年多前转做服务器端开发,才开始接触到HTTP。(注意,我说的是HTTP,不是HTML。服务器开放接口是基于REST理念设计的,使用的协议是HTTP,但是传输的内容不是HTML。这不是Web Server,而是一个Web Service)</p><p>所以我对于GET和POST的理解,是纯粹地来源于HTTP协议。他们只有一点根本区别,简单点儿说,一个用于获取数据,一个用于修改数据。具体的请参考RFC文档。</p><p>如果一个人一开始就做Web开发,很可能把HTML对HTTP协议的使用方式,当成HTTP协议的唯一的合理使用方式。从而犯了以偏概全的错误。</p><p>可能有人会觉得我钻牛角尖。我只是不喜欢模棱两可,不喜欢边界不清、概念不明,不喜欢“拿来主义”,也不喜欢被其它喜欢钻牛角尖的人奚落得无地自容。</p><p>最后:</p><blockquote><p>“知之为知之,不知为不知,是知也。”</p></blockquote>]]></content>
<tags>
<tag> http </tag>
<tag> web </tag>
</tags>
</entry>
<entry>
<title>Python 程序员经常犯的 10 个错误</title>
<link href="/2016/09/30/Python%20%E7%A8%8B%E5%BA%8F%E5%91%98%E7%BB%8F%E5%B8%B8%E7%8A%AF%E7%9A%84%2010%20%E4%B8%AA%E9%94%99%E8%AF%AF/"/>
<url>/2016/09/30/Python%20%E7%A8%8B%E5%BA%8F%E5%91%98%E7%BB%8F%E5%B8%B8%E7%8A%AF%E7%9A%84%2010%20%E4%B8%AA%E9%94%99%E8%AF%AF/</url>
<content type="html"><![CDATA[<p>   <br><a href="https://www.python.org/" target="_blank" rel="noopener">Python</a>是一种解释性、面向对象并具有动态语义的高级程序语言。它内建了高级的数据结构,结合了动态类型和动态绑定的优点,这使得它在<a href="http://en.wikipedia.org/wiki/Rapid_application_development" target="_blank" rel="noopener">快速应用开发</a>中非常有吸引力,并且可作为脚本或胶水语言来连接现有的组件或服务。Python支持模块和包,从而鼓励了程序的模块化和代码重用。<br><a id="more"></a></p><h4 id="关于这篇文章"><a href="#关于这篇文章" class="headerlink" title="关于这篇文章"></a>关于这篇文章</h4><p>Python简单易学的语法可能会使Python开发者–尤其是那些编程的初学者–忽视了它的一些微妙的地方并低估了这门语言的能力。</p><p>有鉴于此,本文列出了一个“10强”名单,枚举了甚至是高级Python开发人员有时也难以捕捉的错误。</p><h4 id="常见错误-1-滥用表达式作为函数参数的默认值"><a href="#常见错误-1-滥用表达式作为函数参数的默认值" class="headerlink" title="常见错误 #1: 滥用表达式作为函数参数的默认值"></a>常见错误 #1: 滥用表达式作为函数参数的默认值</h4><p>Python允许为函数的参数提供默认的可选值。尽管这是语言的一大特色,但是它可能会导致一些<a href="https://docs.python.org/2/reference/datamodel.html" target="_blank" rel="noopener">易变</a>默认值的混乱。例如,看一下这个Python函数的定义:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">>>> def foo(bar=[]): # bar is optional and defaults to [] if not specified</span><br><span class="line">... bar.append("baz") # but this line could be problematic, as we'll see...</span><br><span class="line">... return bar</span><br></pre></td></tr></table></figure><p>一个常见的错误是认为在函数每次不提供可选参数调用时可选参数将设置为默认指定值。在上面的代码中,例如,人们可能会希望反复(即不明确指定bar参数)地调用foo()时总返回’baz’,由于每次foo()调用时都假定(不设定bar参数)bar被设置为[](即一个空列表)。</p><p>但是让我们看一下这样做时究竟会发生什么:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">>>> foo()</span><br><span class="line">["baz"]>>> foo()</span><br><span class="line">["baz", "baz"]>>> foo()</span><br><span class="line">["baz", "baz", "baz"]</span><br></pre></td></tr></table></figure><p>耶?为什么每次foo()调用时都要把默认值”baz”追加到现有列表中而不是创建一个新的列表呢?</p><p>答案是函数参数的默认值只会评估使用一次—在函数定义的时候。因此,bar参数在初始化时为其默认值(即一个空列表),即foo()首次定义的时候,但当调用foo()时(即,不指定bar参数时)将继续使用bar原本已经初始化的参数。</p><p>下面是一个常见的解决方法:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">>>> def foo(bar=None):</span><br><span class="line">... if bar is None: # or if not bar:</span><br><span class="line">... bar = []</span><br><span class="line">... bar.append("baz")</span><br><span class="line">... return bar</span><br><span class="line">...</span><br><span class="line">>>> foo()</span><br><span class="line">["baz"]</span><br><span class="line">>>> foo()</span><br><span class="line">["baz"]</span><br><span class="line">>>> foo()</span><br><span class="line">["baz"]</span><br></pre></td></tr></table></figure><h4 id="常见错误-2-错误地使用类变量"><a href="#常见错误-2-错误地使用类变量" class="headerlink" title="常见错误 #2: 错误地使用类变量"></a>常见错误 #2: 错误地使用类变量</h4><p>考虑一下下面的例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">>>> class A(object):</span><br><span class="line">... x = 1</span><br><span class="line">...</span><br><span class="line">>>> class B(A):</span><br><span class="line">... pass</span><br><span class="line">...</span><br><span class="line">>>> class C(A):</span><br><span class="line">... pass</span><br><span class="line">...</span><br><span class="line">>>> print A.x, B.x, C.x</span><br><span class="line">1 1 1</span><br></pre></td></tr></table></figure><p>常规用一下。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">>>> B.x = 2</span><br><span class="line">>>> print A.x, B.x, C.x</span><br><span class="line">1 2 1</span><br></pre></td></tr></table></figure><p>嗯,再试一下也一样。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">>>> A.x = 3</span><br><span class="line">>>> print A.x, B.x, C.x</span><br><span class="line">3 2 3</span><br></pre></td></tr></table></figure><p>什么 <em>$%#!&</em>?? 我们只改了A.x,为什么C.x也改了?</p><p>在Python中,类变量在内部当做字典来处理,其遵循常被引用的<a href="http://python-history.blogspot.com.ar/2010/06/method-resolution-order.html" target="_blank" rel="noopener">方法解析顺序(MRO)</a>。所以在上面的代码中,由于class C中的x属性没有找到,它会向上找它的基类(尽管Python支持多重继承,但上面的例子中只有A)。换句话说,class C中没有它自己的x属性,其独立于A。因此,C.x事实上是A.x的引用。</p><h4 id="常见错误-3-为-except-指定错误的参数"><a href="#常见错误-3-为-except-指定错误的参数" class="headerlink" title="常见错误 #3: 为 except 指定错误的参数"></a>常见错误 #3: 为 except 指定错误的参数</h4><p>假设你有如下一段代码:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">>>> try:</span><br><span class="line">... l = ["a", "b"]</span><br><span class="line">... int(l[2])</span><br><span class="line">... except ValueError, IndexError: # To catch both exceptions, right?</span><br><span class="line">... pass</span><br><span class="line">...</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File "<stdin>", line 3, in <module></span><br><span class="line">IndexError: list index out of range</span><br></pre></td></tr></table></figure><p>这里的问题在于 except 语句并不接受以这种方式指定的异常列表。相反,在Python 2.x中,使用语法 except Exception, e 是将一个异常对象绑定到第二个<em>可选</em>参数(在这个例子中是 e)上,以便在后面使用。所以,在上面这个例子中,IndexError 这个异常并<em>不**是</em>被except语句捕捉到的,而是被绑定到一个名叫 IndexError的参数上时引发的。</p><p>在一个except语句中捕获多个异常的正确做法是将第一个参数指定为一个含有所有要捕获异常的<a href="https://docs.python.org/2/tutorial/datastructures.html#tut-tuples" target="_blank" rel="noopener">元组</a>。并且,为了代码的可移植性,要使用as关键词,因为Python 2 和Python 3都支持这种语法:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">>>> try:</span><br><span class="line">... l = ["a", "b"]</span><br><span class="line">... int(l[2])</span><br><span class="line">... except (ValueError, IndexError) as e: </span><br><span class="line">... pass</span><br><span class="line">...</span><br><span class="line">>>></span><br></pre></td></tr></table></figure><h4 id="常见错误-4-不理解Python的作用域"><a href="#常见错误-4-不理解Python的作用域" class="headerlink" title="常见错误 #4: 不理解Python的作用域"></a>常见错误 #4: 不理解Python的作用域</h4><p>Python是基于 <a href="https://blog.mozilla.org/webdev/2011/01/31/python-scoping-understanding-legb/" target="_blank" rel="noopener">LEGB</a> 来进行作用于解析的, LEGB 是 <strong>L</strong>ocal, <strong>E</strong>nclosing, <strong>G</strong>lobal, <strong>B</strong>uilt-in 的缩写。看起来“见文知意”,对吗?实际上,在Python中还有一些需要注意的地方,先看下面一段代码:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">>>> x = 10</span><br><span class="line">>>> def foo():</span><br><span class="line">... x += 1</span><br><span class="line">... print x</span><br><span class="line">...</span><br><span class="line">>>> foo()</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File "<stdin>", line 1, in <module></span><br><span class="line"> File "<stdin>", line 2, in foo</span><br><span class="line">UnboundLocalError: local variable 'x' referenced before assignment</span><br></pre></td></tr></table></figure><p>这里出什么问题了?</p><p>上面的问题之所以会发生是因为当你给作用域中的一个变量赋值时,Python 会自动的把它当做是当前作用域的局部变量,从而会隐藏外部作用域中的同名变量。</p><p>很多人会感到很吃惊,当他们给之前可以正常运行的代码的函数体的某个地方添加了一句赋值语句之后就得到了一个 UnboundLocalError 的错误。 (你可以在<a href="https://docs.python.org/2/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value" target="_blank" rel="noopener">这里</a>了解到更多)</p><p>尤其是当开发者使用 <a href="https://docs.python.org/2/tutorial/datastructures.html" target="_blank" rel="noopener">lists</a> 时,这个问题就更加常见. 请看下面这个例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">>>> lst = [1, 2, 3]</span><br><span class="line">>>> def foo1():</span><br><span class="line">... lst.append(5) # 没有问题...</span><br><span class="line">...</span><br><span class="line">>>> foo1()</span><br><span class="line">>>> lst</span><br><span class="line">[1, 2, 3, 5]</span><br><span class="line"> </span><br><span class="line">>>> lst = [1, 2, 3]</span><br><span class="line">>>> def foo2():</span><br><span class="line">... lst += [5] # ... 但是这里有问题!</span><br><span class="line">...</span><br><span class="line">>>> foo2()</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File "<stdin>", line 1, in <module></span><br><span class="line"> File "<stdin>", line 2, in foo</span><br><span class="line">UnboundLocalError: local variable 'lst' referenced before assignment</span><br></pre></td></tr></table></figure><p>嗯?为什么 foo2 报错,而foo1没有问题呢?</p><p>原因和之前那个例子的一样,不过更加令人难以捉摸。foo1 没有对 lst 进行赋值操作,而 foo2 做了。要知道, lst += [5] 是 lst = lst + [5] 的缩写,我们试图对 lst 进行<em>赋值</em>操作(Python把他当成了局部变量)。此外,我们对 lst 进行的赋值操作是基于 lst 自身(这再一次被Python当成了局部变量),但此时还未定义。因此出错!</p><h4 id="常见错误-5:当迭代时修改一个列表(List)"><a href="#常见错误-5:当迭代时修改一个列表(List)" class="headerlink" title="常见错误#5:当迭代时修改一个列表(List)"></a>常见错误#5:当迭代时修改一个列表(List)</h4><p>下面代码中的问题应该是相当明显的:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">>>> odd = lambda x : bool(x % 2)</span><br><span class="line">>>> numbers = [n for n in range(10)]</span><br><span class="line">>>> for i in range(len(numbers)):</span><br><span class="line">... if odd(numbers[i]):</span><br><span class="line">... del numbers[i] # BAD: Deleting item from a list while iterating over it</span><br><span class="line">...</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File "<stdin>", line 2, in <module></span><br><span class="line">IndexError: list index out of range</span><br></pre></td></tr></table></figure><p>当迭代的时候,从一个 列表 (List)或者数组中删除元素,对于任何有经验的开发者来说,这是一个众所周知的错误。尽管上面的例子非常明显,但是许多高级开发者在更复杂的代码中也并非是故意而为之的。</p><p>幸运的是,Python包含大量简洁优雅的编程范例,若使用得当,能大大简化和精炼代码。这样的好处是能得到更简化和更精简的代码,能更好的避免程序中出现<em>当迭代时修改一个列表**(List)</em>这样的bug。一个这样的范例是<a href="https://docs.python.org/2/tutorial/datastructures.html#tut-listcomps" target="_blank" rel="noopener">递推式</a><a href="https://docs.python.org/2/tutorial/datastructures.html#tut-listcomps" target="_blank" rel="noopener">列表(list comprehensions)</a>。而且,递推式列表(list comprehensions)针对这个问题是特别有用的,通过更改上文中的实现,得到一段极佳的代码:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">>>> odd = lambda x : bool(x % 2)</span><br><span class="line">>>> numbers = [n for n in range(10)]</span><br><span class="line">>>> numbers[:] = [n for n in numbers if not odd(n)] # ahh, the beauty of it all</span><br><span class="line">>>> numbers</span><br><span class="line">[0, 2, 4, 6, 8]</span><br></pre></td></tr></table></figure><h4 id="常见错误-6-不明白Python在闭包中是如何绑定变量的"><a href="#常见错误-6-不明白Python在闭包中是如何绑定变量的" class="headerlink" title="常见错误 #6: 不明白Python在闭包中是如何绑定变量的"></a>常见错误 #6: 不明白Python在闭包中是如何绑定变量的</h4><p>看下面这个例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">>>> def create_multipliers():</span><br><span class="line">... return [lambda x : i * x for i in range(5)]</span><br><span class="line">>>> for multiplier in create_multipliers():</span><br><span class="line">... print multiplier(2)</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>你也许希望获得下面的输出结果:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">0</span><br><span class="line">2</span><br><span class="line">4</span><br><span class="line">6</span><br><span class="line">8</span><br></pre></td></tr></table></figure><p>但实际的结果却是:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">8</span><br><span class="line">8</span><br><span class="line">8</span><br><span class="line">8</span><br><span class="line">8</span><br></pre></td></tr></table></figure><p>这之所以会发生是由于Python中的“后期绑定”行为——闭包中用到的变量只有在函数被调用的时候才会被赋值。所以,在上面的代码中,任何时候,当返回的函数被调用时,Python会在该函数被调用时的作用域中查找 i 对应的值(这时,循环已经结束,所以 i 被赋上了最终的值——4)。</p><p>解决的方法有一点hack的味道:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">>>> def create_multipliers():</span><br><span class="line">... return [lambda x, i=i : i * x for i in range(5)]</span><br><span class="line">...</span><br><span class="line">>>> for multiplier in create_multipliers():</span><br><span class="line">... print multiplier(2)</span><br><span class="line">...</span><br><span class="line">0</span><br><span class="line">2</span><br><span class="line">4</span><br><span class="line">6</span><br><span class="line">8</span><br></pre></td></tr></table></figure><p>在这里,我们利用了默认参数来生成一个匿名的函数以便实现我们想要的结果。有人说这个方法很巧妙,有人说它难以理解,还有人讨厌这种做法。但是,如果你是一个 Python 开发者,理解这种行为很重要。</p><h4 id="常见错误-7-创建循环依赖模块"><a href="#常见错误-7-创建循环依赖模块" class="headerlink" title="常见错误 #7: 创建循环依赖模块"></a>常见错误 #7: 创建循环依赖模块</h4><p>让我们假设你有两个文件,a.py 和 b.py,他们之间相互引用,如下所示:</p><p>a.py:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import b</span><br><span class="line"> </span><br><span class="line">def f():</span><br><span class="line"> return b.x</span><br><span class="line"> </span><br><span class="line">print f()</span><br></pre></td></tr></table></figure><p>b.py:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import a</span><br><span class="line"> </span><br><span class="line">x = 1</span><br><span class="line"> </span><br><span class="line">def g():</span><br><span class="line"> print a.f()</span><br></pre></td></tr></table></figure><p>首先,让我们尝试引入 a.py:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">>>> import a</span><br><span class="line">1</span><br></pre></td></tr></table></figure><p>可以正常工作。这也许是你感到很奇怪。毕竟,我们确实在这里引入了一个循环依赖的模块,我们推测这样会出问题的,不是吗?</p><p>答案就是在Python中,仅仅引入一个循环依赖的模块是没有问题的。如果一个模块已经被引入了,Python并不会去再次引入它。但是,根据每个模块要访问其他模块中的函数和变量位置的不同,就很可能会遇到问题。</p><p>所以,回到我们这个例子,当我们引入 a.py 时,再引入 b.py 不会产生任何问题,<em>因为当引入的时候</em>,b.py 不需要 a.py 中定义任何东西。b.py 中唯一引用 a.py 中的东西是调用 a.f()。 但是那个调用是发生在g() 中的,并且 a.py 和 b.py 中都没有调用 g()。所以运行正常。</p><p>但是,如果我们尝试去引入b.py 会发生什么呢?(在这之前不引入a.py),如下所示:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">>>> import b</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File "<stdin>", line 1, in <module></span><br><span class="line"> File "b.py", line 1, in <module></span><br><span class="line"> import a</span><br><span class="line"> File "a.py", line 6, in <module></span><br><span class="line"> print f()</span><br><span class="line"> File "a.py", line 4, in f</span><br><span class="line"> return b.x</span><br><span class="line">AttributeError: 'module' object has no attribute 'x'</span><br></pre></td></tr></table></figure><p>啊哦。 出问题了!此处的问题是,在引入b.py的过程中,Python尝试去引入 a.py,但是a.py 要调用f(),而f() 有尝试去访问 b.x。但是此时 b.x 还没有被定义呢。所以发生了 AttributeError 异常。</p><p>至少,解决这个问题很简单,只需修改b.py,使其在g()中引入 a.py:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">x = 1</span><br><span class="line"> </span><br><span class="line">def g():</span><br><span class="line"> import a # 只有当g()被调用的时候才会引入a</span><br><span class="line"> print a.f()</span><br></pre></td></tr></table></figure><p>现在,当我们再引入b,没有任何问题:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">>>> import b</span><br><span class="line">>>> b.g()</span><br><span class="line">1 # Printed a first time since module 'a' calls 'print f()' at the end</span><br><span class="line">1 # Printed a second time, this one is our call to 'g'</span><br></pre></td></tr></table></figure><h4 id="常见错误-8-与Python标准库中的模块命名冲突"><a href="#常见错误-8-与Python标准库中的模块命名冲突" class="headerlink" title="常见错误 #8: 与Python标准库中的模块命名冲突"></a>常见错误 #8: 与Python标准库中的模块命名冲突</h4><p>Python一个令人称赞的地方是它有丰富的模块可供我们“开箱即用”。但是,如果你没有有意识的注意的话,就很容易出现你写的模块和Python自带的标准库的模块之间发生命名冲突的问题(如,你也许有一个叫 email.py 的模块,但这会和标准库中的同名模块冲突)。</p><p>这可能会导致很怪的问题,例如,你引入了另一个模块,但这个模块要引入一个Python标准库中的模块,由于你定义了一个同名的模块,就会使该模块错误的引入了你的模块,而不是 stdlib 中的模块。这就会出问题了。</p><p>因此,我们必须要注意这个问题,以避免使用和Python标准库中相同的模块名。修改你包中的模块名要比通过 <a href="http://legacy.python.org/dev/peps/" target="_blank" rel="noopener">Python Enhancement Proposal (PEP)</a> 给Python提建议来修改标准库的模块名容易多了。</p><h4 id="常见错误-9-未能解决Python-2和Python-3之间的差异"><a href="#常见错误-9-未能解决Python-2和Python-3之间的差异" class="headerlink" title="常见错误 #9: 未能解决Python 2和Python 3之间的差异"></a>常见错误 #9: 未能解决Python 2和Python 3之间的差异</h4><p>请看下面这个 filefoo.py:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">import sys</span><br><span class="line"> </span><br><span class="line">def bar(i):</span><br><span class="line"> if i == 1:</span><br><span class="line"> raise KeyError(1)</span><br><span class="line"> if i == 2:</span><br><span class="line"> raise ValueError(2)</span><br><span class="line"> </span><br><span class="line">def bad():</span><br><span class="line"> e = None</span><br><span class="line"> try:</span><br><span class="line"> bar(int(sys.argv[1]))</span><br><span class="line"> except KeyError as e:</span><br><span class="line"> print('key error')</span><br><span class="line"> except ValueError as e:</span><br><span class="line"> print('value error')</span><br><span class="line"> print(e)</span><br><span class="line"> </span><br><span class="line">bad()</span><br></pre></td></tr></table></figure><p>在Python 2中运行正常:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$ python foo.py 1</span><br><span class="line">key error</span><br><span class="line">1</span><br><span class="line">$ python foo.py 2</span><br><span class="line">value error</span><br><span class="line">2</span><br></pre></td></tr></table></figure><p>但是,现在让我们把它在Python 3中运行一下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">$ python3 foo.py 1</span><br><span class="line">key error</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File "foo.py", line 19, in <module></span><br><span class="line"> bad()</span><br><span class="line"> File "foo.py", line 17, in bad</span><br><span class="line"> print(e)</span><br><span class="line">UnboundLocalError: local variable 'e' referenced before assignment</span><br></pre></td></tr></table></figure><p>出什么问题了? “问题”就是,在 Python 3 中,异常的对象在 except 代码块之外是不可见的。(这样做的原因是,它将保存一个对内存中堆栈帧的引用周期,直到垃圾回收器运行并且从内存中清除掉引用。了解更多技术细节请参考<a href="https://docs.python.org/3/reference/compound_stmts.html#except" target="_blank" rel="noopener">这里</a>) 。</p><p>一种解决办法是在 except 代码块的外部作用域中定义一个对异常对象的引用,以便访问。下面的例子使用了该方法,因此最后的代码可以在Python 2 和 Python 3中运行良好。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">import sys</span><br><span class="line">def bar(i):</span><br><span class="line"> if i == 1:</span><br><span class="line"> raise KeyError(1)</span><br><span class="line"> if i == 2:</span><br><span class="line"> raise ValueError(2)</span><br><span class="line">def good():</span><br><span class="line"> exception = None</span><br><span class="line"> try:</span><br><span class="line"> bar(int(sys.argv[1]))</span><br><span class="line"> except KeyError as e:</span><br><span class="line"> exception = e</span><br><span class="line"> print('key error')</span><br><span class="line"> except ValueError as e:</span><br><span class="line"> exception = e</span><br><span class="line"> print('value error')</span><br><span class="line"> print(exception)</span><br><span class="line"> </span><br><span class="line">good()</span><br></pre></td></tr></table></figure><p>在Python 3中运行:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$ python3 foo.py 1</span><br><span class="line">key error</span><br><span class="line">1</span><br><span class="line">$ python3 foo.py 2</span><br><span class="line">value error</span><br><span class="line">2</span><br></pre></td></tr></table></figure><p>正常!</p><p>(顺便提一下, 我们的 <a href="http://www.toptal.com/python#hiring-guide" target="_blank" rel="noopener">Python Hiring Guide</a> 讨论了当我们把代码从Python 2 迁移到 Python 3时的其他一些需要知道的重要差异。)</p><h4 id="常见错误-10-误用del方法"><a href="#常见错误-10-误用del方法" class="headerlink" title="常见错误 #10: 误用del方法"></a>常见错误 #10: 误用<strong>del</strong>方法</h4><p>假设你有一个名为 calledmod.py 的文件:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import foo</span><br><span class="line"> </span><br><span class="line">class Bar(object):</span><br><span class="line"> ...</span><br><span class="line"> def __del__(self):</span><br><span class="line"> foo.cleanup(self.myhandle)</span><br></pre></td></tr></table></figure><p>并且有一个名为 another_mod.py 的文件:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">import mod</span><br><span class="line">mybar = mod.Bar()</span><br></pre></td></tr></table></figure><p>你会得到一个 AttributeError 的异常。</p><p>为什么呢?因为,正如<a href="https://mail.python.org/pipermail/python-bugs-list/2009-January/069209.html" target="_blank" rel="noopener">这里</a>所说,当解释器退出的时候,模块中的全局变量都被设置成了 None。所以,在上面这个例子中,当 <a href="https://docs.python.org/2/reference/datamodel.html#object.__del__" target="_blank" rel="noopener"><strong>del</strong></a> 被调用时,foo 已经被设置成了None。</p><p>解决方法是使用 <a href="https://docs.python.org/2/library/atexit.html" target="_blank" rel="noopener">atexit.register()</a> 代替。用这种方式,当你的程序结束执行时(意思是正常退出),你注册的处理程序会在解释器退出之前执行。</p><p>了解了这些,我们可以将上面 mod.py 的代码修改成下面的这样:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">import foo</span><br><span class="line">import atexit</span><br><span class="line"> </span><br><span class="line">def cleanup(handle):</span><br><span class="line"> foo.cleanup(handle)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">class Bar(object):</span><br><span class="line"> def __init__(self):</span><br><span class="line"> ...</span><br><span class="line"> atexit.register(cleanup, self.myhandle)</span><br></pre></td></tr></table></figure><p>这种实现方式提供了一个整洁并且可信赖的方法用来在程序退出之前做一些清理工作。很显然,它是由foo.cleanup 来决定对绑定在 self.myhandle 上对象做些什么处理工作的,但是这就是你想要的。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>Python是一门强大的并且很灵活的语言,它有很多机制和语言规范来显著的提高你的生产力。和其他任何一门语言或软件一样,如果对它能力的了解有限,这很可能会给你带来阻碍,而不是好处。正如一句谚语所说的那样 “knowing enough to be dangerous”(译者注:意思是自以为已经了解足够了,可以做某事了,但其实不是)。</p><p>熟悉Python的一些关键的细微之处,像本文中所提到的那些(但不限于这些),可以帮助我们更好的去使用语言,从而避免一些常见的陷阱。</p><p>你可以查看“<a href="http://www.toptal.com/python#hiring-guide" target="_blank" rel="noopener">Python 面试官指南</a>” 来获得一些关于如何辨别一个开发者是否是Python专家的建议。</p><p>我们希望你在这篇文章中找到了一些对你有帮助的东西,并希望你得到你的反馈。</p><blockquote><h3 id="英文原文:Top-10-Mistakes-that-Python-Programmers-Make"><a href="#英文原文:Top-10-Mistakes-that-Python-Programmers-Make" class="headerlink" title="英文原文:Top 10 Mistakes that Python Programmers Make"></a>英文原文:<a href="http://www.toptal.com/python/top-10-mistakes-that-python-programmers-make" target="_blank" rel="noopener">Top 10 Mistakes that Python Programmers Make</a></h3><h4 id="译文:oschina"><a href="#译文:oschina" class="headerlink" title="译文:oschina"></a>译文:<a href="http://www.oschina.net/translate/top-10-mistakes-that-python-programmers-make" target="_blank" rel="noopener">oschina</a></h4></blockquote><section style="text-align: center; font-size: 1em; font-weight: inherit; text-decoration: inherit; color: rgb(255, 255, 255); border-color: rgb(117, 117, 118); box-sizing: border-box;"><section data-width="2em" style="width: 2em; height: 2em; margin-right: auto; margin-left: auto; border-radius: 100%; box-sizing: border-box; background-color: rgb(117, 117, 118);"><section style="display: inline-block; padding-right: 0.5em; padding-left: 0.5em; font-size: 1em; line-height: 2; box-sizing: border-box; color: inherit;"><section class="135brush" data-brushtype="text" style="box-sizing: border-box; color: inherit;">完</section></section></section><section style="margin-top: -1em; margin-bottom: 1em; box-sizing: border-box; color: inherit;"><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: left; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: right; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section></section></section>]]></content>
<tags>
<tag> Python </tag>
<tag> Tips </tag>
</tags>
</entry>
<entry>
<title>Python初学者的17个技巧</title>
<link href="/2016/09/30/Python%E5%88%9D%E5%AD%A6%E8%80%85%E7%9A%8417%E4%B8%AA%E6%8A%80%E5%B7%A7/"/>
<url>/2016/09/30/Python%E5%88%9D%E5%AD%A6%E8%80%85%E7%9A%8417%E4%B8%AA%E6%8A%80%E5%B7%A7/</url>
<content type="html"><![CDATA[<p>   <br>[译]以下是我在Python中,多年来收集的一些有用的快捷键和工具。希望你能在其中找到对你有帮助的。<br><a id="more"></a></p><h4 id="交换变量"><a href="#交换变量" class="headerlink" title="交换变量"></a>交换变量</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">x = 6</span><br><span class="line">y = 5</span><br><span class="line">x, y = y, x</span><br><span class="line">print x</span><br><span class="line">>>> 5</span><br><span class="line">print y</span><br><span class="line">>>> 6</span><br></pre></td></tr></table></figure><h4 id="if-语句在行内"><a href="#if-语句在行内" class="headerlink" title="if 语句在行内"></a>if 语句在行内</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">print "hello" if True else "world"</span><br><span class="line">>>> hello</span><br></pre></td></tr></table></figure><h4 id="连接"><a href="#连接" class="headerlink" title="连接"></a>连接</h4><p>下面的最后一种方式在绑定两个不同类型的对象时显得很酷。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">nfc = ["Packers", "49ers"]</span><br><span class="line">afc = ["Ravens", "Patriots"]</span><br><span class="line">print nfc + afc</span><br><span class="line">>>> ['Packers', '49ers', 'Ravens', 'Patriots']</span><br><span class="line"> </span><br><span class="line">print str(1) + " world"</span><br><span class="line">>>> 1 world</span><br><span class="line"> </span><br><span class="line">print `1` + " world"</span><br><span class="line">>>> 1 world</span><br><span class="line"> </span><br><span class="line">print 1, "world"</span><br><span class="line">>>> 1 world</span><br><span class="line">print nfc, 1</span><br><span class="line">>>> ['Packers', '49ers'] 1</span><br></pre></td></tr></table></figure><h4 id="计算技巧"><a href="#计算技巧" class="headerlink" title="计算技巧"></a>计算技巧</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># 向下取整</span><br><span class="line">print 5.0//2</span><br><span class="line">>>> 2</span><br><span class="line"># 2的5次方</span><br><span class="line">print 2**5</span><br><span class="line">>> 32</span><br></pre></td></tr></table></figure><h4 id="注意浮点数"><a href="#注意浮点数" class="headerlink" title="注意浮点数"></a>注意浮点数</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">print .3/.1</span><br><span class="line">>>> 2.9999999999999996</span><br><span class="line">print .3//.1</span><br><span class="line">>>> 2.0</span><br></pre></td></tr></table></figure><h4 id="数值比较"><a href="#数值比较" class="headerlink" title="数值比较"></a>数值比较</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">x = <span class="number">2</span></span><br><span class="line"><span class="keyword">if</span> <span class="number">3</span> > x > <span class="number">1</span>:</span><br><span class="line"> <span class="keyword">print</span> x</span><br><span class="line"><span class="meta">>>> </span><span class="number">2</span></span><br><span class="line"><span class="keyword">if</span> <span class="number">1</span> < X > <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">print</span> x</span><br><span class="line"><span class="meta">>>> </span><span class="number">2</span></span><br></pre></td></tr></table></figure><h4 id="两个列表同时迭代"><a href="#两个列表同时迭代" class="headerlink" title="两个列表同时迭代"></a>两个列表同时迭代</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">nfc = ["Packers", "49ers"]</span><br><span class="line">afc = ["Ravens", "Patriots"]</span><br><span class="line"> </span><br><span class="line">for teama, teamb in zip(nfc, afc):</span><br><span class="line"> print teama + " vs. " + teamb</span><br><span class="line"> </span><br><span class="line">>>> Packers vs. Ravens</span><br><span class="line">>>> 49ers vs. Patriots</span><br></pre></td></tr></table></figure><h4 id="带索引的列表迭代"><a href="#带索引的列表迭代" class="headerlink" title="带索引的列表迭代"></a>带索引的列表迭代</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">teams = ["Packers", "49ers", "Ravens", "Patriots"]</span><br><span class="line">for index, team in enumerate(teams):</span><br><span class="line"> print index, team</span><br><span class="line"> </span><br><span class="line">>>> 0 Packers</span><br><span class="line">>>> 1 49ers</span><br><span class="line">>>> 2 Ravens</span><br><span class="line">>>> 3 Patriots</span><br></pre></td></tr></table></figure><h4 id="列表推导"><a href="#列表推导" class="headerlink" title="列表推导"></a>列表推导</h4><p>已知一个列表,筛选出偶数列表方法:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">numbers = [1,2,3,4,5,6]</span><br><span class="line">even = []</span><br><span class="line">for number in numbers:</span><br><span class="line">if number%2 == 0:</span><br><span class="line">even.append(number)</span><br></pre></td></tr></table></figure><p>用下面的代替</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">numbers = [1,2,3,4,5,6]</span><br><span class="line">even = [number for number in numbers if number%2 == 0]</span><br></pre></td></tr></table></figure><h4 id="字典推导"><a href="#字典推导" class="headerlink" title="字典推导"></a>字典推导</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">colors = ["red","black","blue","green"]</span><br><span class="line">print {key: value for value, key in enumerate(colors)}</span><br><span class="line">>>> {'blue': 2, 'green': 3, 'black': 1, 'red': 0}</span><br></pre></td></tr></table></figure><h4 id="初始化列表的值"><a href="#初始化列表的值" class="headerlink" title="初始化列表的值"></a>初始化列表的值</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">items = [0]*3</span><br><span class="line">print items</span><br><span class="line">>>> [0, 0, 0]</span><br></pre></td></tr></table></figure><h4 id="将列表转换成字符串"><a href="#将列表转换成字符串" class="headerlink" title="将列表转换成字符串"></a>将列表转换成字符串</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">colors = ["red","black","blue","green"]</span><br><span class="line">print ",".join(colors)</span><br><span class="line">>>> 'red, black, blue, green'</span><br></pre></td></tr></table></figure><h4 id="从字典中获取元素"><a href="#从字典中获取元素" class="headerlink" title="从字典中获取元素"></a>从字典中获取元素</h4><p>虽然用try/except处理也可以比配不到的情况,但这样不是很优雅</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">data = {'user': 1, 'name': 'Max', 'three': 4}</span><br><span class="line">try:</span><br><span class="line"> is_admin = data['admin']</span><br><span class="line">except KeyError:</span><br><span class="line"> is_admin = False</span><br></pre></td></tr></table></figure><p>这样做更好</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">data = {'user': 1, 'name': 'Max', 'three': 4}</span><br><span class="line">is_admin = data.get('admin', False)</span><br></pre></td></tr></table></figure><h4 id="获取子列表"><a href="#获取子列表" class="headerlink" title="获取子列表"></a>获取子列表</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">x = [1,2,3,4,5,6]</span><br><span class="line"> </span><br><span class="line"># 前3个 </span><br><span class="line">print x[:3]</span><br><span class="line">>>> [1,2,3]</span><br><span class="line"> </span><br><span class="line"># 中间4个</span><br><span class="line">print x[1:5]</span><br><span class="line">>>> [2,3,4,5]</span><br><span class="line"> </span><br><span class="line"># 最后3个</span><br><span class="line">print x[-3:]</span><br><span class="line">>>> [4,5,6]</span><br><span class="line"> </span><br><span class="line"># 奇数项</span><br><span class="line">print x[::2]</span><br><span class="line">>>> [1,3,5]</span><br><span class="line"> </span><br><span class="line"># 偶数项</span><br><span class="line">print x[1::2]</span><br><span class="line">>>> [2,4,6]</span><br></pre></td></tr></table></figure><h4 id="60个字符解决FizzBuzz"><a href="#60个字符解决FizzBuzz" class="headerlink" title="60个字符解决FizzBuzz"></a>60个字符解决FizzBuzz</h4><p>前段时间Jeff Atwood 推广了一个简单的编程练习叫FizzBuzz,问题引用如下:</p><blockquote><p>写一个程序,打印数字1到100,3的倍数打印“Fizz”来替换这个数,5的倍数打印“Buzz”,对于既是3的倍数又是5的倍数的数字打印“FizzBuzz”。</p></blockquote><p>这里有一个简短的方法解决这个问题:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">for x in range(1,101):print"Fizz"[x%3*4:]+"Buzz"[x%5*4:]or x</span><br></pre></td></tr></table></figure><h4 id="集合"><a href="#集合" class="headerlink" title="集合"></a>集合</h4><p>用到<code>Counter</code>库</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from collections import Counter</span><br><span class="line">print Counter("hello")</span><br><span class="line">>>> Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})</span><br></pre></td></tr></table></figure><h4 id="迭代工具"><a href="#迭代工具" class="headerlink" title="迭代工具"></a>迭代工具</h4><p>和<code>collections</code>库一样,还有一个库叫<code>itertools</code></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">from itertools import combinations</span><br><span class="line"> </span><br><span class="line">teams = ["Packers", "49ers", "Ravens", "Patriots"]</span><br><span class="line">for game in combinations(teams, 2):</span><br><span class="line"> print game</span><br><span class="line"> </span><br><span class="line">>>> ('Packers', '49ers')</span><br><span class="line">>>> ('Packers', 'Ravens')</span><br><span class="line">>>> ('Packers', 'Patriots')</span><br><span class="line">>>> ('49ers', 'Ravens')</span><br><span class="line">>>> ('49ers', 'Patriots')</span><br><span class="line">>>> ('Ravens', 'Patriots')</span><br></pre></td></tr></table></figure><p>False == True</p><p>在python中,<code>True</code>和<code>False</code>是全局变量,因此</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">False = True</span><br><span class="line">if False:</span><br><span class="line">print "Hello"</span><br><span class="line">else:</span><br><span class="line">print "World"</span><br><span class="line">>>> Hello</span><br></pre></td></tr></table></figure><blockquote><p>原文:<a href="http://www.maxburstein.com/blog/python-shortcuts-for-the-python-beginner/" target="_blank" rel="noopener">Python Shortcuts for the Python Beginner</a></p></blockquote><section style="text-align: center; font-size: 1em; font-weight: inherit; text-decoration: inherit; color: rgb(255, 255, 255); border-color: rgb(117, 117, 118); box-sizing: border-box;"><section data-width="2em" style="width: 2em; height: 2em; margin-right: auto; margin-left: auto; border-radius: 100%; box-sizing: border-box; background-color: rgb(117, 117, 118);"><section style="display: inline-block; padding-right: 0.5em; padding-left: 0.5em; font-size: 1em; line-height: 2; box-sizing: border-box; color: inherit;"><section class="135brush" data-brushtype="text" style="box-sizing: border-box; color: inherit;">完</section></section></section><section style="margin-top: -1em; margin-bottom: 1em; box-sizing: border-box; color: inherit;"><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: left; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: right; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section></section></section>]]></content>
<tags>
<tag> Python </tag>
<tag> Tips </tag>
</tags>
</entry>
<entry>
<title>pyenv-virtualenv使用指南</title>
<link href="/2016/09/07/pyenv-virtualenv%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/"/>
<url>/2016/09/07/pyenv-virtualenv%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</url>
<content type="html"><![CDATA[<p> <br>  简单的说, pyenv 是一个Python管理工具, 这个是和我们常用的 virtualenv 有所不同, 前者是对 Python 的版本进行管理, 实现不同版本的切换和使用. 后者则是创建一个虚拟环境, 与系统环境以及其他 Python 环境隔离, 避免干扰.<br><a id="more"></a><br>简单的说一下使用方法</p><p>####安装不同版本的 Python</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pyenv install <version> #安装特定版本的 Python</span><br><span class="line">pyenv install 3.5.0 #安装 Python 3.5.0</span><br></pre></td></tr></table></figure><p>  当我的系统 Python 版本是 2.7, 但是有个 叫做 py3-project 需要用 Python3 来运行的时候, 只需要这样做:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">cd py3-project #进入项目目录</span><br><span class="line">pyenv local 3.5.0 #将当前目录下的Python环境切换为3.5.0</span><br><span class="line">pyenv version #运行显示通过pyenv设置之后的python版本, 得到结果是3.5.0 </span><br><span class="line">python --version #查看Python版本, 得到结果也是3.5.0</span><br></pre></td></tr></table></figure><p>  此时就可以通过 python3.5 来运行项目了, 在这个项目之外的目录运行 Python, 你会发现仍然是系统版本. 通过pyenv可以给不同的目录设置不同的 Python 版本, 还可以通过 <code>pyenv global</code> 这个命令切换整个全局的 Python版本. 赞爆了是不是.</p><p>告别virtualenv</p><p>  接下来, 再介绍一个工具, 配合pyenv, 让我告别了用了很久了virtualenv.这个工具叫做 pyenv-virtualenv, 安装方法依然跳过, 至于使用, 你只需要记住三条命令:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">pyenv virtualenv 3.5.0 env #创建一个 Python 版本为 3.5.0 的环境, 环境叫做 env</span><br><span class="line">pyenv activate env_name #激活 env 这个环境, 此时 Python 版本自动变为 3.5.0, 且是独立环境</span><br><span class="line">pyenv deactivate #离开已经激活的环境</span><br></pre></td></tr></table></figure><p>嗯, 就酱,Just enjoying!</p><section style="text-align: center; font-size: 1em; font-weight: inherit; text-decoration: inherit; color: rgb(255, 255, 255); border-color: rgb(117, 117, 118); box-sizing: border-box;"><section data-width="2em" style="width: 2em; height: 2em; margin-right: auto; margin-left: auto; border-radius: 100%; box-sizing: border-box; background-color: rgb(117, 117, 118);"><section style="display: inline-block; padding-right: 0.5em; padding-left: 0.5em; font-size: 1em; line-height: 2; box-sizing: border-box; color: inherit;"><section class="135brush" data-brushtype="text" style="box-sizing: border-box; color: inherit;">完</section></section></section><section style="margin-top: -1em; margin-bottom: 1em; box-sizing: border-box; color: inherit;"><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: left; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: right; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section></section></section>]]></content>
<tags>
<tag> Python </tag>
<tag> Pyenv </tag>
<tag> Virtualenv </tag>
</tags>
</entry>
<entry>
<title>《增广贤文》鉴赏</title>
<link href="/2016/09/03/%E3%80%8A%E5%A2%9E%E5%B9%BF%E8%B4%A4%E6%96%87%E3%80%8B%E9%89%B4%E8%B5%8F/"/>
<url>/2016/09/03/%E3%80%8A%E5%A2%9E%E5%B9%BF%E8%B4%A4%E6%96%87%E3%80%8B%E9%89%B4%E8%B5%8F/</url>
<content type="html"><![CDATA[<p>一本可以三代同读的好书<br><a id="more"></a><br>正文如下:</p><p>昔时贤文,诲汝谆谆,集韵增文,多见多闻。</p><p>观今宜鉴古,无古不成今。</p><p>知己知彼,将心比心。</p><p>酒逢知己饮,诗向会人吟。</p><p>相识满天下,知心能几人。</p><p>相逢好似初相识,到老终无怨恨心。</p><p>近水知鱼性,近山识鸟音。</p><p>易涨易退山溪水,易反易覆小人心。</p><p>运去金成铁,时来铁似金,读书须用意,一字值千金。</p><p>逢人且说三分话,未可全抛一片心。</p><p>有意栽花花不发,无心插柳柳成阴。</p><p>画虎画皮难画骨,知人知面不知心。</p><p>钱财如粪土,仁义值千金。</p><p>流水下滩非有意,白云出岫本无心。</p><p>当时若不登高望,谁信东流海洋深。</p><p>路遥知马力,事久见人心。</p><p>两人一般心,无钱堪买金,一人一般心,有钱难买针。</p><p>相见易得好,久住难为人。</p><p>马行无力皆因瘦,人不风流只为贫。</p><p>饶人不是痴汉,痴汉不会饶人。</p><p>是亲不是亲,非亲却是亲。</p><p>美不美,乡中水,亲不亲,故乡人。</p><p>莺花犹怕春光老,岂可教人枉度春。</p><p>相逢不饮空归去,洞口桃花也笑人。</p><p>红粉佳人休使老,风流浪子莫教贫。</p><p>在家不会迎宾客,出外方知少主人。</p><p>黄金无假,阿魏无真。</p><p>客来主不顾,应恐是痴人。</p><p>贫居闹市无人问,富在深山有远亲。</p><p>谁人背后无人说,哪个人前不说人。</p><p>有钱道真语,无钱语不真。</p><p>不信但看筵中酒,杯杯先劝有钱人。</p><p>闹里有钱,静处安身。</p><p>来如风雨,去似微尘。</p><p>长江后浪推前浪,世上新人赶旧人。</p><p>近水楼台先得月,向阳花木早逢春。</p><p>莫道君行早,更有早行人。</p><p>莫信直中直,须防仁不仁。</p><p>山中有直树,世上无直人。</p><p>自恨枝无叶,莫怨太阳偏。</p><p>大家都是命,半点不由人。</p><p>一年之计在于春,一日之计在于寅,一家之计在于和,一生之计在于勤。</p><p>责人之心责己,恕己之心恕人。</p><p>守口如瓶,防意如城。</p><p>宁可人负我,切莫我负人。</p><p>再三须慎意,第一莫欺心。</p><p>虎生犹可近,人熟不堪亲。</p><p>来说是非者,便是是非人。</p><p>远水难救近火,远亲不如近邻。</p><p>有茶有酒多兄弟,急难何曾见一人。</p><p>人情似纸张张薄,世事如棋局局新。</p><p>山中也有千年树,世上难逢百岁人。</p><p>力微休负重,言轻莫劝人。</p><p>无钱休入众,遭难莫寻亲。</p><p>平生莫作皱眉事,世上应无切齿人。</p><p>士者国之宝,儒为席上珍。</p><p>若要断酒法,醒眼看醉人。</p><p>求人须求大丈夫,济人须济急时无。</p><p>渴时一滴如甘露,醉后添杯不如无。</p><p>久住令人贱,频来亲也疏。</p><p>酒中不语真君子,财上分明大丈夫。</p><p>出家如初,成佛有余。</p><p>积金千两,不如明解经书。</p><p>养子不教如养驴,养女不教如养猪。</p><p>有田不耕仓廪虚,有书不读子孙愚。</p><p>仓廪虚兮岁月乏,子孙愚兮礼义疏。</p><p>同君一席话,胜读十年书。</p><p>人不通今古,马牛如襟裾。</p><p>茫茫四海人无数,哪个男儿是丈夫。</p><p>白酒酿成缘好客,黄金散尽为收书。</p><p>救人一命,胜造七级浮屠。</p><p>城门失火,殃及池鱼。</p><p>庭前生瑞草,好事不如无。</p><p>欲求生富贵,须下死工夫。</p><p>百年成之不足,一旦败之有余。</p><p>人心似铁,官法如炉。</p><p>善化不足,恶化有余。</p><p>水太清则无鱼,人至察则无徒。</p><p>知者减半,省者全无。</p><p>在家由父,出家从夫。</p><p>痴人畏妇,贤女敬夫。</p><p>是非终日有,不听自然无。</p><p>宁可正而不足,不可邪而有余。</p><p>宁可信其有,不可信其无。</p><p>竹篱茅舍风光好,道院僧堂终不如。</p><p>命里有时终须有,命里无时莫强求。</p><p>道院迎仙客,书堂隐相儒。</p><p>庭栽栖凤竹,池养化龙鱼。</p><p>结交须胜己,似我不如无。</p><p>但看三五日,相见不如初。</p><p>人情似水分高下,世事如云任卷舒。</p><p>会说说都是,不会说无礼。</p><p>磨刀恨不利,刀利伤人指。</p><p>求财恨不得,财多害自己。</p><p>知足常足,终身不辱。</p><p>知止常止,终身不耻。</p><p>有福伤财,无福伤己。</p><p>差之毫厘,失之千里。</p><p>若登高必自卑,若涉远必自迩。</p><p>三思而行,再思可矣。</p><p>使口不如自走,求人不如求己。</p><p>小时是兄弟,长大各乡里。</p><p>妒财莫妒食,怨生莫怨死。</p><p>人见白头嗔,我见白头喜。</p><p>多少少年亡,不到白头死。</p><p>墙有逢,壁有耳。</p><p>好事不出门,恶事传千里。</p><p>贼是小人,知过君子。</p><p>君子固穷,小人穷斯滥也。</p><p>贫穷自在,富贵多忧。</p><p>不以我为德,反以我为仇。</p><p>宁向直中取,不可曲中求。</p><p>人无远虑,必有近忧。</p><p>知我者为我心忧,不知我者谓我何求。</p><p>晴天不肯去,只待雨淋头。</p><p>成事莫说,覆水难收。</p><p>是非只为多开口,烦恼皆因强出头。</p><p>忍得一时之气,免得百日之忧。</p><p>近来学得乌龟法,得缩头时且缩头。</p><p>惧法朝朝乐,欺公日日忧。</p><p>人生一世,草生一春。</p><p>黑发不知勤学早,看看又是白头翁。</p><p>月到十五光明少,人到中年万事休。</p><p>儿孙自有儿孙福,莫为儿孙作马牛。</p><p>人生不满百,常怀千岁忧。</p><p>今朝有酒今朝醉,明日愁来明日忧。</p><p>路逢险处难回避,事到头来不自由。</p><p>药能医假病,酒不解真愁。</p><p>人贫不语,水平不流。</p><p>一家有女百家求,一马不行百马忧。</p><p>有花方酌酒,无月不登楼。</p><p>三杯通大道,一醉解千愁。</p><p>深山毕竟藏猛虎,大海终须纳细流。</p><p>惜花须检点,爱月不梳头。</p><p>大抵选他肌骨好,不擦红粉也风流。</p><p>受恩深处宜先退,得意浓时便可休。</p><p>莫待是非来入耳,从前恩爱反为仇。</p><p>留得五湖明月在,不愁无处下金钩。</p><p>休别有鱼处,莫恋浅滩头。</p><p>去时终须去,再三留不住。</p><p>忍一句,息一怒,饶一着,退一步。</p><p>三十不豪,四十不富,五十将来寻死路。</p><p>生不论魂,死不认尸。</p><p>父母恩深终有别,夫妻义重也分离。</p><p>人生似鸟同林宿,大限来时各自飞。</p><p>人善被人欺,马善被人骑。</p><p>人无横财不富,马无野草不肥。</p><p>人恶人怕天不怕,人善人欺天不欺。</p><p>善恶到头终有报,只争来早与来迟。</p><p>黄河尚有澄清日,岂可人无得运时。</p><p>得宠思辱,安居虑危。</p><p>念念有如临敌日,心心常似过桥时。</p><p>英雄行险道,富贵似花枝。</p><p>人情莫道春光好,只怕秋来有冷时。</p><p>送君千里,终须一别。</p><p>但将冷眼看螃蟹,看你横行到几时。</p><p>见事莫说,问事不知。</p><p>闲事休管,无事早归。</p><p>假缎染就真红色,也被旁人说是非。</p><p>善事可作,恶事莫为。</p><p>许人一物,千金不移。</p><p>龙生龙子,虎生豹儿。</p><p>龙游浅水遭虾戏,虎落平阳被犬欺。</p><p>一举首登龙虎榜,十年身到风凰池。</p><p>十年窗下无人问,一举成名天下知。</p><p>酒债寻常行处有,人生七十古来稀。</p><p>养儿待老,积谷防饥。</p><p>鸡豚狗彘之畜,无失其时。</p><p>数家之口,可以无饥矣。</p><p>常将有日思无日,莫把无时当有时。</p><p>时来风送腾王阁,运去雷轰荐福碑。</p><p>入门休问荣枯事,观看容颜便得知。</p><p>官清书吏瘦,神灵庙祝肥。</p><p>息却雷霆之怒,罢却虎狼之威。</p><p>饶人算人之本,输人算人之机。</p><p>好言难得,恶语易施。</p><p>一言既出,驷马难追。</p><p>道吾好者是吾贼,道吾恶者是吾师。</p><p>路逢侠客须呈剑,不是才人莫献诗。</p><p>三人同行,必有我师,择其善者而从之,其不善者而改之。</p><p>少壮不努力,老大徒悲伤。</p><p>人有善愿,天必佑之。</p><p>莫饮卯时酒,昏昏醉到酉。</p><p>莫骂酉时妻,一夜受孤凄。</p><p>种麻得麻,种豆得豆。</p><p>天眼恢恢,疏而不漏。</p><p>见官莫向前,做客莫在后。</p><p>宁添一斗,莫添一口。</p><p>螳螂捕蝉,岂知黄雀在后。</p><p>不求金玉重重贵,但愿儿孙个个贤。</p><p>一日夫妻,百世姻缘。</p><p>百世修来同船渡,千世修来共枕眠。</p><p>杀人一万,自损三千。</p><p>伤人一语,利如刀割。</p><p>枯木逢春犹再发,人无两度再少年。</p><p>未晚先投宿,鸡鸣早看天。</p><p>将相胸前堪走马,公候肚里好撑船。</p><p>富人思来年,穷人思眼前。</p><p>世上若要人情好,赊去物件莫取钱。</p><p>死生有命,富贵在天。</p><p>击石原有火,不击乃无烟。</p><p>为学始知道,不学亦徒然。</p><p>莫笑他人老,终须还到老。</p><p>但能依本分,终须无烦恼。</p><p>君子爱财,取之有道。</p><p>贞妇爱色,纳之以礼。</p><p>善有善报,恶有恶报。</p><p>不是不报,日子不到。</p><p>人而无信,不知其可也。</p><p>一人道好,千人传实。</p><p>凡事要好,须问三老。</p><p>若争小可,便失大道。</p><p>年年防饥,夜夜防盗。</p><p>学者如禾如稻,不学者如蒿如草。</p><p>遇饮酒时须饮酒,得高歌处且高歌。</p><p>因风吹火,用力不多。</p><p>不因渔父引,怎得见波涛。</p><p>无求到处人情好,不饮从他酒价高。</p><p>知事少时烦恼少,识人多处是非多。</p><p>入山不怕伤人虎,只怕人情两面刀。</p><p>强中更有强中手,恶人须用恶人磨。</p><p>会使不在家豪富,风流不用着衣多。</p><p>光阴似箭,日月如梭。</p><p>天时不如地利,地利不如人和。</p><p>黄金未为贵,安乐值钱多。</p><p>世上万般皆下品,思量唯有读书高。</p><p>世间好语书说尽,天下名山僧占多。</p><p>为善最乐,为恶难逃。</p><p>羊有跪乳之恩,鸦有反哺之义。</p><p>你急他未急,人闲心不闲。</p><p>隐恶扬善,执其两端。</p><p>妻贤夫祸少,子孝父心宽。</p><p>既坠釜甑,反顾无益。</p><p>翻覆之水,收之实难。</p><p>人生知足何时足,人老偷闲且是闲。</p><p>但有绿杨堪系马,处处有路透长安。</p><p>见者易,学者难。</p><p>莫将容易得,便作等闲看。</p><p>用心计较般般错,退步思量事事难。</p><p>道路各别,养家一般。</p><p>从俭入奢易,从奢入俭难。</p><p>知音说与知音听,不是知音莫与弹。</p><p>点石化为金,人心犹未足。</p><p>信了肚,卖了屋。</p><p>他人观花,不涉你目。</p><p>他人碌碌,不涉你足。</p><p>谁人不爱子孙贤,谁人不爱千钟粟。</p><p>莫把真心空计较,五行不是这题目。</p><p>与人不和,劝人养鹅。</p><p>与人不睦,劝人架屋。</p><p>但行好事,莫问前程。</p><p>河狭水急,人急计生。</p><p>明知山有虎,莫向虎山行。</p><p>路不行不到,事不为不成。</p><p>人不劝不善,钟不打不鸣。</p><p>无钱方断酒,临老始看经。</p><p>点塔七层,不如暗处一灯。</p><p>万事劝人休瞒昧,举头三尺有神明。</p><p>但存方寸土,留与子孙耕。</p><p>灭却心头火,剔起佛前灯。</p><p>惺惺常不足,懵懵作公卿。</p><p>众星朗朗,不如孤月独明。</p><p>兄弟相害,不如自生。</p><p>合理可作,小利莫争。</p><p>牡丹花好空入目,枣花虽小结实成。</p><p>欺老莫欺小,欺人心不明。</p><p>随分耕锄收地利,他时饱满谢苍天。</p><p>得忍且忍,得耐且耐。</p><p>不忍不耐,小事成大。</p><p>相论逞英雄,家计渐渐退。</p><p>贤妇令夫贵,恶妇令夫败。</p><p>一人有庆,兆民咸赖。</p><p>人老心未老,人穷志莫穷。</p><p>人无千日好,花无百日红。</p><p>杀人可恕,情理难容。</p><p>乍富不知新受用,乍贫难改旧家风。</p><p>座上客常满,樽中酒不空。</p><p>屋漏更遭连年雨,行船又遇打头风。</p><p>笋因落箨方成竹,鱼为奔波始化龙。</p><p>记得少年骑竹马,看看又是白头翁。</p><p>礼义生于富足,盗贼出于贫穷。</p><p>天上众星皆拱北,世间无水不朝东。</p><p>君子安平,达人知命。</p><p>忠言逆耳利于行,良药苦口利于病。</p><p>顺天者存,逆天者亡。</p><p>人为财死,鸟为食亡。</p><p>夫妻相合好,琴瑟与笙簧。</p><p>有儿贫不久,无子富不长。</p><p>善必寿老,恶必早亡。</p><p>爽口食多偏作药,快心事过恐生殃。</p><p>富贵定要安本分,贫穷不必枉思量。</p><p>画水无风空作浪,绣花虽好不闻香。</p><p>贪他一斗米,失却半年粮。</p><p>争他一脚豚,反失一肘羊。</p><p>龙归晚洞云犹湿,麝过春山草木香。</p><p>平生只会量人短,何不回头把自量。</p><p>见善如不及,见恶如探汤。</p><p>人贫志短,马瘦毛长。</p><p>自家心里急,他人未知忙。</p><p>贫无达士将金赠,病有高人说药方。</p><p>触来莫与说,事过心清凉。</p><p>秋至满山多秀色,春来无处不花香。</p><p>凡人不可貌相,海水不可斗量。</p><p>清清之水,为土所防。</p><p>济济之士,为酒所伤。</p><p>蒿草之下,或有兰香。</p><p>茅茨之屋,或有侯王。</p><p>无限朱门生饿殍,几多白屋出卿。</p><p>醉后乾坤大,壶中日月长。</p><p>万事皆已定,浮生空白茫。</p><p>千里送毫毛,礼轻仁义重。</p><p>一人传虚,百人传实。</p><p>世事明如镜,前程暗似漆。</p><p>光阴黄金难买,一世如驹过隙。</p><p>良田万倾,日食一升。</p><p>大厦千间,夜眠八尺。</p><p>千经万典,孝义为先。</p><p>一字入公门,九牛拖不出。</p><p>衙门八字开,有理无钱莫进来。</p><p>富从升合起,贫因不算来。</p><p>家中无才子,官从何处来。</p><p>万事不由人计较,一生都是命安排。</p><p>急行慢行,前程只有多少路。</p><p>人间私语,天闻若雷。</p><p>暗室亏心,神目如电。</p><p>一毫之恶,劝人莫作。</p><p>一毫之善,与人方便。</p><p>欺人是祸,饶人是福。</p><p>天眼恢恢,报应甚速。</p><p>圣贤言语,神钦鬼伏。</p><p>人各有心,心各有见。</p><p>口说不如身逢,耳闻不如目见。</p><p>养军千日,用在一朝。</p><p>国清才子贵,家富小儿骄。</p><p>利刀割体痕易合,恶语伤人恨不消。</p><p>公道世间唯白发,贵人头上不曾饶。</p><p>有钱堪出众,无衣懒出门。</p><p>为官须作相,及第必争先。</p><p>苗从地发,树向枝分。</p><p>父子和而家不退,兄弟和而家不分。</p><p>官有正条,民有和约。</p><p>闲时不烧香,急时抱佛脚。</p><p>幸生太平无事日,恐逢年老不多时。</p><p>国乱思良将,家贫思贤妻。</p><p>池塘积水须防旱,田地勤耕足养家。</p><p>根深不怕风摇动,树正无愁月影斜。</p><p>奉劝君子,各宜守己。</p><p>只此程式,万无一失。</p><p><section style="text-align: center; font-size: 1em; font-weight: inherit; text-decoration: inherit; color: rgb(255, 255, 255); border-color: rgb(117, 117, 118); box-sizing: border-box;"><section data-width="2em" style="width: 2em; height: 2em; margin-right: auto; margin-left: auto; border-radius: 100%; box-sizing: border-box; background-color: rgb(117, 117, 118);"><section style="display: inline-block; padding-right: 0.5em; padding-left: 0.5em; font-size: 1em; line-height: 2; box-sizing: border-box; color: inherit;"><section class="135brush" data-brushtype="text" style="box-sizing: border-box; color: inherit;">完</section></section></section><section style="margin-top: -1em; margin-bottom: 1em; box-sizing: border-box; color: inherit;"><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: left; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: right; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section></section></section><br><br></p>]]></content>
<tags>
<tag> 生活 </tag>
</tags>
</entry>
<entry>
<title>为什么要写Blog?</title>
<link href="/2016/09/01/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%86%99%E5%8D%9A%E5%AE%A2/"/>
<url>/2016/09/01/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%86%99%E5%8D%9A%E5%AE%A2/</url>
<content type="html"><![CDATA[<!-- - 'https://api.i-meto.com/bing?2016-09-01 12:52:00' --><p> <br> Darren Rowse在他的Blog上,讲到了7个理由,我觉得说得很好。<br><a id="more"></a></p><ol><li>学会写作Blog的技巧(teach you the skills of blogging)<br>没有人天生会写Blog,我刚开始的时候也不知道该怎么写。但是,经过不断的尝试,现在我知道怎么可以写出受欢迎的文章。</li><li>熟悉Blog工具(familiarize you with the tools of blogging)<br>写作Blog,可以选择自己搭建平台,也可以选择网上的免费Blog提供商。我曾经试用过不少Blog软件,最后才选择了现在的Moveable Type,这本身也是一个学习过程。</li><li>便于更好地安排时间(help you work out how much time you have)<br>写作Blog花费的时间,要比大家想象的多,甚至也比我自己想象的多。但是,另一方面,每天我们又有很多时间被无谓地浪费了。坚持写作Blog的过程,也是进行更好的时间安排的过程。</li><li>便于你了解自己是否可以长期做一件喜欢的事情(help you work out if you can sustain blogging for the long term)<br>很多人都有自己的爱好,但是只有当你享受到这种爱好时,你才会长期坚持下去。写作Blog可以帮助你体验到这种感觉。</li><li>便于体验Blog文化(give you a taste of blogging ‘culture’)<br>Blog的世界有一种无形的礼仪、风格和用语。熟悉它们,会使你更好地表达自己和理解他人。</li><li>便于你形成和了解自我(help you define a niche)<br>长期写作Blog最大的好处之一就是,写着写着,你的自我会变得越来越清晰。你最终会明白自己是一个什么样的人,以及自己热爱的又是什么东西。</li><li>帮助你找到读者(help you find a readership)<br>与他人交流是生命最大的乐趣之一。写作Blog可以帮助我们更好地做到这一点。</li></ol><p>  如果你觉得你想说的东西不适宜让他人知道,你可以在自己的电脑里写,不用放到网上。这样除了上面第7点以外,其他6点的好处也还是适用的。<br>总之,正是因为以上7个理由,所以我强烈建议,每一个朋友都应该有一个自己的Blog,尝试将自己的生活和想法记录下来,留下一些印记。</p><section style="text-align: center; font-size: 1em; font-weight: inherit; text-decoration: inherit; color: rgb(255, 255, 255); border-color: rgb(117, 117, 118); box-sizing: border-box;"><section data-width="2em" style="width: 2em; height: 2em; margin-right: auto; margin-left: auto; border-radius: 100%; box-sizing: border-box; background-color: rgb(117, 117, 118);"><section style="display: inline-block; padding-right: 0.5em; padding-left: 0.5em; font-size: 1em; line-height: 2; box-sizing: border-box; color: inherit;"><section class="135brush" data-brushtype="text" style="box-sizing: border-box; color: inherit;">完</section></section></section><section style="margin-top: -1em; margin-bottom: 1em; box-sizing: border-box; color: inherit;"><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: left; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section><section data-width="35%" style="border-top-width: 1px; border-top-style: solid; width: 35%; float: right; border-color: rgb(117, 117, 118); box-sizing: border-box; color: inherit;"></section></section></section>]]></content>
<tags>
<tag> 生活 </tag>
</tags>
</entry>
</search>