<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Chen Yufei's blog &#187; python</title>
	<atom:link href="http://chenyufei.info/blog/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://chenyufei.info/blog</link>
	<description>Keep your head about you while all those are losing theirs</description>
	<lastBuildDate>Wed, 21 Jul 2010 05:30:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Get the current module in Python</title>
		<link>http://chenyufei.info/blog/2009-12-31/get-the-current-module-in-python/</link>
		<comments>http://chenyufei.info/blog/2009-12-31/get-the-current-module-in-python/#comments</comments>
		<pubDate>Thu, 31 Dec 2009 02:47:37 +0000</pubDate>
		<dc:creator>chenyufei</dc:creator>
				<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://chenyufei.info/blog/?p=290</guid>
		<description><![CDATA[It&#8217;s sometimes useful to do introspection on the module itself you are writing. But python doesn&#8217;t provide any direct way to support this. In fact a PEP about this feature has been rejected. A little google find a solution to this problem. Here&#8217;s the code import sys # get the current module's name modname = [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s sometimes useful to do introspection on the module itself you are writing. But python doesn&#8217;t provide any direct way to support this. In fact a <a href="http://www.python.org/dev/peps/pep-3130/">PEP about this feature</a> has been rejected.</p>
<p>A little google find <a href="http://old.nabble.com/How-to-get-current-module-object-td15532853.html">a solution</a> to this problem. Here&#8217;s the code</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
<span style="color: #808080; font-style: italic;"># get the current module's name</span>
modname = <span style="color: #008000;">globals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'__name__'</span><span style="color: black;">&#93;</span>
<span style="color: #808080; font-style: italic;"># get the module</span>
module = <span style="color: #dc143c;">sys</span>.<span style="color: black;">modules</span><span style="color: black;">&#91;</span>modname<span style="color: black;">&#93;</span>
<span style="color: #808080; font-style: italic;"># or more simply as suggested by E.T</span>
module = <span style="color: #dc143c;">sys</span>.<span style="color: black;">modules</span><span style="color: black;">&#91;</span>__name__<span style="color: black;">&#93;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://chenyufei.info/blog/2009-12-31/get-the-current-module-in-python/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Reviewboard, PIL and virtualenv</title>
		<link>http://chenyufei.info/blog/2009-12-02/reviewboard-pil-and-virtualenv/</link>
		<comments>http://chenyufei.info/blog/2009-12-02/reviewboard-pil-and-virtualenv/#comments</comments>
		<pubDate>Wed, 02 Dec 2009 06:44:27 +0000</pubDate>
		<dc:creator>chenyufei</dc:creator>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[reviewboard]]></category>
		<category><![CDATA[virtualenv]]></category>

		<guid isPermaLink="false">http://chenyufei.info/blog/2009-12-02/reviewboard-pil-and-virtualenv/</guid>
		<description><![CDATA[I created a separate no site-packages virtualenv directory, and use easy_install to install Reviewboard. However, easy_install installs PIL version 1.1.7 which does not work with the latest stable Reviewboard version 1.0.5.1. Using easy_install PIL==1.1.6 doesn&#8217;t work because of build error. The workaround is to manually download PIL and install it. To make reviewboard work under [...]]]></description>
			<content:encoded><![CDATA[<p>I created a separate no site-packages virtualenv directory, and use easy_install to install Reviewboard.</p>
<p>However, easy_install installs PIL version 1.1.7 which does not work with the latest stable Reviewboard version 1.0.5.1.</p>
<p>Using easy_install PIL==1.1.6 doesn&#8217;t work because of build error. The workaround is to manually download PIL and install it.</p>
<p>To make reviewboard work under virtualenv, additional steps are needed, which in fact are steps for Django application to work under virtualenv.</p>
<ul>
<li>If you use mod_python and apache, <a href="http://mydjangoblog.com/2009/03/30/django-mod_python-and-virtualenv/">this article</a> maybe useful. This works for Reviewboard.</li>
<li>For mod_wsgi, <a href="http://www.danceric.net/2009/03/26/django-virtualenv-and-mod_wsgi/">look here</a>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://chenyufei.info/blog/2009-12-02/reviewboard-pil-and-virtualenv/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>我也来推荐 bpython</title>
		<link>http://chenyufei.info/blog/2009-11-12/recommend-bpython/</link>
		<comments>http://chenyufei.info/blog/2009-11-12/recommend-bpython/#comments</comments>
		<pubDate>Thu, 12 Nov 2009 13:51:10 +0000</pubDate>
		<dc:creator>chenyufei</dc:creator>
				<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://chenyufei.info/blog/?p=262</guid>
		<description><![CDATA[在光华上看到 Zellux 推荐的，bpython。 bpython 对输入的代码有高亮显示，输入代码同时自动补全，不需要按 tab，调用函数时打完左括号文档就自动出现。 现在只是刚刚试了一下，印象不错。 有些 ipython 支持的功能 bpython 里没有，现在发现的是不支持直接执行 shell 命令。（文件名补全的话当前目录的要用 ./ 以后才会出来。）]]></description>
			<content:encoded><![CDATA[<p>在光华上看到 <a href="http://techblog.iamzellux.com/">Zellux</a> 推荐的，<a href="http://www.bpython-interpreter.org/about/">bpython</a>。</p>
<p>bpython 对输入的代码有高亮显示，输入代码同时自动补全，不需要按 tab，调用函数时打完左括号文档就自动出现。</p>
<p>现在只是刚刚试了一下，印象不错。</p>
<p>有些 ipython 支持的功能 bpython 里没有，现在发现的是不支持直接执行 shell 命令。（文件名补全的话当前目录的要用 ./ 以后才会出来。）</p>
]]></content:encoded>
			<wfw:commentRss>http://chenyufei.info/blog/2009-11-12/recommend-bpython/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Shell like data processing in Python &#8212; using decorators</title>
		<link>http://chenyufei.info/blog/2009-10-03/shell-like-data-processing-in-python-using-decorators/</link>
		<comments>http://chenyufei.info/blog/2009-10-03/shell-like-data-processing-in-python-using-decorators/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 15:31:29 +0000</pubDate>
		<dc:creator>chenyufei</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[decorator]]></category>
		<category><![CDATA[pipe]]></category>

		<guid isPermaLink="false">http://chenyufei.info/blog/?p=232</guid>
		<description><![CDATA[前面的文章展示了管道的好处，以及在 Python 程序中利用管道的思想。但是前面文章里的代码还有一点缺陷，看下面的 shell 脚本和 Python 代码的比较： find logdir -name "access-log*" &#124; \ xargs cat &#124; \ grep '[^-]$' &#124; \ awk '{ total += $NF } END { print total }' lines = grep&#40;'[^-]$', cat&#40;find&#40;'logdir', 'access-log*'&#41;&#41;&#41; col = &#40;line.rsplit&#40;None, 1&#41;&#91;1&#93; for line in lines&#41; print sum&#40;int&#40;c&#41; for c in col&#41; Python 中 find, cat, [...]]]></description>
			<content:encoded><![CDATA[<p>前面的文章展示了<a href="http://chenyufei.info/blog/2009-01-19/why-unix-pipe-is-a-good-thing/">管道的好处</a>，以及在 Python 程序中<a href="http://chenyufei.info/blog/2009-01-28/writing-unix-pipe-style-python-code/">利用管道的思想</a>。但是前面文章里的代码还有一点缺陷，看下面的 shell 脚本和 Python 代码的比较：</p>
<pre>
find logdir -name "access-log*" | \
xargs cat | \
grep '[^-]$' | \
awk '{ total += $NF } END { print total }'
</pre>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">lines = grep<span style="color: black;">&#40;</span><span style="color: #483d8b;">'[^-]$'</span>, cat<span style="color: black;">&#40;</span>find<span style="color: black;">&#40;</span><span style="color: #483d8b;">'logdir'</span>, <span style="color: #483d8b;">'access-log*'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
col = <span style="color: black;">&#40;</span>line.<span style="color: black;">rsplit</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> lines<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>c<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> c <span style="color: #ff7700;font-weight:bold;">in</span> col<span style="color: black;">&#41;</span></pre></div></div>

<p>Python 中 find, cat, grep 的调用用一层层的括号嵌套起来进行调用，执行顺序是从最内部的括号开始，可读性没有 shell 脚本好。可不可能在 Python 脚本中用类似 shell 脚本里的语法来提高可读性？用运算符重载就可以做到了。最初的想法<a href="http://code.activestate.com/recipes/276960/">来自这里</a>，这个例子用的方法是重载或运算符 &#8220;|&#8221;。新的 Python 代码如下，我把这样的代码称为 pipe syntax (抽取最后一列并求和的代码不变。)</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">lines = find<span style="color: black;">&#40;</span><span style="color: #483d8b;">'logdir'</span>, <span style="color: #483d8b;">'access-log*'</span><span style="color: black;">&#41;</span> | cat | grep<span style="color: black;">&#40;</span><span style="color: #483d8b;">'[^-]$'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>用运算符重载的方法把一个函数放在管道中必须自己定义一个类，在 override 的 <code>__ror__()</code> 函数中完成实际的工作。每次都要定义一个类我觉得不够方便，因此我用 decorator 来进行简化。</p>
<p><strong>简单来说 decorator 通过用其他对象替换原来的函数来改变函数的行为</strong>。对 decorator 的介绍可以参考 Bruce Eckel 的两篇文章，分别介绍了<a href="http://www.artima.com/weblogs/viewpost.jsp?thread=240808">无参数</a>和<a href="http://www.artima.com/weblogs/viewpost.jsp?thread=240845">有参数</a>的 decorator 如何创建，无参数的那篇文章还介绍了 decoractor 的作用。Bruce Eckel 认为 decorator 就像是宏一样，可以改变函数的语义。他还认为 Python 的 decorator 就像 Lisp 的宏一样 powerful。对这一点我不太赞同，两者差别还是很大的，decorator 其实只是提供了在运行时动态地替换函数的功能，而 Lisp 的宏是在编译时生成代码，要说 powerful 肯定还是 Lisp 的宏更强，但 decorator 更简单而且也已经足够 powerful 了。</p>
<p>使用 decorator 来定义 cat 的代码如下，函数前的 &#8220;@&#8221; 是为了支持 decorator 而引入的新的语法：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@pipeable
<span style="color: #ff7700;font-weight:bold;">def</span> grep<span style="color: black;">&#40;</span><span style="color: #008000;">iter</span>, match<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">callable</span><span style="color: black;">&#40;</span>match<span style="color: black;">&#41;</span>:
        fun = match
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        fun = <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>match<span style="color: black;">&#41;</span>.<span style="color: black;">match</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> ifilter<span style="color: black;">&#40;</span>fun, <span style="color: #008000;">iter</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Without @pipeable before the function definition of grep,</span>
<span style="color: #808080; font-style: italic;"># we can use the following code to achieve the same effect.</span>
grep = pipeable<span style="color: black;">&#40;</span>grep<span style="color: black;">&#41;</span></pre></div></div>

<p>pipeable 其实只是一个普通的 Python 对象，可以是一个函数，也可以是一个类。如果是函数，那么 grep 就是给它的参数；如果是类，grep 是给它的初始化函数的参数。<strong>pipeable(grep) 必须返回一个能够调用的对象（含有 <code>__call__()</code> 方法）</strong>，除此之外没有其他要求。可见，decorator syntax 只是语法糖而已，但这个语法糖使得我们可以在函数之前加上修饰，而且从代码上一下就可以看出 grep 可以用在管道中。</p>
<p>下面首先描述 pipeable 修饰函数的要求和修饰后的行为，然后再看 pipeable 的实现。</p>
<p>可以用 pipeable 进行修饰的函数只有一个要求，第一个参数必须支持遍历操作。如果这个函数之后还有其他管道，那么函数的返回值也需要支持遍历。</p>
<p>被 pipeable 修饰之后，函数的行为如下：</p>
<ol>
<li>可以像没有修饰过时一样调用，函数行为不变</li>
<li>调用时给定除了第一个参数以外的所有参数，当函数对象出现在 &#8220;|&#8221; 右侧时，将左侧对象作为函数的第一个参数，与之前的参数一起完成函数的调用。</li>
</ol>
<p>用来实现 pipe syntax 的 decorator 如下（完整代码<a href='http://chenyufei.info/blog/wp-content/uploads/2009/10/shelike.py'>shelike.py</a>）。</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> functools <span style="color: #ff7700;font-weight:bold;">import</span> update_wrapper
<span style="color: #ff7700;font-weight:bold;">class</span> pipeable:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, method<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">func</span> = method
        <span style="color: #008000;">self</span>.<span style="color: black;">args</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">kwds</span> = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">reqlen</span> = <span style="color: #ff4500;">0</span>
        <span style="color: #808080; font-style: italic;"># Since we need to allow classes to be used in pipe, there are cases that</span>
        <span style="color: #808080; font-style: italic;"># method is not a function.</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">func</span>, <span style="color: #483d8b;">'func_code'</span><span style="color: black;">&#41;</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">reqlen</span> = <span style="color: #008000;">self</span>.<span style="color: black;">func</span>.<span style="color: black;">func_code</span>.<span style="color: black;">co_argcount</span>
        <span style="color: #808080; font-style: italic;"># makes the wrapper object looks like the wrapped function</span>
        update_wrapper<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, method<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__call__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwds<span style="color: black;">&#41;</span>:
        curlen = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>args<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># An ugly hack to handle classes.</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> curlen == <span style="color: #008000;">self</span>.<span style="color: black;">reqlen</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff4500;">0</span> == <span style="color: #008000;">self</span>.<span style="color: black;">reqlen</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">func</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwds<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">elif</span> curlen <span style="color: #66cc66;">!</span>= <span style="color: #008000;">self</span>.<span style="color: black;">reqlen</span> - <span style="color: #ff4500;">1</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">TypeError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Arguments number wrong.'</span><span style="color: black;">&#41;</span>
&nbsp;
        cpy = deepcopy<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        cpy.<span style="color: black;">args</span> = args
        cpy.<span style="color: black;">kwds</span> = kwds
        <span style="color: #ff7700;font-weight:bold;">return</span> cpy
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__ror__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #008000;">iter</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">func</span><span style="color: black;">&#40;</span><span style="color: #008000;">iter</span>, <span style="color: #66cc66;">*</span><span style="color: #008000;">self</span>.<span style="color: black;">args</span>, <span style="color: #66cc66;">**</span><span style="color: #008000;">self</span>.<span style="color: black;">kwds</span><span style="color: black;">&#41;</span></pre></div></div>

<p>由于修改后的对象需要支持 &#8220;|&#8221; 运算符，pipeable 用类的形式实现更方便。（看了 Bruce Eckel 的文章后我也偏好用类来创建 decorator。）</p>
<ol>
<li>
<code>__init__()</code> 接受要修饰的函数，保存起来以备后面调用，这个函数在函数被修饰时执行，实际上就是创建一个pipeable 对象，把原先函数名赋给这个对象。最后的 update_wrapper 把被修饰函数的 <code>__name__, __doc__, __module__</code> 属性拷贝到创建的对象上，这样这个对象看起来就更加像原先的函数。（否则这些属性的值的都是这个对象的值。）
</li>
<li>
<code>__call__()</code> 在被修饰函数/替换的对象被调用时执行，这里根据参数个数直接调用原函数或者把参数保存起来</li>
<li>
<code>__ror__()</code> 就是实现 pipe syntax 的关键，把 &#8220;|&#8221; 左边的序列和其他参数组合起来完成被修饰函数的调用。有些 ugly hack 是为了处理 class 作为初始化参数的情况</li>
</ol>
<p>要把 shell 里的常用命令一个个用 Python 再实现一下也比较麻烦，因此我还实现了一个函数用来把 Python 里的数据转成字符串直接调用 shell 命令来处理，处理完再转成一行一行的 Python 字符串。比较下用 pipeable 和自己定义一个 class 的实现代码（现在的处理方式是把输入一次性全部转成字符串通过 OS 的管道传给外部程序，数据量大的话内存开销比较大，但我没有想到好的解决办法。）</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@pipeable
<span style="color: #ff7700;font-weight:bold;">def</span> shell<span style="color: black;">&#40;</span><span style="color: #008000;">iter</span>, <span style="color: #dc143c;">cmd</span>=<span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    pipe = Popen<span style="color: black;">&#40;</span><span style="color: #dc143c;">cmd</span>, shell=<span style="color: #008000;">True</span>, stdin = PIPE, stdout = PIPE<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> pipe.<span style="color: black;">communicate</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #008000;">iter</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">splitlines</span><span style="color: black;">&#40;</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> shell:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">cmd</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: #dc143c;">cmd</span> = <span style="color: #dc143c;">cmd</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__ror__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #008000;">iter</span><span style="color: black;">&#41;</span>:
        pipe = Popen<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: #dc143c;">cmd</span>, shell=<span style="color: #008000;">True</span>, stdin = PIPE, stdout = PIPE<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> pipe.<span style="color: black;">communicate</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #008000;">iter</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">splitlines</span><span style="color: black;">&#40;</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span></pre></div></div>

<p>有了这个管道，就可以把求和的任务直接用 awk 来完成了。</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">sumtmp = lines | shell<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;awk '{ total += $NF } END { print total }'&quot;</span><span style="color: black;">&#41;</span> | aslist
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>sumtmp<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>当然，如果不想依赖外部程序，可以写一个提取字符串第 n 列/最后一列的函数，作为 tr 的参数放入管道（这个函数的名字不太好，其实就是 map，代码见<a href='http://chenyufei.info/blog/wp-content/uploads/2009/10/shelike.py'>shelike.py</a>），最后转成整数以后再用 sum 求和即可。</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: black;">&#40;</span>lines | tr<span style="color: black;">&#40;</span>last_column<span style="color: black;">&#41;</span> | tr<span style="color: black;">&#40;</span><span style="color: #008000;">int</span><span style="color: black;">&#41;</span> | <span style="color: #008000;">sum</span><span style="color: black;">&#41;</span></pre></div></div>

<p>我很喜欢看这样的代码，有点函数式的味道，而且可读性也很好 :)</p>
<p>有兴趣的话 <a href="http://pypi.python.org/pypi/decorator">decorator module</a> 和 <a href="http://wiki.python.org/moin/PythonDecoratorLibrary">PythonDecoratorLibrary</a> 提供了更多使用 decorator 的例子，推荐。</p>
]]></content:encoded>
			<wfw:commentRss>http://chenyufei.info/blog/2009-10-03/shell-like-data-processing-in-python-using-decorators/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Python 的 iterator protocol 和 generator</title>
		<link>http://chenyufei.info/blog/2009-04-20/python-iterator-protocol-and-generator/</link>
		<comments>http://chenyufei.info/blog/2009-04-20/python-iterator-protocol-and-generator/#comments</comments>
		<pubDate>Mon, 20 Apr 2009 02:48:35 +0000</pubDate>
		<dc:creator>chenyufei</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[generator]]></category>
		<category><![CDATA[lazy evaluation]]></category>

		<guid isPermaLink="false">http://chenyufei.info/blog/?p=216</guid>
		<description><![CDATA[前一篇文章最后的代码效率很差。由于使用 list 保存临时的计算结果，所有文件内容会同时读入内存，其构建的管道类似下图所示： list 中的元素是先通过一个过滤器，存起来，再通过下一个过滤器。这样做的坏处是 浪费内存 浪费时间，来回的在临时 list 中进行存取需要时间，另外临时 list 的内存分配，垃圾收集都会增加时间开销 我们希望的管道其实如下： list 中的每个元素应该一次性通过所有的 filter，只在最后存在一个 list 中。更理想的情况下，一开始的 list 也不应该出现。 对于像 Haskell 这样默认使用 lazy evaluation 的语言来说，前面的函数连续调用默认行为就是如此。只有当管道末端需要一个元素时才会从管道头读取一个元素，经过所有过滤器处理以后得到结果，如果没有读取第二个元素，则管道头的其他元素根本不会被处理。 要在程序中使用管道的风格又必须要避免临时数据的产生，然而 python 中没有直接对 lazy evaluation 提供支持，好在 python 有 iterator protocol 和 generator。 首先介绍 python 的 iterator protocol，了解它才知道 for 语句进行遍历时究竟做了些什么。iterator protocol 使得我们可以对不同的容器（其实是任何支持遍历操作的对象，不一定是用来存放数据的容器）使用相同的方式（for 语句）进行遍历。容器可以是 list, dictionary 或者是其他用户定义的数据结构，它只需要实现 __iter__()方法，返回一个 iterator object 即可。真正关心如何遍历的是 iterator [...]]]></description>
			<content:encoded><![CDATA[<p>前一篇文章最后的代码效率很差。由于使用 list 保存临时的计算结果，所有文件内容会同时读入内存，其构建的管道类似下图所示：</p>
<p><img src="http://chenyufei.info/blog/wp-content/uploads/2009/04/list-pipe.gif" alt="list-pipe" title="list-pipe" width="667" height="59" class="aligncenter size-full wp-image-217" /></p>
<p>list 中的元素是先通过一个过滤器，存起来，再通过下一个过滤器。这样做的坏处是</p>
<ol>
<li>浪费内存</li>
<li>浪费时间，来回的在临时 list 中进行存取需要时间，另外临时 list 的内存分配，垃圾收集都会增加时间开销</li>
</ol>
<p>我们希望的管道其实如下：</p>
<p><img src="http://chenyufei.info/blog/wp-content/uploads/2009/04/generator-pipe.gif" alt="generator-pipe" title="generator-pipe" width="496" height="59" class="aligncenter size-full wp-image-222" /></p>
<p>list 中的每个元素应该一次性通过所有的 filter，只在最后存在一个 list 中。更理想的情况下，一开始的 list 也不应该出现。</p>
<p>对于像 Haskell 这样默认使用 lazy evaluation 的语言来说，前面的函数连续调用默认行为就是如此。只有当管道末端需要一个元素时才会从管道头读取一个元素，经过所有过滤器处理以后得到结果，如果没有读取第二个元素，则管道头的其他元素根本不会被处理。</p>
<p>要在程序中使用管道的风格又必须要避免临时数据的产生，然而 python 中没有直接对 lazy evaluation 提供支持，好在 python 有 iterator protocol 和 generator。</p>
<p>首先介绍 python 的 <em><a href="http://docs.python.org/library/stdtypes.html#iterator-types">iterator protocol</a></em>，了解它才知道 for 语句进行遍历时究竟做了些什么。iterator protocol 使得我们可以对不同的容器（其实是任何支持遍历操作的对象，不一定是用来存放数据的容器）使用相同的方式（for 语句）进行遍历。容器可以是 list, dictionary 或者是其他用户定义的数据结构，它只需要实现 <tt class="docutils literal"><span class="pre">__iter__()</span></tt>方法，返回一个 iterator object 即可。真正关心如何遍历的是 <strong>iterator object，它的两个方法构成了 iterator protocol</strong>。</p>
<ol>
<li><tt>__iter__()</tt> 返回自身</li>
<li><tt>next()</tt> 返回容器中的下一个对象，没有更多对象时应 raise<br />
StopIteration，一旦抛出此异常，后续的调用一定也必须抛出此异常。</li>
</ol>
<p>偷懒起见，直接拿 Beazley 的幻灯片里的例子来说明：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"> <span style="color: #ff7700;font-weight:bold;">class</span> countdown<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;container&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, start<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">count</span> = start
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> countdown_iterator<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">count</span><span style="color: black;">&#41;</span>
&nbsp;
 <span style="color: #ff7700;font-weight:bold;">class</span> countdown_iterator<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;iterator object&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, start<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">count</span> = start
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> next<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">count</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">0</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">StopIteration</span>
        r = <span style="color: #008000;">self</span>.<span style="color: black;">count</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">count</span> -= <span style="color: #ff4500;">1</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> r</pre></div></div>

<p>for 语句首先对要遍历的对象调用 <tt class="docutils literal"><span class="pre">__iter__()</span></tt> 方法得到 iterator object，然后对 iterator object 不停调用 <tt class="docutils literal"><span class="pre">next()</span></tt> 方法直到遇到 &#8220;StopIteration&#8221; 异常为止。由此， 下面代码中的 for 语句和 while 循环等价：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"> <span style="color: #dc143c;">cd</span> = countdown<span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
&nbsp;
 <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">cd</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> i
&nbsp;
 _iter = <span style="color: #dc143c;">cd</span>.<span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">cd</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Get iterator object</span>
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff4500;">1</span>:
<span style="color: #ff7700;font-weight:bold;">try</span>:
    x = _iter.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Get next item</span>
    <span style="color: #ff7700;font-weight:bold;">print</span> x
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">StopIteration</span>: <span style="color: #808080; font-style: italic;"># No more items</span>
    <span style="color: #ff7700;font-weight:bold;">break</span></pre></div></div>

<p>由于 iterator object 的 <tt class="docutils literal"><span class="pre">__iter__()</span></tt> 返回自身，因此 iterator object 也可以用在 for 语句中。<strong>实际上可以把 for 语句看成是一种语法糖，但它是一种重要的语法糖，因为它大大简化了程序的编写</strong>，看看上面例子比较下就知道了。</p>
<p>为了使得容器支持遍历操作而要另外定义一个 iterator 类，这跟 C++ 的 STL 有些类似。使用 <em><a href="http://docs.python.org/library/stdtypes.html#iterator-types">generator object</a></em> 可以不需要另外定义 iterator 类从而更方便的实现 iteration protocol。具体做法如下：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">&nbsp;
 <span style="color: #ff7700;font-weight:bold;">class</span> countdown<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;container&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, start<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">count</span> = start
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        it = <span style="color: #008000;">self</span>.<span style="color: black;">count</span>
        <span style="color: #ff7700;font-weight:bold;">while</span> it <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span>:
            <span style="color: #ff7700;font-weight:bold;">yield</span> it
            it -= <span style="color: #ff4500;">1</span></pre></div></div>

<p>一旦在函数定义中使用 yield，这个函数就成为 <em>generator function</em> 而不是普通的函数。 generator function 被调用时会返回 <em>generator iterator</em>，简称 <em>generator</em>。调用 generator 的 next() 方法时，generator function 的函数体会执行，当遇到 yield 时，generator 的状态会冻结，而当前值被返回。</p>
<h4>lazy evaluation, generator 的其他用处</h4>
<p>利用 generator 可以模拟出 lazy evaluation 来。lazy evaluation 我觉得最有用的地方在于，</p>
<ol>
<li>使用管道风格的代码处理数据时，避免产生大量临时的结果，提高性能</li>
<li>处理无限长度的数据</li>
<li>避免不必要的求值</li>
</ol>
<p>但 generator 不光可以用来处理数据，Beazley 的幻灯片里提到 networking, threads, co-routines 等都可以用 generator 来处理。</p>
]]></content:encoded>
			<wfw:commentRss>http://chenyufei.info/blog/2009-04-20/python-iterator-protocol-and-generator/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>编写 Unix 管道风格的 Python 代码</title>
		<link>http://chenyufei.info/blog/2009-01-28/writing-unix-pipe-style-python-code/</link>
		<comments>http://chenyufei.info/blog/2009-01-28/writing-unix-pipe-style-python-code/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 14:15:07 +0000</pubDate>
		<dc:creator>chenyufei</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[pipe]]></category>

		<guid isPermaLink="false">http://chenyufei.info/blog/?p=201</guid>
		<description><![CDATA[先推荐一份幻灯片，David Beazley (&#34;Python essiential reference&#34;, PLY 的作者) 在 PyCon&#8217;2008 上报告的幻灯片，强烈推荐！！这篇文章的很多内容都来自或者受这份幻灯片的启发而来。 在上一篇文章里介绍了 Unix 管道的好处，那可不可以在写程序时也使用这样的思想呢？当然可以。看过 SICP 就知道，其实函数式编程中的 map, filter 都可以看作是管道思想的应用。但其实管道的思想不仅可以在函数式语言中使用，只要语言支持定义函数，有能够存放一组数据的数据结构，就可以使用管道的思想。 一个日志处理任务 这里直接以前面推荐的幻灯片里的例子来说明，应用场景如下： 某个目录及子目录下有一些 web 服务器的日志文件，日志文件名以 access-log 开头 日志格式如下 81.107.39.38 - ... "GET /ply/ply.html HTTP/1.1" 200 97238 81.107.39.38 - ... "GET /ply HTTP/1.1" 304 - 其中最后一列数字为发送的字节数，若为 &#8216;-&#8217; 则表示没有发送数据 目标是算出总共发送了多少字节的数据，实际上也就是要把日志记录的没一行的最后一列数值加起来 我不直接展示如何用 Unix 管道的风格来处理这个问题，而是先给出一些“不那么好”的代码，指出它们的问题，最后再展示管道风格的代码，并介绍如何使用 generator 来避免效率上的问题。想直接看管道风格的，点这里。 问题并不复杂，几个 for 循环就能搞定： sum [...]]]></description>
			<content:encoded><![CDATA[<p>先推荐一份幻灯片，David Beazley (&quot;Python essiential reference&quot;, PLY 的作者) 在 PyCon&#8217;2008 上报告的<a class="reference external" href="http://www.dabeaz.com/generators/Generators.pdf">幻灯片</a>，强烈推荐！！这篇文章的很多内容都来自或者受这份幻灯片的启发而来。</p>
<p>在上一篇文章里介绍了 Unix 管道的好处，那可不可以在写程序时也使用这样的思想呢？当然可以。看过 SICP 就知道，其实函数式编程中的 map, filter 都可以看作是管道思想的应用。但其实管道的思想不仅可以在函数式语言中使用，只要语言支持定义函数，有能够存放一组数据的数据结构，就可以使用管道的思想。</p>
<h3>一个日志处理任务</h3>
<p>这里直接以前面推荐的幻灯片里的例子来说明，应用场景如下：</p>
<ul>
<li>某个目录及子目录下有一些 web 服务器的日志文件，日志文件名以 access-log 开头
</li>
<li>
日志格式如下</p>
<pre class="literal-block">81.107.39.38 - ... "GET /ply/ply.html HTTP/1.1" 200 97238
81.107.39.38 - ... "GET /ply HTTP/1.1" 304 -
</pre>
<p>其中最后一列数字为发送的字节数，若为 &#8216;-&#8217; 则表示没有发送数据
</li>
<li>目标是算出总共发送了多少字节的数据，实际上也就是要把日志记录的没一行的最后一列数值加起来
</li>
</ul>
<p>我不直接展示如何用 Unix 管道的风格来处理这个问题，而是先给出一些“不那么好”的代码，指出它们的问题，最后再展示管道风格的代码，并介绍如何使用 generator 来避免效率上的问题。想直接看管道风格的，点<a class="reference internal" href="#pipe-style">这里</a>。</p>
<p>问题并不复杂，几个 for 循环就能搞定：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">sum</span> = <span style="color: #ff4500;">0</span>
<span style="color: #ff7700;font-weight:bold;">for</span> path, dirlist, filelist <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">walk</span><span style="color: black;">&#40;</span>top<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> name <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">fnmatch</span>.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span>filelist, <span style="color: #483d8b;">&quot;access-log*&quot;</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># 对子目录中的每个日志文件进行处理</span>
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>name<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
            <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> f:
                <span style="color: #ff7700;font-weight:bold;">if</span> line<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> == <span style="color: #483d8b;">'-'</span>:
                    <span style="color: #ff7700;font-weight:bold;">continue</span>
                <span style="color: #ff7700;font-weight:bold;">else</span>:
                    <span style="color: #008000;">sum</span> += <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>line.<span style="color: black;">rsplit</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>利用 <tt class="docutils literal"><span class="pre">os.walk</span></tt> 这个问题解决起来很方便，由此也可以看出 python 的 for 语句做遍历是多么的方便，不需要额外控制循环次数的变量，省去了设置初始值、更新、判断循环结束条件等工作，相比 C/C++/Java 这样的语言真是太方便了。看起来一切都很美好。</p>
<p>然而，设想以后有了新的统计任务，比如：</p>
<ol>
<li>统计某个特定页面的访问次数</li>
<li>处理另外的一些日志文件，日志文件名字以 error-log 开头</li>
</ol>
<p>完成这些任务直接拿上面的代码过来改改就可以了，文件名的 pattern 改一下，处理每个文件的代码改一下。其实每次任务的处理中，找到特定名字为特定 pattern 的文件的代码是一样的，直接修改之前的代码其实就引入了重复。</p>
<p>如果重复的代码量很大，我们很自然的会注意到。然而 python 的 for 循环实在太方便了，像这里找文件的代码一共就两行，哪怕重写一遍也不会觉得太麻烦。<strong>for 循环的方便使得我们会忽略这样简单代码的重复</strong>。然而，再怎么方便好用，<strong>for 循环无法重用，只有把它放到函数中才能进行重用</strong>。</p>
<p>(先考虑下是你会如何避免这里的代码的重复。下面马上出现的代码并不好，是“误导性”的代码，我会在之后再给出“更好”的代码。)</p>
<p>因此，我们把上面代码中<strong>不变的部分提取成一个通用的函数，可变的部分以参数的形式传入</strong>，得到下面的代码。</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> generic_process<span style="color: black;">&#40;</span>topdir, filepat, processfunc<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> path, dirlist, filelist <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">walk</span><span style="color: black;">&#40;</span>top<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> name <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">fnmatch</span>.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span>filelist, filepat<span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>name<span style="color: black;">&#41;</span> f:
                processfunc<span style="color: black;">&#40;</span>f<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #008000;">sum</span> = <span style="color: #ff4500;">0</span>
<span style="color: #808080; font-style: italic;"># 很遗憾，python 对 closure 中的变量不能进行赋值操作，</span>
<span style="color: #808080; font-style: italic;"># 因此这里只能使用全局变量</span>
<span style="color: #ff7700;font-weight:bold;">def</span> add_count<span style="color: black;">&#40;</span>f<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">global</span> <span style="color: #008000;">sum</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> f:
        <span style="color: #ff7700;font-weight:bold;">if</span> line<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> == <span style="color: #483d8b;">'-'</span>:
            <span style="color: #ff7700;font-weight:bold;">continue</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #008000;">sum</span> += <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>line.<span style="color: black;">rsplit</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
generic_process<span style="color: black;">&#40;</span><span style="color: #483d8b;">'logdir'</span>, <span style="color: #483d8b;">'access-log*'</span>, add_count<span style="color: black;">&#41;</span></pre></div></div>

<p>看起来不变和可变的部分分开了，然而 generic_process 的设计并不好。它除了寻找文件以外还调用了日志文件处理函数，因此在其他任务中很可能就无法使用。另外 add_count 的参数必须是 file like object，因此测试时不能简单的直接使用字符串。</p>
<h3><a id="pipe-style">管道风格的程序</a></h3>
<p>下面考虑用 Unix 的工具和管道我们会如何完成这个任务：</p>
<pre>
find logdir -name "access-log*" | \
xargs cat | \
grep '[^-]$' | \
awk '{ total += $NF } END { print total }'
</pre>
<p>find 根据文件名 pattern 找到文件，cat 把所有文件内容合并输出到 stdout，grep 从 stdin 读入，过滤掉行末为 &#8216;-&#8217; 的行，awk 提取每行最后一列，将数值相加，最后打印出结果。（省掉 cat 是可以的，但这样一来 grep 就需要直接读文件而不是只从标准输入读。）</p>
<p>我们可以在 python 代码中模拟这些工具，Unix 的工具通过文本来传递结果，在 python 中可以使用 list。</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> find<span style="color: black;">&#40;</span>topdir, filepat, processfunc<span style="color: black;">&#41;</span>:
    files = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> path, dirlist, filelist <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">walk</span><span style="color: black;">&#40;</span>top<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> name <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">fnmatch</span>.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span>filelist, filepat<span style="color: black;">&#41;</span>:
            files.<span style="color: black;">append</span><span style="color: black;">&#40;</span>name<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> files
&nbsp;
 <span style="color: #ff7700;font-weight:bold;">def</span> cat<span style="color: black;">&#40;</span>files<span style="color: black;">&#41;</span>:
    lines = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> <span style="color: #008000;">file</span> <span style="color: #ff7700;font-weight:bold;">in</span> files:
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
            <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> f:
                lines.<span style="color: black;">append</span><span style="color: black;">&#40;</span>line<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> lines
&nbsp;
 <span style="color: #ff7700;font-weight:bold;">def</span> grep<span style="color: black;">&#40;</span>pattern, lines<span style="color: black;">&#41;</span>:
    result = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span>
    pat = <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>pattern<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> lines:
        <span style="color: #ff7700;font-weight:bold;">if</span> pat.<span style="color: black;">search</span><span style="color: black;">&#40;</span>line<span style="color: black;">&#41;</span>:
            result.<span style="color: black;">append</span><span style="color: black;">&#40;</span>line<span style="color: black;">&#41;</span>
    resurn result
&nbsp;
lines = grep<span style="color: black;">&#40;</span><span style="color: #483d8b;">'[^-]$'</span>, cat<span style="color: black;">&#40;</span>find<span style="color: black;">&#40;</span><span style="color: #483d8b;">'logdir'</span>, <span style="color: #483d8b;">'access-log*'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
col = <span style="color: black;">&#40;</span>line.<span style="color: black;">rsplit</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> lines<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>c<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> c <span style="color: #ff7700;font-weight:bold;">in</span> col<span style="color: black;">&#41;</span></pre></div></div>

<p>有了 <tt class="docutils literal"><span class="pre">find</span></tt>, <tt class="docutils literal"><span class="pre">cat</span></tt>, <tt class="docutils literal"><span class="pre">grep</span></tt> 这三个函数，只需要连续调用就可以像 Unix 的管道一样将这些函数组合起来。数据在管道中的变化如下图（简洁起见，过滤器直接标在箭头上 ）：</p>
<p><a href="http://chenyufei.info/blog/wp-content/uploads/2009/01/data-pipe.gif"><img src="http://chenyufei.info/blog/wp-content/uploads/2009/01/data-pipe-600x31.gif" alt="data-pipe" title="data-pipe" width="600" height="31" class="aligncenter size-medium wp-image-205" /></a></p>
<p>看起来现在的代码行数比最初直接用 for 循环的代码要多，但现在的代码就像 Unix 的那些小工具一样，每一个都更加可能被用到。我们可以把更多常用的 Unix 工具用 Python 来模拟，从而在 Python 代码中以 Unix 管道的风格来编写代码。</p>
<p>不过上面的代码性能很差，多个临时的 list 被创建。解决的办法是用 generator，因为篇幅比较长，具体做法放到下一篇文章中。</p>
]]></content:encoded>
			<wfw:commentRss>http://chenyufei.info/blog/2009-01-28/writing-unix-pipe-style-python-code/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>对 Python 和 Ruby 的一点看法</title>
		<link>http://chenyufei.info/blog/2008-02-27/%e5%af%b9-python-%e5%92%8c-ruby-%e7%9a%84%e4%b8%80%e7%82%b9%e7%9c%8b%e6%b3%95/</link>
		<comments>http://chenyufei.info/blog/2008-02-27/%e5%af%b9-python-%e5%92%8c-ruby-%e7%9a%84%e4%b8%80%e7%82%b9%e7%9c%8b%e6%b3%95/#comments</comments>
		<pubDate>Wed, 27 Feb 2008 08:27:40 +0000</pubDate>
		<dc:creator>chenyufei</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://chenyufei.info/blog/2008-02-27/%e5%af%b9-python-%e5%92%8c-ruby-%e7%9a%84%e4%b8%80%e7%82%b9%e7%9c%8b%e6%b3%95/</guid>
		<description><![CDATA[还是从我在 Ruby 和 Python 上的经历说起吧。 大二暑假的时候学了 Ruby，但是到现在为止只用 Ruby 做过文本处理，还有一次做 Linux 网络编程作业的时候用 Ruby 实现了一个服务器的原型，还稍微尝试过一下 RoR，不过因为我对 Web 开发没什么兴趣，所以是浅尝辄止而已。平时自己机器上能够用到的 Ruby 程序也只有 deplate 而已。 今年寒假的时候开始考虑毕设的事情，考虑实现语言的时候也曾考虑过 Ruby。但是我要用的 dazuko 的 Ruby 绑定可能存在内存泄漏的问题，引起内存泄漏的原因应该在 Ruby 的实现上。考虑到 Python 的实现更成熟，对于要求稳定的系统程序来说可能更为合适而开始考虑 Python。于是开始看 Dive Into Python，被这本书吸引而继续学下去。我之前的介绍过这本书，很欣赏它。 最经开始更多的实际使用 Python 了，很自然的会想把它跟 Ruby 做些比较。因为我对 Ruby 和 Python 的语法和特性的了解只是一般而已，所以对语法的比较我说不出太多的东西。在我看来语法上来看它们相似的地方多于不同的地方，在它们中进行切换是很方便的。我很喜欢 Ruby 的 block 语法，但 Python 有 list comprehension 和 generator，很多 block 的用法都可以用它们来完成，所以我并不会在使用 [...]]]></description>
			<content:encoded><![CDATA[<p>还是从我在 Ruby 和 Python 上的经历说起吧。</p>
<p>大二暑假的时候学了 Ruby，但是到现在为止只用 Ruby 做过文本处理，还有一次做 Linux 网络编程作业的时候用 Ruby 实现了一个服务器的原型，还稍微尝试过一下 RoR，不过因为我对 Web 开发没什么兴趣，所以是浅尝辄止而已。平时自己机器上能够用到的 Ruby 程序也只有 deplate 而已。</p>
<p>今年寒假的时候开始考虑毕设的事情，考虑实现语言的时候也曾考虑过 Ruby。但是我要用的 dazuko 的 Ruby 绑定可能存在内存泄漏的问题，引起内存泄漏的原因应该在 Ruby 的实现上。考虑到 Python 的实现更成熟，对于要求稳定的系统程序来说可能更为合适而开始考虑 Python。于是开始看 Dive Into Python，被这本书吸引而继续学下去。我之前的介绍过这本书，很欣赏它。</p>
<p>最经开始更多的实际使用 Python 了，很自然的会想把它跟 Ruby 做些比较。因为我对 Ruby 和 Python 的语法和特性的了解只是一般而已，所以对语法的比较我说不出太多的东西。在我看来语法上来看它们相似的地方多于不同的地方，在它们中进行切换是很方便的。我很喜欢 Ruby 的 block 语法，但 Python 有 list comprehension 和 generator，很多 block 的用法都可以用它们来完成，所以我并不会在使用 Python 的时候非常的渴望 Python 也有 block 语法（仅有的时候是文件打开完成任务以后自动关闭这种地方，Python 里还没有很好的解决）。就语言本身来说我更喜欢 Ruby，个人觉得用 Ruby 写程序更为舒服，而且通常完成同样任务的 Ruby 程序也比 Python 更短。但是 Python 的优秀的社区使我选择 Python 而不是 Ruby。</p>
<p>在 Python 和 Ruby 中我只想选一个，用它来完成一些 quick and dirty 的任务，我希望一切越简单越好，最好就是别人已经帮我完成了，直接拿来用就可以。随着越来越多的使用 Python，看到 Python 社区所完成的工作，我觉得 Python 才是这一任务更好的选择。Guido 在一次访谈中说：</p>
<blockquote><p>
对于杀手锏应用（killer application），我个人并不十分迷信。如果你太看重杀手锏应用的话，实际上你可能会把焦点放错地方，或者你可能太专注于某一个方面。
</p></blockquote>
<p>以前对这话觉得不屑，觉得是酸葡萄心里而已，现在越来越觉得 Guido 是对的。Python 现在已经进入很多领域，在科研领域，已经出现像 NumPy, SciPy 这样优秀的软件。我也看到生物信息学研究者写的用 Python 编程来处理生物信息学问题的文章。在图形处理方面也有了优秀的软件，如 PIL。而 NASA, Google 等组织也在大量使用 Python。而在 Web 开发框架上，Python 有不止一个，另外还有像 twisted 这样高层的互联网应用程序开发框架。实现上 CPython 比 CRuby 也要成熟，两者都有许多实现，以前很看好 Rubinius，但现在我知道了 PyPy，如果 Rubinius 能够使得 Ruby 在性能上有很大的提升，那 PyPy 肯定也能，事实上 PyPy 现在应该比 Rubinius 更成熟。而我现在自己常用的 VCS 工具 Mercurial 就是用 Python 实现的。</p>
<p>从使用的广泛程度来说 Python 目前远超过 Ruby，记得 2008 年 1 月的程序设计语言使用广泛度统计中 Python 排名首次超过 Perl，而 Ruby 的排名反而下降了。不知道是因为 Python 有大量优秀的软件导致大量的使用，还是因为大量的使用导致有如此多优秀的软件，但现在的社区已经使得这两个方面可以互相促进，形成一个良性循环了。如果 Python 社区的注意力都集中在 Web 开发上，或许它可以出一个类似 RoR 的 killer application，但它就不会产生如此之多不同领域的优秀软件，也会使得 Python 的使用达不到如此广泛的程度。在我看来这是得不偿失的。</p>
<p>即使我不喜欢 Python 中一些 Guido 强加给我的限制，但是只要它能够让我把那些 quick and dirty work 以最快的速度最小的精力做完，我就不在乎，而那些限制在构建大型软件上可能反而能够带来好处。如果哪天 Ruby 能够像 Python 社区这样成熟，提供更多的优秀的软件，那我在解决个人的 quick and dirty work 时就会选择使用 Ruby。但是现在，我选 Python。</p>
<p>我仍然会花时间去学 Common Lisp，但 CL 现在不擅长跟 OS 和其他基础设施交互，所以我不会用它来完成日常的工作。我目前只打算想把它作为一个研究性质的语言，满足我对程序设计语言本身的兴趣。一方面，SLIME 提供的交互式的开发环境更加合适探索性的任务（ipython 虽然不错，但是跟 SLIME 和 CL 提供的环境比起来还是差了点）；另一方面，正因为有许多工作在 Common Lisp 中还没有完成，我可以尝试自己来研究解决，在其中得到锻炼。我也希望在真正领悟 Common Lisp 的时候我能够成为一个更好的程序员。</p>
<p>语言的选择并不是至关重要的，但是我希望能够使用一个使得编程更加有趣的语言。以前在语言上花了太多的时间，现在决定把语言逐渐固定下来，把注意力放到更加重要的问题上，为我以后的研究做准备。</p>
<p>PS:<br />
现在在浦口每天的时间都可以自己支配，太爽了 :-)</p>
<p>不过想看的书太多了宏观经济学（微观已经看完了），算法导论，线性代数，Ansi Common Lisp，还要每天在毕设上投入一点时间（现在还在准备阶段），再加上要利用本科最后这个学期好好练小提琴，有点安排不过来了。为了集中精力，有些书看了一点又要停下来了。</p>
<p>最近回到浦口真开心，爱死浦口的食堂了 :-) 我现在的日子跟查师兄去年的比真是太舒服了，这两天有点堕落，明天起要鞭策自己努力了。</p>
]]></content:encoded>
			<wfw:commentRss>http://chenyufei.info/blog/2008-02-27/%e5%af%b9-python-%e5%92%8c-ruby-%e7%9a%84%e4%b8%80%e7%82%b9%e7%9c%8b%e6%b3%95/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Python 中 for 循环语句的 else 从句</title>
		<link>http://chenyufei.info/blog/2008-01-29/python-for-loop/</link>
		<comments>http://chenyufei.info/blog/2008-01-29/python-for-loop/#comments</comments>
		<pubDate>Tue, 29 Jan 2008 09:32:47 +0000</pubDate>
		<dc:creator>chenyufei</dc:creator>
				<category><![CDATA[Arch]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://chenyufei.info/blog/2008/01/29/python-%e4%b8%ad-for-%e5%be%aa%e7%8e%af%e7%9a%84%e4%b8%80%e7%82%b9%e5%b0%8f%e9%97%ae%e9%a2%98/</guid>
		<description><![CDATA[昨天用 python 写 insertion sort 练练手，在用 for 循环的时候遇到了一点小问题。 Dive Into Python 这本书的确不适合初学程序设计的人，我看完第 6 章都没有看到 python 中的 while 语句，所以最初我用了两个 for 循环来实现，xrange 也是我看别人的程序的加上查文档才知道怎么用的。对有经验的人来说这样也没什么不好，python 的语言和类库参考都不错，直接查也很方便。 最初的实现出错了，代码如下： def insertion_sort&#40;list&#41;: for i in xrange&#40;1, len&#40;list&#41;&#41;: key = list&#91;i&#93; for j in xrange&#40;i - 1, -1, -1&#41;: if key &#60; list&#91;j&#93;: list&#91;j + 1&#93; = list&#91;j&#93; else: break list&#91;j + 1&#93; [...]]]></description>
			<content:encoded><![CDATA[<p>昨天用 python 写 insertion sort 练练手，在用 for 循环的时候遇到了一点小问题。</p>
<p>Dive Into Python 这本书的确不适合初学程序设计的人，我看完第 6 章都没有看到 python 中的 while 语句，所以最初我用了两个 for 循环来实现，xrange 也是我看别人的程序的加上查文档才知道怎么用的。对有经验的人来说这样也没什么不好，python 的语言和类库参考都不错，直接查也很方便。</p>
<p>最初的实现出错了，代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> insertion_sort<span style="color: black;">&#40;</span><span style="color: #008000;">list</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">list</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
        key = <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>i - <span style="color: #ff4500;">1</span>, -<span style="color: #ff4500;">1</span>, -<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> key <span style="color: #66cc66;">&lt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>:
                <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>j + <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> = <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #ff7700;font-weight:bold;">break</span>
        <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>j + <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> = key
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">list</span></pre></div></div>

<p>随便试了几个就错了，很奇怪为什么会出错。后来才意识到使用 for 遍历的是一个列表，如果没有 break，遍历完之后 j 是列表中的最后一个元素 0，而不是 -1。如果因为列表遍历完成而非 break 中断循环，则最后应该执行 list[0] = key，但实际执行的是 list[1] = key。</p>
<p>这样就有个问题，<strong>如何判断 for 循环是正常遍历结束还是被 break 中断的？</strong>在 C 中写 <code>for (j = i - 1; j > -1; j--)</code> 最后循环结束的时候 j 为 -1，所以检查 j 的值就可以了。但在 python 里面，j 最小只可能到 0，循环结束时 j 为 0 可能是因为 key >= list[j] 而 break，也可能因为 0 是最后一个元素而终止循环，所以通过检查 j 的值是没法做到的。（因为 python 中 for 的作用是遍历列表等容器，所以不能让 for 与 C 中有相同的行为。）</p>
<p>查了下语言参考，发现 for 语句可以跟一个 else 块，觉得有点奇怪，还没有见过哪个语言有这样的语法的。文档说 else 后面的块在循环条件为假时执行一次，但如果 for 后面的块中因为 break 导致循环结束则这个块不执行。一开始觉得这个 else 没什么用，除非死循环，否则条件总是会变为假，那直接把代码放在 for 外面不就可以了。后来想到这个特性正好可以用来判断循环终止的原因，用个条件变量即可，在 else 代码中改变这个条件变量，然后在后面的代码中检查条件变量的值即可。</p>
<p>最后的代码如下：</p>
</pre>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> insertion_sort<span style="color: black;">&#40;</span><span style="color: #008000;">list</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">list</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
        key = <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span>
        outbound = <span style="color: #008000;">False</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>i - <span style="color: #ff4500;">1</span>, -<span style="color: #ff4500;">1</span>, -<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> key <span style="color: #66cc66;">&lt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>:
                <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>j + <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> = <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #ff7700;font-weight:bold;">break</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #008000;">list</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> = key
            outbound = <span style="color: #008000;">True</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> outbound:
            <span style="color: #008000;">list</span><span style="color: black;">&#91;</span>j + <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> = key
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">list</span></pre></div></div>

<p>当然用一个 while 循环就可以不用这么麻烦了，不过我就是想知道用 for 该怎么解决这个问题。</p>
<p>PS:<br />
wordpress 有没有什么贴代码用的插件？</pre>
]]></content:encoded>
			<wfw:commentRss>http://chenyufei.info/blog/2008-01-29/python-for-loop/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Dive Into Python</title>
		<link>http://chenyufei.info/blog/2008-01-26/dive-into-python/</link>
		<comments>http://chenyufei.info/blog/2008-01-26/dive-into-python/#comments</comments>
		<pubDate>Sat, 26 Jan 2008 04:24:15 +0000</pubDate>
		<dc:creator>chenyufei</dc:creator>
				<category><![CDATA[book]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://chenyufei.info/blog/2008/01/26/dive-into-python/</guid>
		<description><![CDATA[我觉得很不错的一本讲 Python 的书。Dive Into Python，适合有经验的程序员，GNU Free Documentation License 下发布。 每一章先上一段代码，通过这些代码解释语言的特性，没有什么废话，很快就涉及语言里比较高级的特性（第 4 章就开始讲 introspection 了。Dave Thomas 的 Programming Ruby 这本书就感觉太罗嗦，因为没有耐心看最后几章，Ruby 的 introspection 特性我都不怎么了解。） 去年就学了 Ruby，不过没有用它做过实际的项目，只写过一些小的文本处理的脚本而已。毕设我不打算用 C，开发效率太低了，Java 已经腻了，而 Ruby 糟糕的实现始终有点让人担心，对 Common Lisp 还是没有把握。看到今年的语言流行度，加上毕设可能要用的一个重要的类库只有 Python 的绑定，还是决定学下 Python 了。初步印象还不错，不过还是很喜欢 Ruby 里面的 block。]]></description>
			<content:encoded><![CDATA[<p>我觉得很不错的一本讲 Python 的书。<a href="http://www.diveintopython.org/">Dive Into Python</a>，适合有经验的程序员，GNU Free Documentation License 下发布。</p>
<p>每一章先上一段代码，通过这些代码解释语言的特性，没有什么废话，很快就涉及语言里比较高级的特性（第 4 章就开始讲 introspection 了。Dave Thomas 的 Programming Ruby 这本书就感觉太罗嗦，因为没有耐心看最后几章，Ruby 的 introspection 特性我都不怎么了解。）</p>
<p>去年就学了 Ruby，不过没有用它做过实际的项目，只写过一些小的文本处理的脚本而已。毕设我不打算用 C，开发效率太低了，Java 已经腻了，而 Ruby 糟糕的实现始终有点让人担心，对 Common Lisp 还是没有把握。看到今年的语言流行度，加上毕设可能要用的一个重要的类库只有 Python 的绑定，还是决定学下 Python 了。初步印象还不错，不过还是很喜欢 Ruby 里面的 block。</p>
]]></content:encoded>
			<wfw:commentRss>http://chenyufei.info/blog/2008-01-26/dive-into-python/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
