<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-33791960</id><updated>2011-07-08T12:59:45.507+08:00</updated><category term='others'/><category term='allegra'/><category term='javascript'/><category term='pocoo'/><category term='REST'/><category term='web'/><category term='paste'/><category term='ajax'/><category term='newforms'/><category term='tutorial'/><category term='continuation'/><category term='sqlalchemy'/><category term='gtk'/><category term='django'/><category term='mochikit'/><category term='PEAK'/><category term='pickle'/><category term='stackless'/><category term='descriptor'/><category term='libevent'/><category term='python3000'/><category term='python'/><category term='cherrypy'/><category term='wsgi'/><category term='ply'/><category term='mako'/><category term='rails'/><category term='functional'/><category term='haskell'/><category term='turbogears'/><category term='orm'/><category term='metaclass'/><category term='设计模式'/><category term='network'/><category term='genshi'/><category term='vim'/><category term='framework'/><category term='IronPython'/><category term='dotnet'/><category term='inkscape'/><category term='pypy'/><category term='compiler'/><title type='text'>白菜</title><subtitle type='html'>请使用firefox浏览！</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>86</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-33791960.post-3012611108675636830</id><published>2010-04-10T15:30:00.003+08:00</published><updated>2010-04-10T16:17:54.930+08:00</updated><title type='text'>博客搬新家</title><content type='html'>鉴于blogger常年在墙外，严重影响了发贴的心情。终于搭建了自己的博客。

http://www.yi-programmer.com/blog/

博客的成功运转跟下面这些光辉的名字是分不开，向创造这些东西的大牛们表示致敬，谢谢git，谢谢make，谢谢python，谢谢docutils，谢谢mako，谢谢pygments，谢谢latex。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-3012611108675636830?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.yi-programmer.com/blog/' title='博客搬新家'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/3012611108675636830/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=3012611108675636830' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3012611108675636830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3012611108675636830'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2010/04/blog-post.html' title='博客搬新家'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-6013772031813819174</id><published>2009-04-23T13:32:00.001+08:00</published><updated>2009-04-23T13:32:33.985+08:00</updated><title type='text'></title><content type='html'>hello&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-6013772031813819174?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/6013772031813819174/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=6013772031813819174' title='5 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6013772031813819174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6013772031813819174'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2009/04/hello.html' title=''/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-3922551842111360395</id><published>2009-04-20T18:23:00.001+08:00</published><updated>2009-04-20T18:24:31.820+08:00</updated><title type='text'>学习Haskell</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;div style="text-align: center;"&gt;&lt;h1&gt;学习Haskell&lt;/h1&gt;&lt;/div&gt;&lt;/div&gt;发现自己学习一门新语言的时候总是去尝试找到一个能完全表达这门语言的最小子集，然后其他的都是语法糖。比如c语言这个子集基本就是汇编语言所提供的那些东西：分支跳转指针等，python的这个子集大概是些对象、类型、属性、duck typing之类的东西。这样可以帮助记忆。haskell的这个子集里都会有些什么呢？lambda、type、typeclass，这样考虑起来 haskell 语言的核心概念还是挺少的，就是有些理论还需要学习，函数式的风格需要转换过来。&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-3922551842111360395?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/3922551842111360395/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=3922551842111360395' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3922551842111360395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3922551842111360395'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2009/04/blog-post.html' title='学习Haskell'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4156376875170557792</id><published>2009-04-20T14:19:00.002+08:00</published><updated>2009-04-20T14:21:26.257+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='functional'/><title type='text'>monad与状态</title><content type='html'>&lt;h1 style="text-align: center;"&gt;monad与状态&lt;/h1&gt;
&lt;div style="text-align: left;"&gt;最近重新捡起haskell来看了看，似乎对monad和程序状态的关系有点小小的明白了。强烈希望明白人指点一下。&lt;/div&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style="text-align: left;"&gt;话说用命令式语言写程序的时候，有明白人就强烈要求不要用全局变量不要用全局变量，其实要取消所有的全局变量也容易，不过就是增加几个参数而已，比如这样的程序：&lt;/div&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style="text-align: left;"&gt;int 全局变量=0;&lt;/div&gt;
&lt;div style="text-align: left;"&gt;void inc(){全局变量+=1;}&lt;/div&gt;
&lt;div style="text-align: left;"&gt;void dec(){全局变量-=1;}&lt;/div&gt;
&lt;div style="text-align: left;"&gt;void main(){inc(); dec();}&lt;/div&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style="text-align: left;"&gt;改成这样就成了：&lt;/div&gt;
&lt;div style="text-align: left;"&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style="text-align: left;"&gt;void inc(int *变量){*变量+=1;}&lt;/div&gt;
&lt;div style="text-align: left;"&gt;void dec(int *变量){*变量-=1;}&lt;/div&gt;
&lt;div style="text-align: left;"&gt;void main(){int 全局变量=0; inc(&amp;amp;全局变量); dec(&amp;amp;全局变量);}&lt;/div&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style="text-align: left;"&gt;其实说起来，搞个全局变量也就是为了让函数少写几个参数而已。参数实在太多了，大不了就搞个 struct stat 把公用的参数给包装成一个。&lt;/div&gt;
&lt;div style="text-align: left;"&gt;函数式编程号称不准修改状态，那大不了就每次改都创建一份新的，然后返回了，这样程序就变成这样了：&lt;/div&gt;
&lt;div style="text-align: left;"&gt;
&lt;div style="text-align: left;"&gt;void inc(状态,...){...; return 结果和新状态;}&lt;/div&gt;
&lt;div style="text-align: left;"&gt;void dec(状态,...){...; return 结果和新状态}&lt;/div&gt;
&lt;div style="text-align: left;"&gt;void main(){&lt;/div&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 初始状态;&lt;/div&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;新状态, 返回值 = inc(初始状态,...);&lt;/div&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;新状态2, 返回值 = dec(新状态,...);&lt;/div&gt;
&lt;div style="text-align: left;"&gt;}&lt;/div&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style="text-align: left;"&gt;这样所有函数都要多加一个状态参数，要多返回一个新状态。麻是麻烦点，不过据说都要玩并行计算了嘛，忍了。&lt;/div&gt;
&lt;div style="text-align: left;"&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style="text-align: left;"&gt;那么可以把状态这个东西本身抽象了一下，我们用python来模拟一下吧，假设原来的程序是这样的：&lt;br&gt;&lt;br&gt;global_stat = []&lt;br&gt;def inc1(stat, input):&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return stat+['inc1'], input+1&lt;br&gt;&lt;br&gt;def inc2(stat, input):&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return stat+['inc2'], input+2&lt;br&gt;&lt;br&gt;a = 1&lt;br&gt;new_stat, a1 = inc1(global_stat, a)&lt;br&gt;new_stat, a2 = inc2(new_stat, a1)&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;为了简化这个问题，我们引入一个 bind 函数来进行抽象：&lt;br&gt;&lt;br&gt;def bind(func1, func2):&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; def lazy_bind(stat, value):&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new_stat, return_value = func1(stat, value)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; func2(new_stat, return_value)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return lazy_bind&lt;br&gt;&lt;br&gt;# 然后就可以这样来调用 inc1,inc2...&lt;br&gt;&lt;br&gt;bind(inc1,&lt;br&gt;bind(inc2,&lt;br&gt;bind(xxx,&lt;br&gt;...&lt;br&gt;))...) (init_stat, defaut_value)&lt;br&gt;&lt;br&gt;就我们这个例子来说，后面这种方式除了让程序更加诡异以外看不出来有什么特别的好处。&lt;br&gt;但是对于 Haskell 来说，很多基本的东西（IO）都是构建与这种类型的抽象之上，并且提供一些语法糖让代码变得更好看，这样一种抽象方式也就成为理解haskell程序很重要的一个东西了。&lt;br&gt;而haskell之所以说能够通过这种抽象方式来隔离纯代码和有副作用的代码（比如说具体的IO操作）就我个人理解就是因为可以把有副作用的代码放到bind里面执行，从而保证 inc1、inc2 这种函数的纯粹性。&lt;br&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4156376875170557792?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4156376875170557792/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4156376875170557792' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4156376875170557792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4156376875170557792'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2009/04/monad_20.html' title='monad与状态'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-3715058342621257522</id><published>2009-01-20T15:20:00.000+08:00</published><updated>2009-01-20T15:21:31.865+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>所谓日久生情</title><content type='html'>不要怀疑，这个日就是你心里想的那个日，而且是被。
意思是说，再郁闷的东西，被郁闷久了，也总能从中发掘出一些稍微好玩一点的东西出来。
&lt;a href="http://huangyilib.googlecode.com/svn/trunk/doc/js_best_practice.html"&gt;http://huangyilib.googlecode.com/svn/trunk/doc/js_best_practice.html&lt;/a&gt;
当然，玩python的兄弟就不要点了，主要是用来忽悠没玩过动态语言的朋友的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-3715058342621257522?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/3715058342621257522/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=3715058342621257522' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3715058342621257522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3715058342621257522'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2009/01/blog-post.html' title='所谓日久生情'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-8498870682467032404</id><published>2008-12-26T17:46:00.001+08:00</published><updated>2008-12-26T17:48:19.884+08:00</updated><title type='text'>无题</title><content type='html'>想起来也很久没有用python，尤其没有用来做web了，没想到还记得很清楚，不容易不容易。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-8498870682467032404?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/8498870682467032404/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=8498870682467032404' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8498870682467032404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8498870682467032404'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2008/12/blog-post.html' title='无题'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-6189352720810301624</id><published>2008-11-12T00:31:00.002+08:00</published><updated>2008-11-12T01:07:43.164+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gtk'/><title type='text'>linux下的半透明窗口</title><content type='html'>为了做一个显示歌词的小玩意，学习了一把x window，我希望歌词窗口能背景透明但文字清晰显示。理论基础就是 composite window manager（比如compiz）支持窗口使用 alpha channel。那么应用程序只要整好rgba的图像交给x服务器即可。
发现使用 gtk＋cairo＋pango 大大简化了工作。

代码：http://code.google.com/p/huangyilib/source/browse/trunk/py_transparent_window.py

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jpcT9HwSFrU/SRm7tda0QrI/AAAAAAAAAak/-3faHlg_t6A/s1600-h/Screenshot-py_transparent_window.py.png"&gt;&lt;img style="cursor: pointer; width: 200px; height: 64px;" src="http://1.bp.blogspot.com/_jpcT9HwSFrU/SRm7tda0QrI/AAAAAAAAAak/-3faHlg_t6A/s200/Screenshot-py_transparent_window.py.png" alt="" id="BLOGGER_PHOTO_ID_5267447628852118194" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-6189352720810301624?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/6189352720810301624/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=6189352720810301624' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6189352720810301624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6189352720810301624'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2008/11/linux.html' title='linux下的半透明窗口'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_jpcT9HwSFrU/SRm7tda0QrI/AAAAAAAAAak/-3faHlg_t6A/s72-c/Screenshot-py_transparent_window.py.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-6290524401097239332</id><published>2008-11-11T23:39:00.002+08:00</published><updated>2008-11-11T23:49:03.291+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='设计模式'/><title type='text'>关于设计模式</title><content type='html'>又看到关于设计模式的文章，突然联想到vim的作者说过一句大概是这样的话：学习vim的方法就是使用它，然后在使用过程中注意发现那些经常重复的行为，然后简化之。
写程序的模式又何尝不是如此呢？只不过程序的事情更复杂罢了，那些重复的模式往往需要灵感来发现，简化的方法也总是不那么明显，甚至需要思维方式的彻底改变。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-6290524401097239332?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/6290524401097239332/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=6290524401097239332' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6290524401097239332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6290524401097239332'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2008/11/blog-post.html' title='关于设计模式'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-782886885965896696</id><published>2008-11-08T17:20:00.003+08:00</published><updated>2008-11-08T18:40:31.127+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='inkscape'/><category scheme='http://www.blogger.com/atom/ns#' term='libevent'/><title type='text'>inkscape还是很好用的</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jpcT9HwSFrU/SRVsRd_pvbI/AAAAAAAAAac/Ran0fgy0chg/s1600-h/libevent_quene.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_jpcT9HwSFrU/SRVsRd_pvbI/AAAAAAAAAac/Ran0fgy0chg/s200/libevent_quene.png" alt="" id="BLOGGER_PHOTO_ID_5266234386644843954" border="0" /&gt;&lt;/a&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jpcT9HwSFrU/SRVsRLLI8LI/AAAAAAAAAaU/zS4Y-IWNE_c/s1600-h/libevent_buffer.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_jpcT9HwSFrU/SRVsRLLI8LI/AAAAAAAAAaU/zS4Y-IWNE_c/s200/libevent_buffer.png" alt="" id="BLOGGER_PHOTO_ID_5266234381592752306" border="0" /&gt;&lt;/a&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jpcT9HwSFrU/SRVsQ_Ha69I/AAAAAAAAAaM/e0wfacESReQ/s1600-h/libevent_basic.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_jpcT9HwSFrU/SRVsQ_Ha69I/AAAAAAAAAaM/e0wfacESReQ/s200/libevent_basic.png" alt="" id="BLOGGER_PHOTO_ID_5266234378355928018" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-782886885965896696?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/782886885965896696/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=782886885965896696' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/782886885965896696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/782886885965896696'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2008/11/inkscape.html' title='inkscape还是很好用的'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_jpcT9HwSFrU/SRVsRd_pvbI/AAAAAAAAAac/Ran0fgy0chg/s72-c/libevent_quene.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2767928833029807606</id><published>2008-10-28T20:54:00.000+08:00</published><updated>2008-10-28T20:55:12.199+08:00</updated><title type='text'>北京好远啊</title><content type='html'>唉&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2767928833029807606?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2767928833029807606/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2767928833029807606' title='5 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2767928833029807606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2767928833029807606'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2008/10/blog-post.html' title='北京好远啊'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-3083700302582596656</id><published>2007-12-18T21:53:00.000+08:00</published><updated>2007-12-18T22:04:35.039+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>工作后</title><content type='html'>转眼来到腾讯有5个月了，博客也就长个5个月的草了。
china-pub 又给我送了几本书来，自然也就又有一百多块离开了我的身边。
拿到书的时候心情自然是不用说，不过想起床上躺着上个月的科幻世界没看完时，却也着实让人发愁。
有时间的时候没钱，有钱的时候没时间，人生啊！！！
还有可爱的python也是许久没有贡献新东西了，真是惭愧，唉~~~&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-3083700302582596656?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/3083700302582596656/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=3083700302582596656' title='6 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3083700302582596656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3083700302582596656'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/12/blog-post.html' title='工作后'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-8376664447707104354</id><published>2007-09-26T20:46:00.000+08:00</published><updated>2007-09-26T20:48:51.726+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>爆强的翻译</title><content type='html'>第一次见到翻译得这么好的编程之道了：&lt;a href="http://livecn.huasing.org/tao_of_programming.htm"&gt;http://livecn.huasing.org/tao_of_programming.htm&lt;/a&gt;

Prince Wang's programmer was coding software. His fingers danced upon the keyboard. The program compiled without an error message, and the program ran like a gentle wind.
Excellent!" the Prince exclaimed, "Your technique is faultless!"
"Technique?" said the programmer, turning from his terminal, "What I follow is the Tao -- beyond all technique. When I first began to program I would see before me the whole program in one mass. After three years I no longer saw this mass. Instead, I used subroutines. But now I see nothing. My whole being exists in a formless void. My senses are idle. My spirit, free to work without a plan, follows its own instinct. In short, my program writes itself. True, sometimes there are difficult problems. I see them coming, I slow down, I watch silently. Then I change a single line of code and the difficulties vanish like puffs of idle smoke. I then compile the program. I sit still and let the joy of the work fill my being. I close my eyes for a moment and then log off."
Price Wang said, "Would that all of my programmers were as wise!"
程序员为公子王写软件，指飞键舞，不差丝毫，行之如风。
公子王曰：『嘻，善哉！技盖至此乎？』
程序员释键对曰：『臣之所好者道也，进乎技矣。始臣之编程之时，所见无非程序者；三年之后，未尝见程序也，见其子程序也；方今之时，臣以神遇而不以目视，官知止而神欲行，因其固然，程序自写之。诚然，尝至于难者，吾见其难为，怵然为戒，视为止，行为迟，改其一字，謋然已解，如烟随风。使之编译，释键而坐，为之踌躇满志，闭目而log off之。』
公子王曰：『吾之程序员皆如此，则其善焉！』&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-8376664447707104354?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/8376664447707104354/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=8376664447707104354' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8376664447707104354'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8376664447707104354'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/09/blog-post.html' title='爆强的翻译'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4521895195599150</id><published>2007-06-26T01:02:00.000+08:00</published><updated>2007-06-26T01:22:14.382+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>实现一个 django 的 url dispatcher</title><content type='html'>心血来潮，实现了一个 django 的 url dispatcher，比想象中简单多了。
&lt;a href="http://djangodispatcher.googlecode.com/svn/trunk/mapper.py"&gt;http://djangodispatcher.googlecode.com/svn/trunk/mapper.py&lt;/a&gt;
&lt;a href="http://djangodispatcher.googlecode.com/svn/trunk/test.py"&gt;http://djangodispatcher.googlecode.com/svn/trunk/test.py&lt;/a&gt;

实际实现功能的代码才2、30行，功能基本完整，包括分层次的url配置，和发生异常时帮助调试用的一些信息。

PS：发现最近爱上了 Test Driven.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4521895195599150?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4521895195599150/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4521895195599150' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4521895195599150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4521895195599150'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/06/django-url-dispatcher.html' title='实现一个 django 的 url dispatcher'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2327156398965324935</id><published>2007-06-22T17:07:00.000+08:00</published><updated>2007-06-22T17:12:30.744+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>如何在醉酒的情况下编写正确的程序</title><content type='html'>答案很简单：Test Driven。
哈哈，这个（&lt;a href="http://code.google.com/p/pylifegame/"&gt;http://code.google.com/p/pylifegame/&lt;/a&gt;）就是好例子！
醉了，不多说了，自己看去，我要睡觉去了，嗯 ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2327156398965324935?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2327156398965324935/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2327156398965324935' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2327156398965324935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2327156398965324935'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/06/blog-post_22.html' title='如何在醉酒的情况下编写正确的程序'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4028884238963321838</id><published>2007-06-20T12:17:00.000+08:00</published><updated>2007-06-20T12:18:48.711+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>Faint! 和我同名的编辑器</title><content type='html'>&lt;p align="center"&gt;&lt;a href="http://www.haskell.org/yi/Yi.html"&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Yi&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
Yi is a text editor written and extensible in Haskell. The goal of Yi is to provide a flexible, powerful and correct editor core dynamically scriptable in Haskell.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4028884238963321838?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.haskell.org/yi/Yi.html' title='Faint! 和我同名的编辑器'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4028884238963321838/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4028884238963321838' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4028884238963321838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4028884238963321838'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/06/faint.html' title='Faint! 和我同名的编辑器'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-248044144434992470</id><published>2007-06-20T11:28:00.000+08:00</published><updated>2007-06-20T11:31:23.150+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pickle'/><title type='text'>原来 pickle 这么有意思</title><content type='html'>&lt;a href="http://peadrop.com/blog/2007/06/18/pickle-an-interesting-stack-language/"&gt;Pickle: An interesting stack language&lt;/a&gt;
原来 pickle 本身就是就是一个微型的基于栈的语言，呵呵，有点意思。
研究一下 pickle.py 和 pickletools.py ，可以看到更细节的东西。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-248044144434992470?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://peadrop.com/blog/2007/06/18/pickle-an-interesting-stack-language/' title='原来 pickle 这么有意思'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/248044144434992470/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=248044144434992470' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/248044144434992470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/248044144434992470'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/06/pickle.html' title='原来 pickle 这么有意思'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-5512761520356297707</id><published>2007-06-20T11:26:00.000+08:00</published><updated>2007-06-20T11:27:51.872+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python3000'/><title type='text'>翻译了这篇文章</title><content type='html'>&lt;a class="toc-backref" id="python-3000" href="http://wiki.woodpecker.org.cn/moin/Py3000StatusUpdate#id17" name="python-3000"&gt;Python 3000 进度报告&lt;/a&gt;
也可以从 guido 的中文 blog 看到：&lt;a href="http://blog.csdn.net/gvanrossum/archive/2007/06/20/1658829.aspx"&gt;http://blog.csdn.net/gvanrossum/archive/2007/06/20/1658829.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-5512761520356297707?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://wiki.woodpecker.org.cn/moin/Py3000StatusUpdate' title='翻译了这篇文章'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/5512761520356297707/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=5512761520356297707' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5512761520356297707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5512761520356297707'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/06/blog-post_20.html' title='翻译了这篇文章'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2786400504209156668</id><published>2007-06-19T16:39:00.000+08:00</published><updated>2007-06-19T16:41:52.638+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python3000'/><title type='text'>Python 3000 Status Update (Long!)</title><content type='html'>&lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=208549"&gt;Python 3000 Status Update (Long!)&lt;/a&gt; by Guido van Rossum """
&lt;strong&gt;Summary&lt;/strong&gt;
Here's a long-awaited update on where the Python 3000 project stands. We're looking at a modest two months of schedule slip, and many exciting new features. I'll be presenting this in person several times over the next two months.
"""&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2786400504209156668?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.artima.com/weblogs/viewpost.jsp?thread=208549' title='Python 3000 Status Update (Long!)'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2786400504209156668/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2786400504209156668' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2786400504209156668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2786400504209156668'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/06/python-3000-status-update-long.html' title='Python 3000 Status Update (Long!)'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-7268198981529498579</id><published>2007-06-08T23:47:00.000+08:00</published><updated>2007-06-09T00:32:13.755+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>老子毕业了</title><content type='html'>&lt;a href="http://picasaweb.google.com/yi.codeplayer/070608"&gt;http://picasaweb.google.com/yi.codeplayer/070608&lt;/a&gt;


&lt;img src="http://lh6.google.com/image/yi.codeplayer/Rmlv-LQQLXI/AAAAAAAAAEU/423ul6UtTDo/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20005.jpg?imgmax=512" /&gt;
&lt;img src="http://lh5.google.com/image/yi.codeplayer/Rmlzc7QQLhI/AAAAAAAAAFo/PBd5rwh1KOM/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20015.jpg?imgmax=288" /&gt;
&lt;img src="http://lh5.google.com/image/yi.codeplayer/Rmlys7QQLgI/AAAAAAAAAFc/LJtHUc00iHg/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20014.jpg?imgmax=288" /&gt;
&lt;img src="http://lh6.google.com/image/yi.codeplayer/RmlzuLQQLiI/AAAAAAAAAFw/F2E--aoUcA4/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20016.jpg?imgmax=288" /&gt;
&lt;img src="http://lh5.google.com/image/yi.codeplayer/RmlyQ7QQLfI/AAAAAAAAAFU/9oWUzy0bfVc/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20013.jpg?imgmax=288" /&gt;
&lt;img src="http://lh4.google.com/image/yi.codeplayer/Rml5YrQQLnI/AAAAAAAAAGw/JziZHS0IDeg/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20021.jpg?imgmax=288" /&gt;
&lt;img src="http://lh4.google.com/image/yi.codeplayer/Rml-brQQMOI/AAAAAAAAALo/8u55Fz0TjUs/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20060.jpg?imgmax=288" /&gt;
&lt;img src="http://lh6.google.com/image/yi.codeplayer/Rml-nLQQMQI/AAAAAAAAAL4/5g0YrKSybM8/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20062.jpg?imgmax=288" /&gt;
&lt;img src="http://lh3.google.com/image/yi.codeplayer/Rml8ibQQL9I/AAAAAAAAAJg/i1Xoy4znGPk/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20043.jpg?imgmax=288" /&gt;
&lt;img src="http://lh5.google.com/image/yi.codeplayer/Rml_c7QQMaI/AAAAAAAAANI/dc_1YSpT1Bw/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20073.jpg?imgmax=288" /&gt;
&lt;img src="http://lh4.google.com/image/yi.codeplayer/RmmCNrQQM2I/AAAAAAAAAQo/ICgcSN1lOMw/%E5%AD%A6%E5%A3%AB%E6%9C%8D070608%20101.jpg?imgmax=288" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-7268198981529498579?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://picasaweb.google.com/yi.codeplayer/070608' title='老子毕业了'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/7268198981529498579/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=7268198981529498579' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7268198981529498579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7268198981529498579'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/06/blog-post.html' title='老子毕业了'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-1870267912331268088</id><published>2007-06-03T02:22:00.000+08:00</published><updated>2007-06-03T02:47:51.927+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sqlalchemy'/><title type='text'>SQLAlchemy Examples</title><content type='html'>看 SQLAlchemy 自带的 zblog 的例子，可以看到 SQLAlchemy 一些非常有用的特性。

&lt;p&gt;&lt;strong&gt;文章相关评论数统计&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;比如显示文章列表的同时我们希望获得相关文章的评论数，如果是用 django 那就只能放弃 ORM 的好处自己去执行 sql 语句了，否则就只会导致 n+1 条 SQL 语句的执行。
在 SQLAlchemy 中你可以把任意的 select 语句映射到一个 class ，这样就可以用一条 SQL 语句搞定，还能获得 ORM 的好处，下面是原封不动拷过来的代码（只调整了下格式）：&lt;/p&gt;&lt;pre&gt;   # Post mapper, these are posts within a blog.
  # since we want the count of comments for each post,
  # create a select that will get the posts
  # and count the comments in one query.
  posts_with_ccount = select(
      [c for c in tables.posts.c if c.key != 'body'] + [
          func.count(tables.comments.c.comment_id).label('comment_count')
      ],
      from_obj = [
          outerjoin(tables.posts, tables.comments)
      ],
      group_by=[
          c for c in tables.posts.c if c.key != 'body'
      ]
      ) .alias('postswcount')

  # then create a Post mapper on that query.
  # we have the body as "deferred" so that it loads only when needed,
  # the user as a Lazy load, since the lazy load will run only once per user and
  # its usually only one user's posts is needed per page,
  # the owning blog is a lazy load since its also probably loaded into the identity map
  # already, and topics is an eager load since that query has to be done per post in any
  # case.
  mapper(Post, posts_with_ccount, properties={
      'id':posts_with_ccount.c.post_id,
      'body':deferred(tables.posts.c.body),
      'user':relation(user.User, lazy=True,
               backref=backref('posts', cascade="all, delete-orphan")),
      'blog':relation(Blog, lazy=True,
               backref=backref('posts', cascade="all, delete-orphan")),
      'topics':relation(TopicAssociation, lazy=False, private=True,
               association=Topic, backref='post')
  }, order_by=[desc(posts_with_ccount.c.datetime)])&lt;/pre&gt;
&lt;strong&gt;树形评论&lt;/strong&gt;
映射如下：
&lt;pre&gt;   # comment mapper.  This mapper is handling a hierarchical relationship on itself,
  # and contains
  # a lazy reference both to its parent comment and its list of child comments.
  mapper(Comment, tables.comments, properties={
      'id':tables.comments.c.comment_id,
      'post':relation(Post, lazy=True,
               backref=backref('comments', cascade="all, delete-orphan")),
      'user':relation(user.User, lazy=False,
               backref=backref('comments', cascade="all, delete-orphan")),
      'parent':relation(Comment,
               primaryjoin=tables.comments.c.parent_comment_id==tables.comments.c.comment_id,
               foreignkey=tables.comments.c.comment_id, lazy=True, uselist=False),
      'replies':relation(Comment,
               primaryjoin=tables.comments.c.parent_comment_id==tables.comments.c.comment_id,
               lazy=True, uselist=True, cascade="all"),
  })
&lt;/pre&gt;
很多时候我们需要一次性获取对应一个文章的所有评论，可以用一条 select 先把数据取出，然后手动建立树形结构：
&lt;pre&gt;# we define one special find-by for the comments of a post, which is going to make its own
# "noload" mapper and organize the comments into their correct hierarchy in one pass. hierarchical
# data normally needs to be loaded by separate queries for each set of children, unless you
# use a proprietary extension like CONNECT BY.
def find_by_post(post):
  """returns a hierarchical collection of comments based on a given criterion.
  uses a mapper that does not lazy load replies or parents, and instead
  organizes comments into a hierarchical tree when the result is produced.
  """
  q = session().query(Comment).options(noload('replies'), noload('parent'))
  comments = q.select_by(post_id=post.id)
  result = []
  d = {}
  for c in comments:
      d[c.id] = c
      if c.parent_comment_id is None:
          result.append(c)
          c.parent=None
      else:
          parent = d[c.parent_comment_id]
          parent.replies.append(c)
          c.parent = parent
  return result

Comment.find_by_post = staticmethod(find_by_post)
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-1870267912331268088?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/1870267912331268088/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=1870267912331268088' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1870267912331268088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1870267912331268088'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/06/sqlalchemy-examples.html' title='SQLAlchemy Examples'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-1752792102647239870</id><published>2007-05-30T12:29:00.000+08:00</published><updated>2007-05-30T12:40:10.306+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='stackless'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='continuation'/><title type='text'>multitask and Hive</title><content type='html'>&lt;a href="http://o2s.csail.mit.edu/o2s-wiki/multitask"&gt;&lt;strong&gt;multitask&lt;/strong&gt;&lt;/a&gt;
multitask allows Python programs to use generators (aka coroutines) to perform cooperative multitasking and asynchronous I/O. Applications written using multitask consist of a set of cooperating tasks that yield to a shared task manager whenever they perform a (potentially) blocking operation, such as I/O on a socket or getting data from a queue. The task manager temporarily suspends the task (allowing other tasks to run in the meantime) and then restarts it when the blocking operation is complete. Such an approach is suitable for applications that would otherwise have to use select() and/or multiple threads to achieve concurrency.
&lt;a href="http://www.oluyede.org/blog/2007/05/29/producerconsumer-with-multitask-library/"&gt;Producer/Consumer with multitask library &lt;/a&gt;

&lt;a href="http://cheeseshop.python.org/pypi/Hive"&gt;&lt;strong&gt;Hive&lt;/strong&gt;&lt;/a&gt;
This is a basic concurrency module that uses only dependencies available in the Python 2.5 standard library. It allows the creation of a jobfile for uses to queue work that any number of worker processes with access to the jobfile can pull from the queue and run.

看到这两个库很快就联想到曾经写过的&lt;a href="http://codeplayer.blogspot.com/2006/09/python25-yield-stacklesspython.html"&gt;那段代码&lt;/a&gt;，python2.5 增强的 yield 表达式所蕴涵的 continuation 的能力似乎终于有人拿它来发挥点实际作用了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-1752792102647239870?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/1752792102647239870/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=1752792102647239870' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1752792102647239870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1752792102647239870'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/multitask-and-hive.html' title='multitask and Hive'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-3887861122517836240</id><published>2007-05-30T12:16:00.000+08:00</published><updated>2007-05-30T12:28:47.910+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='sqlalchemy'/><title type='text'>Polymorphic Associations in Rails</title><content type='html'>&lt;a title="Permanent Link to Polymorphic Associations with SQLAlchemy" href="http://techspot.zzzeek.org/?p=13" rel="bookmark"&gt;Polymorphic Associations with SQLAlchemy&lt;/a&gt;
&lt;a href="http://techspot.zzzeek.org/"&gt;SQLAlchemy 老大&lt;/a&gt;展示怎么用 &lt;a href="http://www.sqlalchemy.org"&gt;sqlalchemy &lt;/a&gt;实现 rails 的 &lt;a href="http://wiki.rubyonrails.com/rails/pages/UnderstandingPolymorphicAssociations"&gt;Polymorphic Associations &lt;/a&gt;
顺便看了下 Rails 所谓&lt;a href="http://wiki.rubyonrails.com/rails/pages/UnderstandingPolymorphicAssociations"&gt;Polymorphic Associations &lt;/a&gt;的介绍，才发现其实就是我很早就&lt;a href="http://codeplayer.blogspot.com/2006/09/django-contribs-contenttype.html"&gt;介绍过&lt;/a&gt;的 django 的 content-type app 所干的事情，app 就是插件的意思。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-3887861122517836240?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/3887861122517836240/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=3887861122517836240' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3887861122517836240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3887861122517836240'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/polymorphic-associations-in-rails.html' title='Polymorphic Associations in Rails'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-6104566048530825814</id><published>2007-05-26T16:23:00.000+08:00</published><updated>2007-05-26T16:29:34.893+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vim'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Python and vim: Two great tastes that go great together</title><content type='html'>&lt;a href="http://www.tummy.com/Community/Presentations/vimpython-20070225/vim.html"&gt;Python and vim: Two great tastes that go great together&lt;/a&gt;

用 python 扩展 vim ，想法倒是不新，不过第一次看到 tutotial 。

记得 tocer 说过要用 python 写个 vim 库的，不知道有没有进展哈，呵呵。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-6104566048530825814?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.tummy.com/Community/Presentations/vimpython-20070225/vim.html' title='Python and vim: Two great tastes that go great together'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/6104566048530825814/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=6104566048530825814' title='8 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6104566048530825814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6104566048530825814'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/python-and-vim-two-great-tastes-that-go.html' title='Python and vim: Two great tastes that go great together'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2266117505551383861</id><published>2007-05-26T15:47:00.000+08:00</published><updated>2007-05-26T15:51:31.860+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Evolution of a Python programmer</title><content type='html'>&lt;a href="http://dis.4chan.org/read/prog/1180084983/"&gt;http://dis.4chan.org/read/prog/1180084983/&lt;/a&gt;

哈哈，有点意思，再加一个：

Python 2.5 programmer:
&lt;pre&gt;def fact(x):
    return x * fact(x - 1) if x &gt; 1 else 1
print fact(6)
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2266117505551383861?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://dis.4chan.org/read/prog/1180084983/' title='Evolution of a Python programmer'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2266117505551383861/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2266117505551383861' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2266117505551383861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2266117505551383861'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/evolution-of-python-programmer.html' title='Evolution of a Python programmer'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-1038369601701991927</id><published>2007-05-22T02:47:00.000+08:00</published><updated>2007-05-22T02:57:31.400+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>Elixir Examples</title><content type='html'>有的时候在 blog 里写 wiki，有的时候在 wiki 里写 blog，有的时候在 blog 里发在 wiki 里写的 blog ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-1038369601701991927?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://wiki.woodpecker.org.cn/moin/SQLAlchemy/ElixirExamples' title='Elixir Examples'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/1038369601701991927/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=1038369601701991927' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1038369601701991927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1038369601701991927'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/elixir-examples.html' title='Elixir Examples'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-1239642480709403512</id><published>2007-05-22T01:57:00.000+08:00</published><updated>2007-05-22T02:30:26.715+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>多重继承真是好哇</title><content type='html'>写 model 的时候发现有些东西在重复，第一反应就是写个基类，把这些重复的东西拿出来，然而 Model 类之间继承却不是那么方便的，应该会影响到 ORM 的行为。
怎么办呢？幸好 python 有多重继承。
下面就是项目中做这些重复事情的类：
&lt;pre&gt;class ModelMixin(object):
    def save(self):
        if not self.id: # creation time
            if hasattr(self, 'pubdate'):
                self.pubdate = datetime.now()
            if hasattr(self, 'pubtime'):
                self.pubtime = datetime.now()

        if hasattr(self, 'updatedate'):
            self.updatedate = datetime.now()
        if hasattr(self, 'updatetime'):
            self.updatetime = datetime.now()
        if hasattr(self, 'number'): # 今天第几次发布
            self.number = self.__class__.objects.filter(pubdate=datetime.now()).count()+1

        if hasattr(self, 'before_save'):
            self.before_save()
        super(ModelMixin, self).save()
        if hasattr(self, 'after_save'):
            self.after_save()
&lt;/pre&gt;
注意：django 将废弃 auto_add 和 auto_now 这些东西，认为太 magic ，建议在 save 中处理，所以上面这个类就更有用了。

怎么用呢？
&lt;pre&gt;class Product(ModelMixin, models.Model):
    pubdate = models.DateField(u'...', editable=False)
    number = models.IntegerField(u'...', editable=False)
    ...
&lt;/pre&gt;
这样 pubdate 和 number 自然就有了相应的含义了。另外 ModelMixin 还定义了 before_save 和 after_save 的钩子，具体 model 可以在这两个方法里放点代码，比如：
&lt;pre&gt;    def before_save(self):
        self.totalprice = self.count * self.product.unitprice

...

    def after_save(self):
        if self._create:
            p = OutProduct(postuser=self.postuser,count=1,
                    pubdate=self.pubdate,mainproduct=self)
            p.save()
&lt;/pre&gt;
这些都是项目中直接拷出来的代码，具体意思你就慢慢猜吧，呵呵。

多重继承的实现其实是个还算复杂的过程，复杂的多重继承也会产生一些奇特的行为，不过基本上只要遵守一些良好的习惯（比如常用 super ，虽然写起来有些繁琐），了解一些多重继承的基本原理，基本上不会遇到什么奇怪的问题了。
关于 python 多重继承的实现，请看：&lt;a href="http://www.python.org/download/releases/2.3/mro/"&gt;The Python 2.3 Mehod Resolution Order&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-1239642480709403512?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/1239642480709403512/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=1239642480709403512' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1239642480709403512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1239642480709403512'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/blog-post.html' title='多重继承真是好哇'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2398595637388166171</id><published>2007-05-22T01:08:00.000+08:00</published><updated>2007-05-22T01:40:20.116+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='newforms'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>newforms 太好用了</title><content type='html'>建一个项目 newformstutorials ，建一个 app blog ，在 blog 的 models 中定义个：
&lt;pre&gt;class Article(models.Model):
    title = models.CharField(u'标题', maxlength=255)
    author = models.CharField(u'作者', maxlength=20)
    hits = models.IntegerField(u'点击数', default=0, editable=False)
    content = models.TextField(u'内容')
&lt;/pre&gt;
配置好数据库，把 newformstutorials.blog 加到 INSTALLED_APPS，manage.py syncdb，然后 manage.py shell ，然后：
&lt;pre&gt;In [1]: import django.newforms as forms

In [2]: from newformstutorials.blog.models import Article

In [3]: ArticleForm = forms.form_for_model(Article)

In [4]: form = ArticleForm()

In [5]: print unicode(form)
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&amp;lt;label for="id_title"&amp;gt;标题:&amp;lt;/label&amp;gt;&amp;lt;/th&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input id="id_title" type="t
ext" name="title" maxlength="255" /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&amp;lt;label for="id_author"&amp;gt;作者:&amp;lt;/label&amp;gt;&amp;lt;/th&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input id="id_author" type=
"text" name="author" maxlength="20" /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&amp;lt;label for="id_content"&amp;gt;内容:&amp;lt;/label&amp;gt;&amp;lt;/th&amp;gt;&amp;lt;td&amp;gt;&amp;lt;textarea id="id_content"
rows="10" cols="40" name="content"&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;

In [6]: print form.as_ul()
&amp;lt;li&amp;gt;&amp;lt;label for="id_title"&amp;gt;标题:&amp;lt;/label&amp;gt; &amp;lt;input id="id_title" type="text" name="t
itle" maxlength="255" /&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;label for="id_author"&amp;gt;作者:&amp;lt;/label&amp;gt; &amp;lt;input id="id_author" type="text" name=
"author" maxlength="20" /&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;label for="id_content"&amp;gt;内容:&amp;lt;/label&amp;gt; &amp;lt;textarea id="id_content" rows="10" co
ls="40" name="content"&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/li&amp;gt;
&lt;/pre&gt;
一个空白的 form 就这样出来了，这就是个添加文章的表单，让我们用这个表单来加点数据吧：
&lt;pre&gt;In [7]: form = ArticleForm({'title':'some title','author':'huangyi'})

In [8]: form.is_valid()
Out[8]: False

In [9]: form.errors
Out[9]: {'content': [u'This field is required.']}

In [10]: form = ArticleForm({'title':'some title','author':'huangyi', 'content':
'some contents...'})

In [11]: form.is_valid()
Out[11]: True

In [12]: article = form.save(commit=True)
&lt;/pre&gt;
OK，数据就这样保存了，我们再来试试数据更新的页面吧：
&lt;pre&gt;In [13]: ChangeForm = forms.form_for_instance(article)

In [14]: form = ChangeForm()

In [15]: print unicode(form)
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&amp;lt;label for="id_title"&amp;gt;标题:&amp;lt;/label&amp;gt;&amp;lt;/th&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input id="id_title" type="t
ext" name="title" value="some title" maxlength="255" /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&amp;lt;label for="id_author"&amp;gt;作者:&amp;lt;/label&amp;gt;&amp;lt;/th&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input id="id_author" type=
"text" name="author" value="huangyi" maxlength="20" /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&amp;lt;label for="id_content"&amp;gt;内容:&amp;lt;/label&amp;gt;&amp;lt;/th&amp;gt;&amp;lt;td&amp;gt;&amp;lt;textarea id="id_content"
rows="10" cols="40" name="content"&amp;gt;some contents...&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;

In [16]: form = ChangeForm({'title':'another title', 'author':'huangyi', 'conten
t':'other contents...'})
In [17]: form.is_valid()
Out[17]: True

In [18]: form.save()
Out[18]: &amp;lt;Article: Article object&amp;gt;

In [19]: article = Article.objects.get(id=article.id)

In [20]: article.title
Out[20]: 'another title'
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2398595637388166171?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2398595637388166171/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2398595637388166171' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2398595637388166171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2398595637388166171'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/newforms.html' title='newforms 太好用了'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-6184862087764942116</id><published>2007-05-21T23:41:00.000+08:00</published><updated>2007-05-22T01:48:28.832+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>django newforms admin</title><content type='html'>又用 django 做了个项目，因为主要都是后台的东西，所以决定启用 django 的 &lt;a href="http://code.djangoproject.com/wiki/NewformsAdminBranch"&gt;newforms admin 分支&lt;/a&gt;！(不过这里我不是推荐大家现在就开始用 newforms admin 分支，如果没有把握，最好是抱着玩玩的态度先，我在开发过程中就改掉它好几个bug)

newforms admin 分支是用 newforms 来重构 admin 模块，也顺便改变了一些设计决策，大大增强了 admin 的可定制性。首先 newforms 的应用，成功分离了 db field、form field、widget 三个部分，db field 属于 ORM ，主要负责 model 相关的事务，form field 主要处理用户输入数据的验证，widget 负责渲染ui，似乎这里面还透着 MVC 的影子呢 ;-)
newforms admin中可以方便地对 widget 进行替换，怎一个爽字了得。
另外，新的 admin 把 admin 部分的定义从 model 中分离出来了，似乎写起来要麻烦点，不过好处也是显而易见的，首先是 model 定义更整洁了，其次新的 admin 设计成了一种重用性更好的形式，用得好的话还能省下不少代码呢，而且能够完成一些以前的 admin 很难完成的任务。
新 admin 的核心在于 AdminSite 和 AdminModel，AdminSite 负责一些全局性的事务，比如首页，用户登录登出改密码权限控制，和model的注册，AdminModel 负责单个 model 的相关管理页面。 这样做的好处是你可以继承这两个类，覆盖掉一些合适的方法，你基本上可以为所欲为。
比如，我在这个项目中就写了这么几个自定义的 admin 类：
&lt;pre&gt;
class CustomAdmin(admin.ModelAdmin):
    def before_save(self, request, instance, form, change=False):
        pass

    def save_add(self, request, model, form, post_url_continue):
        def custom_save(form, commit=False):
            instance = model()
            new_object = forms.save_instance(form, instance,
                    fail_message='created', commit=False)
            self.before_save(request, new_object, form)
            if commit:
                new_object.save()
                for f in model._meta.many_to_many:
                    if f.name in form.cleaned_data:
                        setattr(new_object, f.attname, form.cleaned_data[f.name])
            return new_object
        form.__class__.save = custom_save
        return super(CustomAdmin, self).save_add(request, model, form,
                    post_url_continue)

    def save_change(self, request, model, form):
        def custom_save(form, commit=False):
            from copy import copy
            new_object = forms.save_instance(form,
                    copy(form.original_object),
                    fail_message='changed', commit=False)
            self.before_save(request, new_object, form, change=True)
            if commit:
                new_object.save()
                for f in model._meta.many_to_many:
                    if f.name in form.cleaned_data:
                        setattr(new_object, f.attname, form.cleaned_data[f.name])
            return new_object
        form.__class__.save = custom_save
        return super(CustomAdmin, self).save_change(request, model, form)&lt;/pre&gt;
大家应该可以看得出来，这个 admin 提供了 before_save 的钩子（当然你也可以提供 after_save 不过我这里暂时只需要 before_save），你可以继承它然后在这个方法里写些代码，就得在 model 保存之前得到执行。你可能要问，为什么不直接定义 Model 的 save 方法呢？答案很简单 Model 不知道 request 和 form 的存在！
在 before_save 中你就可以做些很有意思的事情了，比如自动把 model 中某个字段设置成当前登录用户！这个定制需求其实很早就提出来了，以前的解决方案是写个 middleware 把 request 放到 threadlocal 中去，然后在 model 中通过 threadlocal 获取当前请求的 request ，能用，但是很麻烦也很丑。现在用这个 before_save 可以轻松实现：
&lt;pre&gt;class AutoUserAdmin(CustomAdmin):
    user_field_name = 'postuser'
    def before_save(self, request, instance, form, change=False):
        setattr(instance, self.user_field_name, request.user)
        super(AutoUserAdmin, self).before_save(request, instance, form, change)
&lt;/pre&gt;
当然你也可以继承这个 AutoUserAdmin ，写上你自己的 user_field_name ，太简单了。
还有一个常见的定制需求就是限制登录用户只能看到自己发布的信息，看不到更不能修改别人发布的信息。 在上面这个 AutoUserAdmin 的基础上做：
&lt;pre&gt;class RestrictUserAdmin(AutoUserAdmin):
    def queryset(self, request):
        queries = {self.user_field_name:request.user}
        return super(RestrictUserAdmin, self).queryset(request).\
                filter(**queries)
&lt;/pre&gt;
是不是超简单？呵呵。
另外别忘了 python 还支持传说中的多重继承，意味着你可以同时继承多个 admin 类，并拥有多个 admin 类的组合功能。比如我这里定制了一个支持文件上传的 admin（newforms 和 newforms admin 暂时都还没有把文件上传相关的东西加进去，只能自己写），我把它叫做 FileUploadAdmin ，现在我希望我的 admin 能同时拥有 RestrictUserAdmin 和 FileUploadAdmin 的功能，没问题：
&lt;pre&gt;class CommonAdmin(FileUploadAdmin, RestrictUserAdmin):
    date_hierarchy = 'pubdate'
    list_per_page = 15
    ordering = ('-id',)
&lt;/pre&gt;
当然我还在里面定义了一些通用的（当然是对于我自己的项目来说） admin 配置。
然后怎么把这些 admin 应用到 model 上去呢？
&lt;pre&gt;class ProductAdmin(CommonAdmin):
    list_display = ('__str__', 'type', 'unitname', 'unitprice',
        'qsinfo', 'postuser', 'pubdate', 'image_view')
    list_filter = ('type', 'pubdate')
)
admin.site.register(Product, ProductAdmin)
&lt;/pre&gt;
上面的代码虽然不错，不过我还是嫌麻烦，实际上我是这么写的：
&lt;pre&gt;admin.site.register(Product,
    CommonAdmin,
    list_display = ('__str__', 'type', 'unitname', 'unitprice',
        'qsinfo', 'postuser', 'pubdate', 'image_view'),
    list_filter = ('type', 'pubdate'),
    section_name = '通用',
)
&lt;/pre&gt;
不过要让上面的代码正常运行，还需要对 django newforms admin 分支的代码做一点小改动才行，在文件 django/contrib/admin/sites.py 中大约 73 行的位置：
&lt;pre&gt;          # TODO: Handle options&lt;/pre&gt;
的下面加上：
&lt;pre&gt;          # it works
        if options:
            admin_class = type(admin_class.__name__, (admin_class,),
                    options)&lt;/pre&gt;
实际上，使用 django 乃至 python 最大的快乐就是别人写的代码你都可以轻松看懂，这难道不是作为程序员最大的快乐吗？ ;-)

如果你现在开始用 django newforms admin 分支的话，估计遇到的大部分问题都是和 unicode 有关（因为我遇到的就是这样的），这是因为目前 django 的开发 和 python 本身的开发一样，都处在整体向 unicode 迁移的过程之中，当前最大的矛盾就是 ORM 使用的是普通字符串(也就是 python3000中所谓字节数组)，而 newforms 却开始整体使用 unicode 了，这常常带来麻烦。如果你在基于 django 最新的 svn 版本开发，那一定要看一下 &lt;a href="http://code.djangoproject.com/wiki/UnicodeBranch"&gt;Unicode 分支&lt;/a&gt;了，里面说到了如何使让你的程序顺利过渡到 unicode ，祝大家过渡快乐 ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-6184862087764942116?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/6184862087764942116/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=6184862087764942116' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6184862087764942116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6184862087764942116'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/django-newforms-admin.html' title='django newforms admin'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-5489160500752784450</id><published>2007-05-15T21:37:00.000+08:00</published><updated>2007-05-15T21:48:10.989+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>好久没写blog了</title><content type='html'>&lt;p&gt;好久没写 blog 了，现在毕业论文终于敲定，可以长舒一口气 ;-)&lt;/p&gt;&lt;p&gt;写论文的时候，rst 可真是帮我不少忙，不过学校规定得交 doc 的版本，包括论文的格式什么的都是针对 msword 来说的，只好用 rst 生成 html ，然后拷贝到 msword。看到同学直接在 msword 里写论文，最后再痛苦地调整格式，窃喜 ;-)&lt;/p&gt;&lt;p&gt;继续我们可爱的python的写作，不过写到现在感觉自己还是不习惯写入门的东西，总是不自觉地想用最简洁的语言把所有东西都说出来（不过这倒符合python的哲学 = =" ），只好努力压下许多 python 的好东东了。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-5489160500752784450?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/5489160500752784450/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=5489160500752784450' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5489160500752784450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5489160500752784450'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/blog.html' title='好久没写blog了'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-9023098109496689631</id><published>2007-05-01T14:07:00.001+08:00</published><updated>2007-05-15T22:35:11.040+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python3000'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>python3000与接口</title><content type='html'>"""
要编写复杂软件又不至于一败涂地的唯一方法就是用定义清晰的接口把若干简单模块组合起来。
"""
抽象的说，其实接口、契约、协议、界面等等概念说的差不多都是一个意思。
作为如此流行的被大规模使用的语言，python 一直没有这么个东西的标准实现，实在是一种遗憾，当然第三方的实现 zope.interface 其实早就在 zope 和 twisted 中大量应用了。

python 3000 中正在讨论的：
&lt;a href="http://www.python.org/dev/peps/pep-3119"&gt;pep 3119 Introducing Abstract Base Classes&lt;/a&gt;；
&lt;a href="http://www.python.org/dev/peps/pep-3124"&gt;pep 3124 Overloading, Generic Functions, Interfaces, and Adaptation&lt;/a&gt;；
（还有 &lt;a href="http://www.python.org/dev/peps/pep-3133"&gt;pep 3133 Introducing Roles &lt;/a&gt;，不过暂时没看出它和 Abstracet Base Class 有啥大区别）
希望向 python 中引入一些类型约束的能力，配合上已经被接受的 &lt;a href="http://www.python.org/dev/peps/pep-3107"&gt;PEP 3107 Function Annotations &lt;/a&gt;提议的语法，真是对 python 非常好的补充。
甚至对其他动态语言也是非常好的一个启示！

另外，啄木鸟上有&lt;a href="http://wiki.woodpecker.org.cn/moin/Python3000"&gt; python3000 页面&lt;/a&gt;，欢迎大家在上面添加自己的想法 ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-9023098109496689631?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/9023098109496689631/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=9023098109496689631' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/9023098109496689631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/9023098109496689631'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/05/python3000.html' title='python3000与接口'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-915667823146770986</id><published>2007-04-02T15:27:00.000+08:00</published><updated>2007-04-02T15:31:12.965+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>新的 pep ！</title><content type='html'>虽然我发晚了一点，但还是很值得一看的 PEP ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-915667823146770986?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://mail.python.org/pipermail/python-dev/2007-April/072419.html' title='新的 pep ！'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/915667823146770986/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=915667823146770986' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/915667823146770986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/915667823146770986'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/04/pep.html' title='新的 pep ！'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-3629060886131628694</id><published>2007-04-01T01:26:00.000+08:00</published><updated>2007-04-01T01:32:26.738+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>突破 gwf 的封锁 访问 blogger 的通用方法</title><content type='html'>根据&lt;a href="http://www.gseeker.com/50226711/blogspoteeaeie070328ie_78129.php"&gt;这篇文章&lt;/a&gt;给出的好办法，&lt;a href="http://www.gseeker.com/50226711/ieblogspotaeaeieeeie_85030.php"&gt;据说&lt;/a&gt; ie 下也可以用。
简单得说就是先下载&lt;a href="http://www.kenwong.cn/wp-content/proxy.pac"&gt;这个代理文件&lt;/a&gt;，比如说你保存在 c:/proxy.pac，然后在 firefox 中 选项 -&gt; 高级 -&gt; 连接配置 -&gt; 自动配置代理url ，填入 file:///c:/proxy.pac 。
如果有任何疑问看上面的连接以获得详细的配置办法！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-3629060886131628694?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/3629060886131628694/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=3629060886131628694' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3629060886131628694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3629060886131628694'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/04/gwf-blogger.html' title='突破 gwf 的封锁 访问 blogger 的通用方法'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-1617844793598423838</id><published>2007-03-30T15:56:00.000+08:00</published><updated>2007-03-30T16:01:03.521+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pypy'/><title type='text'>trying out PyPy</title><content type='html'>对 pypy 的简单试验，惊叹其优化的智能！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-1617844793598423838?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://docs.google.com/Doc?id=dczg8vtk_24g5sdrr' title='trying out PyPy'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/1617844793598423838/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=1617844793598423838' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1617844793598423838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1617844793598423838'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/03/trying-out-pypy.html' title='trying out PyPy'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-1870566978691856850</id><published>2007-03-27T09:52:00.000+08:00</published><updated>2007-03-27T09:58:22.260+08:00</updated><title type='text'>[有趣]Invasion Of The Dynamic Language Weenies</title><content type='html'>&lt;a href="http://www.hacknot.info/hacknot/action/showEntry?eid=93"&gt;Invasion Of The Dynamic Language Weenies&lt;/a&gt;
这文章很是耐人寻味，嘿嘿 ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-1870566978691856850?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/1870566978691856850/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=1870566978691856850' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1870566978691856850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1870566978691856850'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/03/invasion-of-dynamic-language-weenies.html' title='[有趣]Invasion Of The Dynamic Language Weenies'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4392426361108766572</id><published>2007-03-18T15:45:00.000+08:00</published><updated>2007-03-18T15:59:14.872+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>django and non programmers</title><content type='html'>看了&lt;a href="http://www.wilsonminer.com/posts/2006/may/09/are-you-generic/"&gt;Are You Generic?&lt;/a&gt;，&lt;a href="http://www2.jeffcroft.com/blog/2006/may/02/django-non-programmers/"&gt;Django for non-programmers&lt;/a&gt; 两篇文章。
django 真是设计人员的福音啊！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4392426361108766572?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4392426361108766572/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4392426361108766572' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4392426361108766572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4392426361108766572'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/03/django-and-non-programmers.html' title='django and non programmers'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4607725305714146838</id><published>2007-03-17T14:43:00.000+08:00</published><updated>2007-03-19T18:18:22.493+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>字典与动态语言</title><content type='html'>字典（或者叫哈希表、关联数组..）与动态语言的渊源可谓极深。动态语言之所以动态，归根结底是因为把对变量的求值放在了运行时完成而非静态语言的编译时确定。动态语言程序中众多的不同层次的名字空间（或者说作用范围）其实就是一个个的字典，变量名为 key，对象为 value。
    而对变量求值的过程就是对所在名字空间查找的过程，根据变量名，找出相应的对象，有时候在局部名字空间中没找到，还可能会自动跑到外部名字空间或是全局名字空间去找。
    对于支持 OO 的动态语言，对对象的实现其实也都是字典，属性名为 key，属性值为 value ，属性的获取也就变成了对字典的查找。有时子类中找不到还会到父类中去找，这也就是动态语言对继承的实现。
    javascript 的 prototype 可能是动态语言实现继承最直接最简洁的方式了。python 为 OO 加了几个新语法，新概念，还有对多重继承的支持，不过本质上其实还差不多。
    字典的核心地位在 lua、javascript 中表现得最为明显，在 javascript 中字典和 object 其实就是同义词；在 python 中其实也不难找到字典的身影：locals()、globals()、还有(几乎)所有对象都有的 __dict__ 属性；ruby 这样的语言中这一点会藏得深一些。
    【以下为个人感受】
    字典是动态语言的灵魂，要使用好动态语言首先肯定是要认清这一点的，不过在实际软件开发中像 lua 一样直面字典编程未免太简陋了一些，javascript 稍微好点，python 完美，而 ruby 过了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4607725305714146838?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4607725305714146838/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4607725305714146838' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4607725305714146838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4607725305714146838'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/03/blog-post.html' title='字典与动态语言'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-3022552876276823051</id><published>2007-03-12T17:06:00.000+08:00</published><updated>2007-03-12T17:29:03.732+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='pypy'/><title type='text'>pypy 介绍</title><content type='html'>前面写过篇&lt;a href="http://codeplayer.blogspot.com/2006/12/python-virtual-machines.html"&gt;介绍 pypy 的文章&lt;/a&gt;了，不过感觉有些东西还说得不够清楚也不够准确。

pypy 分为两部分：一个 python 的实现 和 一个编译器。
pypy 这名字说的就是这第一部分：用python实现的python。但其实这么说并不准确，准确得说应该是用 rpython 实现的 python ，rpython 是 python 的一个子集，不过不要搞混了，虽然 rpython 不是完整的 python ，但用 rpython 写的这个 python 实现却是可以解释完整的 python 语言。
那为什么要用 rpython 来写这个 python 实现呢，这其实就涉及到了 pypy 的第二部分：编译器。
这是一个编译 rpython 的编译器，或者说这个编译器有一个 rpython 的前端，目前也只有这么一个前端，不过它的后端却是不少，也就是说这个编译器支持许多的目标语言，比较重要的有：c, cli, javascript ...
而当我们把这两部分合起来看的时候，就能够发现 pypy 最重大的意义所在，当我们用这个编译器来编译这个用 rpython 写的 python 实现，我们能够得到什么呢？一个 c 写的 python 实现，一个用 .net 写的 python 实现（不过目前的 cli 后端还不能用来编译这个 python 实现） ...

我想这个介绍应该是比较简要了，pypy 的这两个大部分中都包含有许多有趣的内容，等玩得多些了再来介绍吧。

[update] 刚看到&lt;a href="http://groups.google.com/group/comp.lang.python/browse_thread/thread/e93d54b945f58140/77ef3b267138d946?lnk=gst&amp;q=pypy&amp;amp;rnum=5#77ef3b267138d946"&gt; pypy 0.99 发布的声明&lt;/a&gt;，其中说到编译后的解释器性能 &lt;span class="fixed_width"  style="font-family:Courier, Monospaced;"&gt;twice the speed of the 0.9 release, overall 2-3 slower than CPython 。并且：
&lt;/span&gt;&lt;span class="fixed_width"  style="font-family:Courier, Monospaced;"&gt;It is now possible to translate the &lt;b style="color: black; background-color: rgb(255, 255, 102);"&gt;PyPy&lt;/b&gt; interpreter to run on the .NET platform .
&lt;/span&gt;&lt;span class="fixed_width"  style="font-family:Courier, Monospaced;"&gt;the JavaScript backend has evolved to a point where it can be used to write AJAX web applications with it.

WOW!
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-3022552876276823051?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/3022552876276823051/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=3022552876276823051' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3022552876276823051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3022552876276823051'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/03/pypy-pypy-python-pypy-pythonpython.html' title='pypy 介绍'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4160519999149984357</id><published>2007-03-09T21:03:00.000+08:00</published><updated>2007-03-12T17:12:59.163+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cherrypy'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>pythonic cherrypy</title><content type='html'>刚才看到这个页面：http://tools.cherrypy.org/wiki/InteractiveInterpreter，发现 cherrypy 还可以这样做，真是有点意思，正如作者所说： We think it showcases the pythonic nature of &lt;a class="wiki" href="http://tools.cherrypy.org/wiki/CherryPy"&gt;CherryPy&lt;/a&gt;.
不过那个视频使用的是cherrypy以前的版本，cherrypy3稍有不同，以下是我使用 cherrypy3 在 ipython 上实验的结果：&lt;pre&gt;Python 2.4.4 Stackless 3.1b3 060516 (#71, Jan 27 2007, 21:48:58) [MSC v.1310 32
bit (Intel)]
Type "copyright", "credits" or "license" for more information.

IPython 0.7.3 -- An enhanced Interactive Python.
?       -&gt; Introduction to IPython's features.
%magic  -&gt; Information about IPython's 'magic' % functions.
help    -&gt; Python's own help system.
object? -&gt; Details about 'object'. ?object also works, ?? prints more.

In [1]: import cherrypy

In [2]: cherrypy.config.update({
  ...: 'autoreload.on':False,
  ...: 'server.log_to_screen':False
  ...: })

In [3]: class Hello(object):
  ...:     @cherrypy.expose
  ...:     def index(self):
  ...:         return 'hello world!'
  ...:     @cherrypy.expose
  ...:     def test(self):
  ...:         yield 'test1'
  ...:         yield 'test2'
  ...:

In [4]: hello = Hello()

In [5]: cherrypy.tree.mount(hello, '/')
Out[5]: &amp;lt;cherrypy._cptree.Application object at 0x00E2C0F0&amp;gt;

In [6]: cherrypy.engine.start(blocking=False)
CherryPy Checker:
The Application mounted at '' has an empty config.


In [7]: cherrypy.server.quickstart()
[09/Mar/2007:21:01:40] HTTP Serving HTTP on http://0.0.0.0:8080/

# 注释：此时可以访问 http://localhost:8080/ 和 http://localhost:8080/test 了。

In [8]: def test2(self):
  ...:     return 'test2'
  ...:

In [9]: Hello.test2 = cherrypy.expose(test2)
# 注释：此时可以访问 http://localhost:8080/test2 了！&lt;/pre&gt;
真是方便那！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4160519999149984357?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4160519999149984357/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4160519999149984357' title='4 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4160519999149984357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4160519999149984357'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/03/pythonic-cherrypy.html' title='pythonic cherrypy'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-8236843480674435807</id><published>2007-02-07T04:29:00.000+08:00</published><updated>2007-02-07T18:57:40.484+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='orm'/><category scheme='http://www.blogger.com/atom/ns#' term='sqlalchemy'/><title type='text'>强大的 sqlalchemy</title><content type='html'>&lt;p&gt;&lt;a href="http://www.sqlalchemy.org/docs"&gt;sqlalchemy 的文档&lt;/a&gt;可谓典范，谁叫作者还开发着模板语言（&lt;a href="http://myghty.org"&gt;myghty&lt;/a&gt;、&lt;a href="http://www.makotemplate.org"&gt;mako&lt;/a&gt;）呢，呵呵。其实 sqlalchemy 的文档就是用 myghty 写的。&lt;/p&gt;&lt;p&gt;不过系统复杂了，功能多了，再好的文档也会让人迷路。最近用了用 sqlalchemy ，对这一点感受颇深，故把临时想到的几个比较常用的功能摘录如下，提纲挈领，既为自己整理一下思路，也让新手一窥 sqlalchemy 的精华。&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.sqlalchemy.org/docs/datamapping.myt#datamapping_selectrelations_eagerload"&gt;Eager Loading&lt;/a&gt;
Join，本是关系数据库中多么常见的操作，怎奈 django 的 orm 就是不支持，&lt;a href="http://www.sqlobject.org/FAQ.html#how-can-i-do-a-left-join"&gt;SQLObject 的做法&lt;/a&gt;也很不如人意。
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.sqlalchemy.org/docs/datamapping.myt#datamapping_association"&gt;Association Object&lt;/a&gt;
many-to-many 关系都是通过增加一个中间表来实现，映射到对象后，这个中间表就不需要我们再操心了，会隐式地进行处理。
不过对于多个实体两两之间多对多关系，往往另外再增加一个关联对象会更方便。
这样的例子其实也不少，比如：user-bookmark-tags、产品-元件-元件供应商(这是一次期末考试题目里面的 ;-)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.sqlalchemy.org/docs/adv_datamapping.myt#advdatamapping_properties_deferred"&gt;Deferred Column Loading&lt;/a&gt;
比如文章表里面的 body 字段通常比较大，在获取文章列表时这个字段就不必取出来了。甚至如果你有某个字段存的是文件的话，这个功能就更加重要了。
这本是个不起眼的小功能，不过上次看到 &lt;a href="http://www.javaeye.com/topic/51505"&gt;javaeye 中有一贴&lt;/a&gt;说到大名鼎鼎的 Hibernate 都对这个功能实现得这么痛苦后，我蓦然发现 sa 真的很 nb。呵呵，托了动态语言的福了吧。
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.sqlalchemy.org/docs/adv_datamapping.myt#advdatamapping_inheritance"&gt;Mapping a Class with Table Inheritance&lt;/a&gt;
如何把对象间继承关系映射到关系数据库，sqlalchemy 提供三种方式：
single table inheritance 所有子类型都放在一个表中；
concrete table inheritance 每一种子类型存在独立的表中；
multiple table inheritance 父子类型都存在独立的表中，查询的时候进行连接；
显然最后一种是冗余最少的，不过查询的时候要做一次连接操作，如何选择还是看具体情况了。
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.sqlalchemy.org/docs/adv_datamapping.myt#advdatamapping_selects"&gt;Mapping a Class against Arbitary Selects&lt;/a&gt;
将对象映射到任意的 select，其实也就是任意的 sql 子查询。
这功能太强大了，有了这个后，我们就可以骄傲地宣称，(几乎)没有什么是 sqlalchemy 做不了的了！
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.sqlalchemy.org/docs/unitofwork.myt#unitofwork_identitymap"&gt;Identity Map&lt;/a&gt;
&lt;a href="http://www.sqlalchemy.org/docs/unitofwork.myt"&gt;session &lt;/a&gt;在 sqlalchemy 中是一个非常重要的概念，session 跟踪对象的修改情况，跟踪对象之间的关联，智能判断数据库操作执行的顺序等等。
Identity Map 是 session 中一个容易让人掉入陷阱的概念，你可以把它想象成一个以数据表主键为key的cache。每次从数据库查询后，如果 sqlalchemy 发现 Identity Map 中已经有了相同主键的实例，那就不会重新生成实例了。因为如果存在多个实例会带来许多问题，比如多个实例分别修改并保存时就会产生混乱。
偶尔 Identity Map 也会产生一些意想不到的行为，比如 &lt;a href="http://www.sqlalchemy.org/trac/ticket/458"&gt;ticket 458&lt;/a&gt; ，不过理解了 Identity Map 的机理后，也就没什么问题了。
值得一提的是，&lt;a href="http://www.sqlalchemy.org/docs/adv_datamapping.myt#advdatamapping_mapperoptions"&gt;Mapper Options&lt;/a&gt; 有一个 always_refresh 参数，如果把它设为True，则对该 mapper 的任何查询操作都会自动使用从数据库中查询到的数据覆盖 Identity Map 中已有的实例，这样要是对旧实例做过什么还没保存的修改的话，就都没了。所以要慎用！
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.sqlalchemy.org/docs/unitofwork.myt#unitofwork_cascade"&gt;Cascade rules&lt;/a&gt;
最后这个也是很有用的功能，举个例子来说吧，user 和 article 有一对多的关系，现在删除一个 user，是否应该把相关的 article 也删了呢，要 article 还有其他的依赖关系呢？这些决定当然是要根据实际的需求来，而控制这些行为的方法就是通过 relation 的 cascade 参数，具体取值及其含义看文档去吧。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;总滴来说，本文只是个提纲的作用，具体还得去看文档，看示例，看unittest。&lt;/p&gt;&lt;p&gt;最后还想说两句的就是，大家之所以选择 ORM ，主要原因是逃离 SQL，然而我感觉不能掌握 SQL 是不能(很好)掌握sqlalchemy的。至少要对关系数据库的这些概念了解，理解 SQL 就是理解关系数据库。只有这样才能利用sqlalchemy将关系数据库发挥到极致！&lt;/p&gt;&lt;p&gt;使用 sqlalchemy 的好处就是不用写 sql 了，屏蔽不同dbms之间SQL语法的区别，同时又让你在需要的时候能够利用到不同 DBMS 提供的一些独特特性，让你以对象的方式管理数据库访问代码，提高代码重用性！&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-8236843480674435807?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/8236843480674435807/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=8236843480674435807' title='5 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8236843480674435807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8236843480674435807'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/02/sqlalchemy.html' title='强大的 sqlalchemy'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4805931389149232047</id><published>2007-02-07T02:50:00.000+08:00</published><updated>2007-02-07T04:28:23.751+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>Introducing Duck Typing</title><content type='html'>用 &lt;a href="http://docs.google.com/"&gt;google docs&lt;/a&gt; 写的：&lt;a class="tabcontent" id="publishedDocumentUrl" href="http://docs.google.com/View?docid=dczg8vtk_18gxgvgq&amp;revision=_published" target="_blank"&gt;http://docs.google.com/View?docid=dczg8vtk_18gxgvgq&amp;amp;revision=_published&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4805931389149232047?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://docs.google.com/View?docid=dczg8vtk_18gxgvgq' title='Introducing Duck Typing'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4805931389149232047/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4805931389149232047' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4805931389149232047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4805931389149232047'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/02/introducing-duck-typing.html' title='Introducing Duck Typing'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-5948046007034257590</id><published>2007-02-06T23:30:00.000+08:00</published><updated>2007-02-06T23:33:05.016+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>[豆瓣九点] 博客确认帖</title><content type='html'>doubanclaim8bca4134ae01e52b
白菜的页面在这里：&lt;a href="http://9.douban.com/subject/9031109/"&gt;http://9.douban.com/subject/9031109/&lt;/a&gt;
说实话，还不太会玩这个豆瓣九点，研究研究先。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-5948046007034257590?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/5948046007034257590/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=5948046007034257590' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5948046007034257590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5948046007034257590'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/02/blog-post.html' title='[豆瓣九点] 博客确认帖'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-3403435845884039226</id><published>2007-02-05T22:48:00.000+08:00</published><updated>2007-02-06T10:41:37.437+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>Deploying Django</title><content type='html'>&lt;a href="http://www.djangobook.com/"&gt;Django Book&lt;/a&gt; &lt;a href="http://www.djangobook.com/en/beta/chapter21/"&gt;Chapter 21: Deploying Django&lt;/a&gt;

肯定有许多人对这章的内容感兴趣 ;-)
这一章首先介绍了 django “Shared nothing”的设计哲学，这是django可扩展性的源泉。
随后介绍了他们比较偏爱的典型配置：
&lt;ol&gt;&lt;li&gt;操作系统用 Linux——特别是Ubuntu。&lt;/li&gt;
&lt;li&gt;web 服务器用 Apache 和 mod_python。 &lt;/li&gt;
&lt;li&gt;数据库服务器用 PostgreSQL。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;随后介绍如何配置 apache、mod_python 和你的django应用。教你如何在一个apache上部署多个django应用，如何把 mod_python 用做开发服务器，如何处理静态文件，如何处理错误等等。&lt;/p&gt;&lt;p&gt;随后还介绍了使用 fastcgi 方式部署 django 应用，不过这部分我不太感兴趣，就直接跳过去了。&lt;/p&gt;&lt;p&gt;然后，便是万众期待的 Scaling 了！一图胜千言： &lt;a href="http://media.djangobook.com/content/chapter21/scaling-1.png"&gt;&lt;img style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="单服务器" src="http://media.djangobook.com/content/chapter21/scaling-1.png" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://media.djangobook.com/content/chapter21/scaling-2.png"&gt;&lt;img style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="分离数据库服务器" src="http://media.djangobook.com/content/chapter21/scaling-2.png" border="0" /&gt;&lt;/a&gt;
&lt;a href="http://media.djangobook.com/content/chapter21/scaling-3.png"&gt;&lt;img style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="单独处理静态文件" src="http://media.djangobook.com/content/chapter21/scaling-3.png" border="0" /&gt;&lt;/a&gt;

&lt;a href="http://media.djangobook.com/content/chapter21/scaling-4.png"&gt;&lt;img style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="负载均衡" src="http://media.djangobook.com/content/chapter21/scaling-4.png" border="0" /&gt;&lt;/a&gt;

&lt;a href="http://media.djangobook.com/content/chapter21/scaling-5.png"&gt;&lt;img style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="负载均衡集群+dns轮询" src="http://media.djangobook.com/content/chapter21/scaling-5.png" border="0" /&gt;&lt;/a&gt;

最后还有很重要的一部分，调优，不过说来说去也还是那么几条了： &lt;/p&gt;&lt;ol&gt;&lt;li&gt;多买内存&lt;/li&gt;&lt;li&gt;关闭 Keep-Alive ，不过这一点只是大部分情况而已，具体还得看你网站提供的功能。&lt;/li&gt;&lt;li&gt;使用 &lt;a href="http://www.djangobook.com/en/beta/chapter14/"&gt;memcached&lt;/a&gt;&lt;/li&gt;&lt;li&gt;积极参加各个开源产品的社区&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;ps: 有些日子没写blog了，刚考完，心一下就野了，什么计划都忘了，写一篇来凑凑数目 ;-) &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-3403435845884039226?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/3403435845884039226/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=3403435845884039226' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3403435845884039226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3403435845884039226'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/02/deploying-django.html' title='Deploying Django'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2692243988855739598</id><published>2007-01-27T18:35:00.000+08:00</published><updated>2007-01-27T19:42:36.099+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>使用 python 模拟 ruby 的 open class</title><content type='html'>老早就写了这些代码，但一直懒得为它写篇博客，我觉得我永远也无法理解为什么会有人发明这种奇怪的东西。
不过终于还是决定写一篇吧，多一点有意思的代码也许能吸引更多人对 python 的兴趣呢，呵呵。虽然我对 ruby 的这个东西有许多贬义词想说，不过想想既然有人用，也就应该有其理由吧。
且看代码：
&lt;div style="background:#000000;color:#cccccc"&gt;&lt;pre&gt;
&lt;font color="#ffff00"&gt;def&lt;/font&gt; &lt;font color="#40ffff"&gt;update&lt;/font&gt;( klass, bases, attrs ):
    &lt;font color="#ffff00"&gt;for&lt;/font&gt; k,v &lt;font color="#ffff00"&gt;in&lt;/font&gt; attrs.items():
        &lt;font color="#ffff00"&gt;if&lt;/font&gt; &lt;font color="#ffff00"&gt;not&lt;/font&gt; k.startswith(&lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;&lt;font color="#ffa0a0"&gt;__&lt;/font&gt;&lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;) &lt;font color="#ffff00"&gt;or&lt;/font&gt; &lt;font color="#ffff00"&gt;not&lt;/font&gt; k.endswith(&lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;&lt;font color="#ffa0a0"&gt;__&lt;/font&gt;&lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;):
            setattr(klass, k, v)
    &lt;font color="#ffff00"&gt;if&lt;/font&gt; bases:
        klass.__bases__ = bases
    &lt;font color="#ffff00"&gt;return&lt;/font&gt; klass

&lt;font color="#ffff00"&gt;class&lt;/font&gt; &lt;font color="#40ffff"&gt;Meta&lt;/font&gt;(type):
    &lt;font color="#ffff00"&gt;def&lt;/font&gt; &lt;font color="#40ffff"&gt;__new__&lt;/font&gt;(cls, klass, bases, attrs):
        &lt;font color="#ffff00"&gt;try&lt;/font&gt;:
            &lt;font color="#ffff00"&gt;return&lt;/font&gt; update( globals()[klass], bases, attrs )
        &lt;font color="#ffff00"&gt;except&lt;/font&gt; KeyError:
            &lt;font color="#ffff00"&gt;return&lt;/font&gt; type.__new__(cls, klass, bases, attrs)

&lt;font color="#80a0ff"&gt;# test&lt;/font&gt;
__metaclass__ = Meta

&lt;font color="#80a0ff"&gt;# test simple&lt;/font&gt;
&lt;font color="#ffff00"&gt;class&lt;/font&gt; &lt;font color="#40ffff"&gt;A&lt;/font&gt;:
    &lt;font color="#ffff00"&gt;def&lt;/font&gt; &lt;font color="#40ffff"&gt;say&lt;/font&gt;(self):
        &lt;font color="#ffff00"&gt;print&lt;/font&gt; &lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;&lt;font color="#ffa0a0"&gt;hi&lt;/font&gt;&lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;

a = A()
a.say() &lt;font color="#80a0ff"&gt;# hi&lt;/font&gt;

&lt;font color="#ffff00"&gt;class&lt;/font&gt; &lt;font color="#40ffff"&gt;A&lt;/font&gt;:
    &lt;font color="#ffff00"&gt;def&lt;/font&gt; &lt;font color="#40ffff"&gt;say&lt;/font&gt;(self):
        &lt;font color="#ffff00"&gt;print&lt;/font&gt; &lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;&lt;font color="#ffa0a0"&gt;ho&lt;/font&gt;&lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;
    &lt;font color="#ffff00"&gt;def&lt;/font&gt; &lt;font color="#40ffff"&gt;new_func&lt;/font&gt;(self):
        &lt;font color="#ffff00"&gt;print&lt;/font&gt; &lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;&lt;font color="#ffa0a0"&gt;new&lt;/font&gt;&lt;span style="background-color: #000000"&gt;&lt;font color="#cccccc"&gt;'&lt;/font&gt;&lt;/span&gt;

a.say() &lt;font color="#80a0ff"&gt;# ho&lt;/font&gt;
a.new_func() &lt;font color="#80a0ff"&gt;# new&lt;/font&gt;

&lt;font color="#80a0ff"&gt;# test inherit&lt;/font&gt;
&lt;font color="#80a0ff"&gt;#del A&lt;/font&gt;
&lt;font color="#80a0ff"&gt;#class A:&lt;/font&gt;
    &lt;font color="#80a0ff"&gt;#def say(self):&lt;/font&gt;
        &lt;font color="#80a0ff"&gt;#print 'hi'&lt;/font&gt;

&lt;font color="#80a0ff"&gt;#a = A()&lt;/font&gt;
&lt;font color="#80a0ff"&gt;#a.say() # hi&lt;/font&gt;

&lt;font color="#80a0ff"&gt;#class B:&lt;/font&gt;
    &lt;font color="#80a0ff"&gt;#def say(self):&lt;/font&gt;
        &lt;font color="#80a0ff"&gt;#print 'ho'&lt;/font&gt;

&lt;font color="#80a0ff"&gt;#class A(B):&lt;/font&gt;
    &lt;font color="#80a0ff"&gt;#def say(self):&lt;/font&gt;
        &lt;font color="#80a0ff"&gt;#super(A, self).say()&lt;/font&gt;

&lt;font color="#80a0ff"&gt;#a.say() # ho&lt;/font&gt;
&lt;/pre&gt;&lt;/div&gt;
update: 很遗憾，测试发现 new style class 貌似还有个&lt;a href="http://mail.python.org/pipermail/python-bugs-list/2005-March/028024.html"&gt; bug &lt;/a&gt;。所以把后面部分注释了先，不知道 python2.5 怎么样。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2692243988855739598?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2692243988855739598/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2692243988855739598' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2692243988855739598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2692243988855739598'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/python-ruby-open-class.html' title='使用 python 模拟 ruby 的 open class'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2705639497692975737</id><published>2007-01-26T12:36:00.000+08:00</published><updated>2007-01-26T12:44:26.299+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>用 jquery 加了点 js 效果</title><content type='html'>代码超简单：
&lt;pre&gt;
$(function(){
  $(".box h2").css('cursor', 'pointer');
  $(".box h2").click(
    function(e){
      $(this).next().toggle();
    }
  ).click();
  $(".post-title").css('cursor', 'pointer');
  $(".post-title").click(
    function(e){
      $(this).next().next().toggle();
    }
  ).click();
  $('#readerpublishermodule0 h3').css('cursor', 'pointer');
  $('#readerpublishermodule0 h3').click(
    function(e){
      $(this).next().toggle();
    }
  ).click();
})
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2705639497692975737?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2705639497692975737/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2705639497692975737' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2705639497692975737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2705639497692975737'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/jquery-js.html' title='用 jquery 加了点 js 效果'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-5476869432422723585</id><published>2007-01-24T23:22:00.000+08:00</published><updated>2007-01-24T23:35:42.238+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>ie sucks</title><content type='html'>偶然的机会，在 ie 下看了一下今天的成果，才发现右边的 widgets 周围没有圆角，郁闷。
只能是建议大家用 firefox 看了 ;-)
另外由于在 ie 下过长的单词会把 div 撑开，又不想用固定宽度，所以没办法，只好动用了 word-break: break-all;  也就是在需要换行的地方会把一个单词拆开，看的时候确实很不爽，不过没办法，在 firefox 下看就好了。
要是你知道有什么好的 ie 下的解决方法，不妨告之，先谢了 ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-5476869432422723585?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/5476869432422723585/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=5476869432422723585' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5476869432422723585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5476869432422723585'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/ie-sucks.html' title='ie sucks'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-7259186970552756959</id><published>2007-01-24T18:20:00.000+08:00</published><updated>2007-01-24T18:51:55.976+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>added google reader clip</title><content type='html'>用 google reader 这么久，才发现它有&lt;a href="http://www.google.com/help/reader/sharing.html#clip"&gt;这功能&lt;/a&gt;，看右边的 Starred Google Reader，那是我所有加过星的条目。
另外看 google reader clip 的 css 效果不错，赶紧抄过来，现在右边全是这风格了，爽 ;-)
是不是好像和其他部分有点不太协调，不过要是全部搞成绿色的风格又觉得不太好，不管怎么说比以前还是好多了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-7259186970552756959?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/7259186970552756959/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=7259186970552756959' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7259186970552756959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7259186970552756959'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/added-google-reader-clip.html' title='added google reader clip'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-1862528405371014465</id><published>2007-01-22T13:17:00.000+08:00</published><updated>2007-01-22T13:58:30.997+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='genshi'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>intergrate genshi with django</title><content type='html'>&lt;p&gt;写了个程序，用来在 &lt;a href="http://www.djangoproject.com/"&gt;django&lt;/a&gt; 中使用 &lt;a href="http://genshi.edgewall.org/"&gt;genshi 模版&lt;/a&gt;：
http://huangyilib.googlecode.com/svn/trunk/mashi_django/genshi_django.py
&lt;/p&gt;&lt;ol&gt;&lt;li&gt;配置文件中通过元组 GENSHI_TEMPLATE_DIRS 指定模版存放路径；&lt;/li&gt;&lt;li&gt;会自动到已安装的 app 下的 genshi_templates 目录找模版文件；
&lt;/li&gt;&lt;li&gt;DEBUG 为 True 时，启动模版的 auto_reload，否则关闭；
&lt;/li&gt;&lt;/ol&gt;genshi 是个好模版，希望大家会喜欢。
加上 genshi_django 后，就是名副其实的 mashi_django 了。
发现什么问题，记得告诉我 ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-1862528405371014465?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/1862528405371014465/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=1862528405371014465' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1862528405371014465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/1862528405371014465'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/intergrate-genshi-with-django.html' title='intergrate genshi with django'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-8109551435695286310</id><published>2007-01-22T11:18:00.001+08:00</published><updated>2007-01-22T11:39:28.244+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mako'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>intergrate mako with django</title><content type='html'>写了个程序，用来在 &lt;a href="http://www.djangoproject.com/"&gt;django&lt;/a&gt; 中使用 &lt;a href="http://www.makotemplates.org/"&gt;mako 模版&lt;/a&gt;：
http://huangyilib.googlecode.com/svn/trunk/mashi_django/mako_django.py
&lt;ol&gt;&lt;li&gt;配置文件中通过元组 MAKO_TEMPLATE_DIRS 指定模版存放路径；
&lt;/li&gt;&lt;li&gt;另外自动到所有安装过的 app 下的 mako_templates 目录下找模版；&lt;/li&gt;&lt;li&gt;模版编译后的 python 代码默认和相应模版文件放在一个目录下面，然后在模版文件的文件名后面加 ‘.py’，你可以通过配置 MAKO_MODULENAME_CALLABLE callable 对象来定义你自己的 module 文件名生成方式，这个功能来源于 &lt;a href="http://www.makotemplates.org/trac/ticket/14"&gt;mako ticket 14&lt;/a&gt; ，好像这是我第一个 ticket ;-)
&lt;/li&gt;&lt;li&gt;如果在配置文件中指定 MAKO_MODULE_DIR 的话，所有编译后的 python 代码都会存到这一个目录里来。&lt;/li&gt;&lt;/ol&gt;mako 是个好模版，希望大家会喜欢。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-8109551435695286310?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/8109551435695286310/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=8109551435695286310' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8109551435695286310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8109551435695286310'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/intergrate-mako-with-django.html' title='intergrate mako with django'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-8186984138865757192</id><published>2007-01-22T11:06:00.000+08:00</published><updated>2007-01-22T11:21:28.390+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>[news] django moving towards 1.0</title><content type='html'>都是些好消息 ;-)
&lt;blockquote&gt;&lt;p&gt;There’s a lot of different things that “1.0” can mean.  In many cases the label refers to some arbitrary measure of code maturity, but that’s usually
very indistinct.  There’s quite a bit of “1.0” software that’s far less robust
than Django was at day 1; we could have called it “1.0” then and gotten away
with it, I think.&lt;/p&gt;  &lt;p&gt;In the context of Django, though, 1.0 has always meant something more concrete: forwards compatibility.  Once we tag something as 1.0, we’re
committing to maintaining &lt;span class="caps"&gt;API &lt;/span&gt;stability as described in the contributing &lt;span class="caps"&gt;HOWTO&lt;/span&gt;
(http://www.djangoproject.com/documentation/contributing/#official-releases).&lt;/p&gt;&lt;/blockquote&gt;&lt;div style="text-align: right;"&gt;——摘自 &lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/592d5b8f9593ea38/0c19a63a1e4648e5"&gt;邮件列表&lt;/a&gt;
&lt;div style="text-align: left;"&gt;
&lt;a href="http://code.djangoproject.com/wiki/VersionOneFeatures"&gt;这个&lt;/a&gt; 页面列出的是很可能会在 1.0 中出现的特性，还在讨论中。
最近 django 还定了一套&lt;a href="http://www.djangoproject.com/documentation/contributing/#ticket-triage"&gt;新的 ticket 管理流程&lt;/a&gt; ，并且组织了一个 4 人的 ticket 管理队伍：
&lt;blockquote&gt;The last, most important, piece of the puzzle, is that we now have official ticket managers, a group of volunteers who work together to manage ticket metadata and otherwise streamline the process. Although anyone can -- and is encouraged to -- help out keeping tickets organized, these folks have volunteered to take ownership of the ticket tracker in the long term. &lt;em&gt;Please welcome Chris Beaven (SmileyChris), Simon Greenhill, Michael Radziej and Gary Wilson!&lt;/em&gt;&lt;/blockquote&gt;
另外现在还有了一名&lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/9cc70167a6af4a03/6c6a5fdabcf6f3c6"&gt;专门的 release 管理员&lt;/a&gt; ，并且最近发布了 &lt;a href="http://www.djangoproject.com/weblog/2007/jan/21/0951/"&gt;django 0.95.1&lt;/a&gt;。
&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-8186984138865757192?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/8186984138865757192/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=8186984138865757192' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8186984138865757192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8186984138865757192'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/news-django-moving-towards-10.html' title='[news] django moving towards 1.0'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-7291302503320306739</id><published>2007-01-19T22:05:00.000+08:00</published><updated>2007-01-20T19:19:12.332+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>do it runtime</title><content type='html'>&lt;div class="post-body"&gt;   &lt;p&gt;     第一次从静态语言到动态语言的人肯定在思维上需要一个比较大的跳跃，主要是许多静态语言中编译器干的事情到动态语言中后，或是不存在了，或是需要在运行时进行。
    典型的例子包括：类型检查，重载，访问控制，常量。（暂时就想到这几个，还有一些代码生成的技术像define、template我们就不提了）
   
    &lt;span style="font-weight: bold;"&gt;1、类型检查&lt;/span&gt;。   &lt;/p&gt;   &lt;p&gt;     对于类型检查我想大部分人倾向于可选地进行，毕竟动态语言不是静态语言，duck typing还是给动态语言带来了巨大的灵活性的。
    python对类型检查的实现只搜到这么一个：&lt;a href="http://oakwinter.com/code/typecheck/" target="blank_" title="http://oakwinter.com/code/typecheck/"&gt;http://oakwinter.com/code/typecheck/&lt;/a&gt;     ，粗略看了一下文档，似乎已经相当完善了。   &lt;/p&gt;   &lt;p&gt;     而我自己出于学习的目的也写了个超级简单的：&lt;a href="http://huangyilib.googlecode.com/svn/trunk/typecheck.py"&gt;http://huangyilib.googlecode.com/svn/trunk/typecheck.py&lt;/a&gt;，这个代码做为学习的材料也还是不错的。而且写完这个我自己也感觉对python的函数参数的处理机制有了更完善的认识。   &lt;/p&gt;   &lt;p&gt;     给大家看下测试输出先，从中大家可以一窥其功能：
  &lt;/p&gt;   &lt;pre&gt;call temp(1, 'hello')
call temp(1, 'hello', c=4)
call temp(1, c=4, b='hello')
call temp(a=1, c=4, b='hello')

call temp(1, 2)
TypecheckError : the value 2 of argument 'b' is not type &amp;lt;type 'str'&gt;

call temp(1, 'hello', c='hello')
TypecheckError : the value 'hello' of argument 'c' is not type &amp;lt;type 'int'&gt;

call temp(1, c=1)
TypeError : temp() takes at least 2 non-keyword arguments (1 given)

temp() has not this keyword argument 'd'

the default value 1 of argument 'c' is not type &amp;lt;type 'str'&gt;

temp() has not so meny arguments 4

test success
&lt;/pre&gt;   另外还值得一提的就是，python3000 中的   &lt;a href="http://www.python.org/dev/peps/pep-3107/"&gt;pep-3107&lt;/a&gt;   提议一种给函数增加元数据的方式：   &lt;pre&gt;def foo(a: 'x', b: 5 + 6, c: list) -&gt; max(2, 9):&lt;/pre&gt;   不过这个东西并非为类型检查而生的，类型检查只是它潜在的一个应用而已，它本身只负责存储元数据，具体元数据是啥和元数据怎么用由第三方库决定，其他潜在应用包括：文档生成、rpc、与静态语言之间的交互等等。
 
  &lt;span style="font-weight: bold;"&gt;2、重载&lt;/span&gt;。
  关于重载首先要说的一点是 python   中灵活的参数传递机制可以减少大量使用重载的场景，不过剩下那些基于实参类型的重载python仍然无能为力。而幸运的是我们有&lt;a href="http://peak.telecommunity.com/"&gt;PEAK&lt;/a&gt;，其中有个&lt;a href="http://www-128.ibm.com/developerworks/library/l-cppeak2/"&gt;RuleDispatch&lt;/a&gt;便是干这事的，而Guido这篇博客：&lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=155123"&gt;Python   3000 - Adaptation or Generic   Functions?&lt;/a&gt;说到要把这东西加到python3k中去，也掀起一阵热烈的讨论，只不过在这里我们不叫它重载，叫它Generic   Function，但实质是一样的，就是根据传入的不同类型的实参调用合适的函数，比如：
  &lt;pre&gt;&gt;&gt;&gt; class PrettyPrinter:
...     @generic
...     def pformat(self, object):
...         """Return the pretty string representation of object"""
...         return repr(object)
...
&gt;&gt;&gt; @PrettyPrinter.pformat.when(object=list)
... def pformat_list(self, object):
...     s = '['
...     for item in object:
...         s += (' '*self.indent) + self.pformat(item) + ',\n'
...     return s + (' '*self.indent) + ']'
...&lt;/pre&gt;   然后当调用
  &lt;pre&gt;PrettyPrinter().pformat([1,2,3])&lt;/pre&gt;   时，实际调用到的函数其实是下面那个pformat_list 。
 
  &lt;span style="font-weight: bold;"&gt;3、访问控制&lt;/span&gt;。
  python是不对属性做强制性的访问控制的，而是依赖于约定，一方面是坚持相信程序员的信条，另一方面我觉的是确实不好实现，程序中对属性的访问是如此的常见，如果在运行时进行检查，效率上损失太大，得不偿失。
ruby 是进行强制性访问控制的，对象所有属性都只能通过方法暴露，然后对方法进行访问控制，也就是说，每一次你访问一个对象暴露出来的属性，实际上你都是通过调 用一个方法，而调用方法之前访问控制机制还要先判断该调用地点是否可以调用该方法！所以说ruby慢不光是因为它的实现慢，它的语言设计本身就慢！(如对 ruby 有误解，欢迎指出)
另外还有一个原因是ruby中函数不是第一型对象，可以调用函数但不能获取函数对象本身。python中函数是第一型对象，函数对象本身可以当参数传递， 而且class中的方法其实只是普通的函数而已，完全可以把一个外部定义的函数对象交给class给它当方法用，这带来巨大的灵活性，但也使得这种情况下 对方法实现访问控制是根本不可能！你想啊：在class外部定义的函数自然是不能访问 class 的私有属性的，但是当它作为class的方法后就突然变得可以了吗？
 
  &lt;span style="font-weight: bold;"&gt;4、常量&lt;/span&gt;。
  常量换句话说就是只读的变量，在静态语言中它也是通过编译器在编译期间对代码进行约束。那么在动态语言中又该如何来实现呢？
  这个问题最近在两个邮件里都提出来：&lt;a href="http://python.cn/pipermail/python-chinese/2006-December/033716.html"&gt;请教：在python中要实现类似define的功能怎么办？&lt;/a&gt;，&lt;a href="http://python.cn/pipermail/python-chinese/2007-January/034313.html"&gt;怎么不用property来实现只读属性？&lt;/a&gt;。
  最常见的方法莫过于使用property实现只读的属性：   &lt;pre&gt;&gt;&gt;&gt; class Person(object):
...     def __init__(self, name):
...         self.__name = name
...     @property  # 只读属性
...     def name(self):
...         return self.__name
...
&gt;&gt;&gt; p = Person('huangyi')
&gt;&gt;&gt; p.name
'huangyi'
&gt;&gt;&gt; p.name = 'another'
Traceback (most recent call last):
  File "&amp;lt;stdin&gt;", line 1, in ?
AttributeError: can't set attribute&lt;/pre&gt;   我记得我当时在邮件的讨论中就很详细得总结了一下各种做法，但是刚才去搜的时候，竟然发现它不见了！难道出现了幻觉？估计是gmail当时出了点问题。不过幸好我在另一个地方存了一份;-)   顺便把它改成了doctest的形式。
  下面直接粘贴一份语法加亮过的版本，你也可以在这里找到&lt;a href="http://huangyilib.googlecode.com/svn/trunk/const.py"&gt;代码&lt;/a&gt;和&lt;a href="http://huangyilib.googlecode.com/svn/trunk/const.html"&gt;语法加亮的html&lt;/a&gt;：
  &lt;div style="background: rgb(0, 0, 0) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(204, 204, 204);"&gt;     &lt;pre&gt;&lt;span style="color:#80a0ff;"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;感觉楼主的这篇和上次用 python 实现 define 的那篇帖子，想说的都是&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;一个东西，就是静态语言中的 const，第一次初始化后不能修改的东西。&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;说起来，python 对象中其实是有这样的东西，就是 imutable object 。&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;不过常量针对的是名字而非对象，所以在 python 中常量的准确定义应该&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;是：在第一次绑定后不能重新绑定其他对象的名字。&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;遗憾的是 python 中没有这样的东西。&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;其实和类型检查、访问控制等东西一样，静态语言中常量是通过编译器在&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;编译时进行检查，而 python 就算实现那也只能是在运行时进行计算，势&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;必损耗性能，我想这也是 python 中没有这样的东西的原因。&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;但是正如 python 中的访问控制是通过对名字的约定来做的一样，其实常&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;量也比较适合这样做。&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;如果实在要用动态语言模拟 const，那么关键在于对名字的绑定进行控制。&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;下面总结一下各种做法：&lt;/span&gt;
&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;

&lt;span style="color:#ffff00;"&gt;def&lt;/span&gt; &lt;span style="color:#40ffff;"&gt;a_const_value&lt;/span&gt;():
   &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    方法1是通过使用函数替代对名字的直接访问，好像是比较傻的方法。&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    不过 ruby 中函数调用可以省略括号就有点像了&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; a_const_value()&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    'const'&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &lt;/span&gt;&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;
   &lt;span style="color:#ffff00;"&gt;return&lt;/span&gt; &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#ffa0a0;"&gt;const&lt;/span&gt;&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span style="color:#ffff00;"&gt;class&lt;/span&gt; &lt;span style="color:#40ffff;"&gt;Temp&lt;/span&gt;(object):
   &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    class 中通过 property 可以做得更漂亮：&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t = Temp()&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.a_const_value&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    'const'&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.a_const_value = 'another value'&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    Traceback (most recent call last):&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;        ...&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    AttributeError: can't set attribute&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &lt;/span&gt;&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;
   &lt;span style="color:#ff80ff;"&gt;@&lt;/span&gt;&lt;span style="color:#40ffff;"&gt;property&lt;/span&gt;
   &lt;span style="color:#ffff00;"&gt;def&lt;/span&gt; &lt;span style="color:#40ffff;"&gt;a_const_value&lt;/span&gt;(self):
       &lt;span style="color:#ffff00;"&gt;return&lt;/span&gt; &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#ffa0a0;"&gt;const&lt;/span&gt;&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span style="color:#ffff00;"&gt;class&lt;/span&gt; &lt;span style="color:#40ffff;"&gt;ConstError&lt;/span&gt;(Exception):
   &lt;span style="color:#ffff00;"&gt;pass&lt;/span&gt;

&lt;span style="color:#ffff00;"&gt;class&lt;/span&gt; &lt;span style="color:#40ffff;"&gt;Consts&lt;/span&gt;(object):
   &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    方法2是将常量名字放入一个 class 中统一进行管理：&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; consts = Consts()&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; consts.a = 2&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; consts.a&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    2&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; consts.a = 3&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    Traceback (most recent call last):&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;        ...&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    ConstError: can't rebind const name&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;    不过需要注意的是，仍然可以通过 __dict__ 直接访问常量：&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; consts.__dict__['a'] = 3&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; consts.a&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    3&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &lt;/span&gt;&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;
   &lt;span style="color:#ffff00;"&gt;def&lt;/span&gt; &lt;span style="color:#40ffff;"&gt;__setattr__&lt;/span&gt;(self, name, value):
       &lt;span style="color:#ffff00;"&gt;if&lt;/span&gt; name &lt;span style="color:#ffff00;"&gt;in&lt;/span&gt; self.__dict__:
           &lt;span style="color:#ffff00;"&gt;raise&lt;/span&gt; ConstError, &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#ffa0a0;"&gt;can&lt;/span&gt;&lt;span style="color:#ffa500;"&gt;\'&lt;/span&gt;&lt;span style="color:#ffa0a0;"&gt;t rebind const name&lt;/span&gt;&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;
       &lt;span style="color:#ffff00;"&gt;else&lt;/span&gt;:
           self.__dict__[name] = value

&lt;span style="color:#ffff00;"&gt;class&lt;/span&gt; &lt;span style="color:#40ffff;"&gt;ConstBase&lt;/span&gt;(object):
   &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    或者让 class 自己指定那些是常量：&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; class Temp(ConstBase):&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    ...     __consts__ = {'a':None, 'b':2}&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    ...     def __init__(self, a):&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    ...         self.a = a&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    ...&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t = Temp(2)&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.a&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    2&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.b&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    2&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.a = 3&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    Traceback (most recent call last):&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;        ...&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    ConstError: can't rebind const name&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.b = 3&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    Traceback (most recent call last):&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;        ...&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    ConstError: can't rebind const name&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.c = 5&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.c&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    5&lt;/span&gt;

&lt;span style="color:#ffa0a0;"&gt;    使用这种方式，也可以直接通过 __dict__ 对常量进行修改：&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.__dict__['a']= 3&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &gt;&gt;&gt; t.a&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    3&lt;/span&gt;
&lt;span style="color:#ffa0a0;"&gt;    &lt;/span&gt;&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'''&lt;/span&gt;&lt;/span&gt;
   __consts__ = {}
   &lt;span style="color:#ffff00;"&gt;def&lt;/span&gt; &lt;span style="color:#40ffff;"&gt;__setattr__&lt;/span&gt;(self, name, value):
       &lt;span style="color:#ffff00;"&gt;if&lt;/span&gt; name &lt;span style="color:#ffff00;"&gt;in&lt;/span&gt; self.__consts__:
           &lt;span style="color:#ffff00;"&gt;if&lt;/span&gt; self.__consts__[name] == None:
               self.__consts__[name] = value
           &lt;span style="color:#ffff00;"&gt;else&lt;/span&gt;:
               &lt;span style="color:#ffff00;"&gt;raise&lt;/span&gt; ConstError, &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#ffa0a0;"&gt;can&lt;/span&gt;&lt;span style="color:#ffa500;"&gt;\'&lt;/span&gt;&lt;span style="color:#ffa0a0;"&gt;t rebind const name&lt;/span&gt;&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;
       &lt;span style="color:#ffff00;"&gt;else&lt;/span&gt;:
           super(ConstBase, self).__setattr__(name, value)
   &lt;span style="color:#ffff00;"&gt;def&lt;/span&gt; &lt;span style="color:#40ffff;"&gt;__getattr__&lt;/span&gt;(self, name):
       &lt;span style="color:#ffff00;"&gt;if&lt;/span&gt; name &lt;span style="color:#ffff00;"&gt;in&lt;/span&gt; self.__consts__:
           &lt;span style="color:#ffff00;"&gt;return&lt;/span&gt; self.__consts__[name]
       &lt;span style="color:#ffff00;"&gt;else&lt;/span&gt;:
           &lt;span style="color:#ffff00;"&gt;return&lt;/span&gt; super(ConstBase, self).__getattr__(name, value)

&lt;span style="color:#ffff00;"&gt;if&lt;/span&gt; __name__ == &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#ffa0a0;"&gt;__main__&lt;/span&gt;&lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color:#cccccc;"&gt;'&lt;/span&gt;&lt;/span&gt;:
   &lt;span style="color:#ff80ff;"&gt;import&lt;/span&gt; doctest
   doctest.testmod()
&lt;/pre&gt;   &lt;/div&gt; &lt;/div&gt; &lt;span class="post-author"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-7291302503320306739?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/7291302503320306739/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=7291302503320306739' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7291302503320306739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7291302503320306739'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/do-it-runtime.html' title='do it runtime'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4213524858864822245</id><published>2007-01-17T22:04:00.000+08:00</published><updated>2007-01-17T22:09:13.083+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>new blog template</title><content type='html'>哈哈，新年新模版！
从 &lt;a href="http://www.oswd.org"&gt;oswd&lt;/a&gt; 随便找了个没图片的模版改了改，open source 的东西就是好哇！
越发感觉到 google 的 blog 做得专业，还专门给模版整了个模版语言，nb！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4213524858864822245?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4213524858864822245/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4213524858864822245' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4213524858864822245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4213524858864822245'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/new-blog-template.html' title='new blog template'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-617567281302548704</id><published>2007-01-16T11:00:00.000+08:00</published><updated>2007-01-27T01:23:14.427+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='PEAK'/><title type='text'>Build extensible application with egg</title><content type='html'>在 python 社区中 &lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;egg&lt;/a&gt; 已经是一种广为人知的格式了。众所周知对于 python 来说 &lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;egg&lt;/a&gt; 是一种用来生小蛇的东西，小蛇自然就是 python 软件包了(纯属瞎扯 ;-)。

简单地说，&lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;egg&lt;/a&gt; 之于 python 正如 jar 之于 java。是一种软件包打包的格式——要注意的是这个格式并非文件格式，实际上 egg 可以使用多种文件格式，当然最常用的还是 zip ——这里的格式主要是指组织其中包含的文件的格式。

只是把软件包打包成 zip 格式的话，那就不足为奇了。&lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;egg&lt;/a&gt; 显然不光是用来干这个的，&lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;egg&lt;/a&gt; 最重要的作用是给软件包增加元数据！而元数据具体包含些什么内容和它的格式几乎没有什么强制的定义，这给基于 &lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;egg&lt;/a&gt; 的应用提供了大量发挥的空间。

比如做&lt;a href="http://cheeseshop.python.org/pypi/"&gt;PyPi&lt;/a&gt;软件包注册查找的机制、&lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs#declaring-dependencies"&gt;处理软件包之间的依赖关系&lt;/a&gt;等等，比如 &lt;a href="http://peak.telecommunity.com/DevCenter/setuptools"&gt;setuptools&lt;/a&gt; 就是定义了一些元数据的格式，然后软件包的开发者只需按照这种格式把相关信息写进 setup.py ，setuptools 读取到这些信息后就可以帮你干这些事情了。

除此以外，我觉的 egg 最有意思的应用莫过于做为插件系统了。相信把 egg 做为插件系统来用的几个框架大家应该都了解，像 &lt;a href="http://www.turbogears.org/"&gt;turbogears&lt;/a&gt; 的&lt;a href="http://www.turbogears.org/docs/plugins/template.html"&gt;模版插件系统&lt;/a&gt;，&lt;a href="http://pythonpaste.org/"&gt;paste&lt;/a&gt; 的&lt;a href="http://pythonpaste.org/script/developer.html#templates"&gt;可扩展的项目模版&lt;/a&gt;，还有 &lt;a href="http://trac.edgewall.org/"&gt;trac&lt;/a&gt; 的&lt;a href="http://trac.edgewall.org/wiki/TracDev/PluginDevelopment"&gt;插件系统&lt;/a&gt;等。

一个插件系统莫过于这么几个步骤：框架首先定义一个/些插件的接口；第三方插件替你实现这个/些接口；插件注册；框架发现并使用插件。而 &lt;a href="http://peak.telecommunity.com/DevCenter/setuptools"&gt;setuptools&lt;/a&gt; 和 &lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;egg&lt;/a&gt; 便可以帮你完成后面两个最麻烦的步骤：注册和发现。

先来看个效果，以下代码能帮你找到你安装过的所有 paste 项目模版(下面用到的 &lt;a href="http://peak.telecommunity.com/DevCenter/PkgResources"&gt;pkg_resources&lt;/a&gt; 模块安装 &lt;a href="http://peak.telecommunity.com/DevCenter/setuptools"&gt;setuptools &lt;/a&gt;后就有)：
&lt;pre&gt;&lt;code&gt;
In [3]: import pkg_resources

In [4]: pts = list( pkg_resources.iter_entry_points('paste.paster_create_templat
e') )

In [5]: pts
Out[5]:
[EntryPoint.parse('pylons_minimal = pylons.util:MinimalPylonsTemplate'),
EntryPoint.parse('pylons = pylons.util:PylonsTemplate'),
EntryPoint.parse('myghty_modulecomponents = myghty.paste.templates:MCTemplate')
,
EntryPoint.parse('myghty_simple = myghty.paste.templates:SimpleTemplate'),
EntryPoint.parse('myghty_routes = myghty.paste.templates:RoutesTemplate'),
EntryPoint.parse('basic_package = paste.script.templates:BasicPackage'),
EntryPoint.parse('paste_deploy = paste.deploy.paster_templates:PasteDeploy'),
EntryPoint.parse('toscawidgets = toscawidgets.util:ToscaWidgetsTemplate')]

In [6]: pts[0].name
Out[6]: 'pylons_minimal'

In [7]: pts[0].module_name
Out[7]: 'pylons.util'

In [8]: pts[0].attrs
Out[8]: ('MinimalPylonsTemplate',)

In [9]: pts[0].load()
Out[9]: &amp;lt;class 'pylons.util.MinimalPylonsTemplate'&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
可以看到最后一步我们就在运行时加载了那个实现了 paste 所定义接口的类。

注册的过程就更简单了，把 entry_points 元数据往 setup.py 里一填，setup.py install 一装就 ok 了。

这个过程中使用到的元数据叫做 entry_points ，entry_points 的格式很简单，其实就是 ini 的格式，一个 group 对应多个 name，
&lt;pre&gt;&lt;code&gt;
[group_name]
...
...
&lt;/code&gt;&lt;/pre&gt;pkg_resource 中将 name 的格式定义为： &lt;pre class="literal-block"&gt;name = some.module:some.attr [extra1,extra2]&lt;/pre&gt;  而 group_name 则由框架定义，其实就是对应一个接口，插件只需要将自己实现了这个接口的类列在下面，然后 setup.py install 一装，就 ok 了。

现在 setuptools 和 egg 已经帮你干完了这些麻烦事，你还需要做的事情就只剩下：设计你的系统，定义你的插件接口。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-617567281302548704?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/617567281302548704/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=617567281302548704' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/617567281302548704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/617567281302548704'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/build-extensible-application-with-egg.html' title='Build extensible application with egg'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-7591104861676598705</id><published>2007-01-13T19:59:00.000+08:00</published><updated>2007-01-13T21:21:52.267+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>Recently...</title><content type='html'>没啥要紧事写的时候就起这个标题：Recently...  ;-)

现在开始为下一个学期做点计划了，下学期看来就是我待在学校的最后一个学期了(也是最闲的一个学期;-) 一毕业就得去公司报到了，连暑假都没得过 ;-)  不如就把下个学期当作是我过的最后一个“暑假”吧。

虽然是“暑假”但也不能闲着啊，想干的事情还有一大堆呢：
&lt;ol&gt;&lt;li&gt;昨天邮件列表又见 ZoomQuiet 提起 &lt;a href="http://webpages.charter.net/edreamleo/front.html"&gt;Leo&lt;/a&gt; ，再次对文学编程思考了一番，越发觉得有其合理之处。Leo 的核心就在于 outline ，它可以用来表达任何事物之间逻辑上的关联，这使得 Leo 拥有了难以置信的灵活性，你可以用它来组织管理许许多多的东西。而同时它能将这种逻辑上的关联与物理上的文件(代码、文档等)联系起来，并能做到两者之间 的同步，这使得它可以当个 IDE 来用！今天看 Leo 的网站的时候，惊喜地发现文档多了不少(上次就是文档不够在短暂地接触leo后就离开了)，这个&lt;a href="http://www.3dtree.com/ev/e/sbooks/leo/sbframetoc_ie.htm"&gt;在线教程&lt;/a&gt;做得非常棒，并且有了&lt;a href="http://webpages.charter.net/edreamleo/plugins.html"&gt;一大堆的 plugin &lt;/a&gt;了。打算找时间好好研究下这东西。

&lt;/li&gt;&lt;li&gt;  使用 vim 的时间也不算短了，可还是时常感觉不能够运用自如，想来主要原因在于还没系统地看过 vim 的文档，而最缺的一块就是vim插件的编写了，等把这个搞定应该就能够达到运用自如的境界了吧。

&lt;/li&gt;&lt;li&gt;在 python 社区里面混，竟然都不会玩 linux，整体用着个盗版 xp，自己想起来都觉的惭愧 = =" 。下学期要试着在 linux 下面工作入下门了。

&lt;/li&gt;&lt;li&gt;毕业就要去公司了，c/c++ 还是得先搞一搞，python 当然还是要宣传的，不过毕竟是公司，肯定不能完全顺着自己的喜好来。

&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/pylifes"&gt;Pylifes&lt;/a&gt; 项目一放就是半年没动了，下学期的毕业设计尽量给它找个合适点的题目，继续搞。&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-7591104861676598705?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/7591104861676598705/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=7591104861676598705' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7591104861676598705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7591104861676598705'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/recently_13.html' title='Recently...'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-5885723234830093958</id><published>2007-01-09T19:33:00.001+08:00</published><updated>2007-01-09T20:26:20.891+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>写了个方便下载 tudou 网视频的小程序</title><content type='html'>&lt;a href="http://huangyilib.googlecode.com/svn/trunk/tudou_dl.py" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt;http://huangyilib.googlecode.com/svn/trunk/tudou_dl.py&lt;/a&gt;

只要给它视频播放页面的地址，比如：
&lt;a href="http://www.tudou.com/programs/view/AmYV7YnHqBU/" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt;http://www.tudou.com/programs/view/AmYV7YnHqBU/ &lt;/a&gt;
它能帮你找出实际的 flv 视频下载地址：
&lt;a href="http://hot.tudou.com/flv/003/900/922/3900922.flv#81100%231" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt;http://hot.tudou.com/flv/003/900/922/3900922.flv#81100#1&lt;/a&gt;

这可是我辛辛苦苦反编译了它的 flash 播放器的代码才找到的方法啊，希望 tudou 不要太快升级才好  ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-5885723234830093958?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/5885723234830093958/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=5885723234830093958' title='4 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5885723234830093958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5885723234830093958'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/tudou.html' title='写了个方便下载 tudou 网视频的小程序'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-5444214237494291875</id><published>2007-01-03T19:58:00.001+08:00</published><updated>2007-01-04T00:50:23.651+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Recently...</title><content type='html'>最近——正在翻译 Text Process in Python 附录A：&lt;a href="http://wiki.woodpecker.org.cn/moin/TPiP/AppendixA"&gt;选择性的令人印象深刻的 python 简短回顾&lt;/a&gt;
这算是本老书了，可惜以往总是瞟一眼那短小的目录就感觉似乎都懂，没啥好看的，所以一直都没正眼瞧过它，最近偶然仔细看了几眼却惊喜地发现这竟是本不可多得的好书。
就说这篇附录吧，我发现它正是我一直在寻求的对 python 的超精简的但绝不失深度的介绍。更别说书中还有大量的高质量的(pythonic的) python 程序。
我想这篇附录最适合让已经有丰富的其他语言编程经验，甚至是有丰富的动态语言编程经验的兄弟来快速掌握 python 语言的精髓的了！

最近——惊现新的模版引擎 mako (&lt;a href="http://www.makotemplates.org/%29"&gt;http://www.makotemplates.org/) &lt;/a&gt;，myghty 杀手啊！估计最吸引眼球是它那个 benchmark 了：

Mako:    0.90 ms            Myghty:    5.25 ms
Cheetah:    0.70 ms        Genshi:    12.53 ms
Django:    5.43 ms        Kid:    19.12 ms

Cheetah above gets a speed boost from native C extensions, whereas Mako is pure Python.

恐怖啊！
genshi 刚成取代 kid 之势，看来 myghty 就快要被 mako 取代了，呵呵。
genshi/kid 的特点在于方便灵活的 xml 生成；mako/myghty 是用来生成任意形式的模版的，特点在于将 python 语言优雅地植入到模版中，并且将模版编译成 python 代码，获得极高的性能。
而这两组中的前者都超越了后者一大步！难道 genshi 和 mako 要平分(django以外的)模版世界了？拭目以待。
另外由于 mako 将模版查找的逻辑抽象到灵活的 TemplateLookup 里面 (窃以为是学习了 django 模版的思想)，我想在要在 django 的基于 app 的架构中应用 mako 模版应该不是难事，有机会要尝试一下。
再另外 mako 模版还吸收了 django 模版中的 filter 的概念。

最近—— cherrypy3.0 发布了 (&lt;a href="http://cherrypy.org/wiki/WhatsNewIn30%29"&gt; http://cherrypy.org/wiki/WhatsNewIn30)&lt;/a&gt;，大量的重构！
我感兴趣的变化首先是："CherryPy 3 is much faster than CherryPy 2 (as much as three times faster in benchmarks)."
其次就是 web 服务器和逻辑服务器的完全分离了，说 cherrypy 的 web 服务器是目前最优秀的 wsgi服务器应该没有人会反对 ;-)
另外："cherrypy.Application objects are now WSGI applications"，也就是说 cherrypy 的 url dispatcher 直接处理的就是 wsgi 应用程序了，好处不言自明，呵呵。
另外，刚又发现了这篇文章 &lt;a href="http://www.aminus.org/blogs/index.php/fumanchu/2006/12/23/cherrypy_3_has_fastest_wsgi_server_yet"&gt;cherrypy 3 has fastest WSGI server yet&lt;/a&gt;.
和 &lt;a href="http://www.zetadev.com/software/aspen/"&gt;aspen&lt;/a&gt;：一个基于 cherrypy wsgi server 的 web server，目的是方便各种风格的 web 应用程序以统一的方便的 pythonic 的方式进行部署。


直到最近——才发现原来 &lt;a href="http://routes.groovie.org/"&gt;routes&lt;/a&gt; 已经支持了 REST 形式的 dispatch 了，跟 rails 还跟得挺紧，呵呵。还发现不少新特性：

# Sub-domain support built-in
# Conditional matching based on domain, cookies, HTTP method (RESTful), and more
# Easily extensible utilizing custom condition functions and route generation functions&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-5444214237494291875?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/5444214237494291875/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=5444214237494291875' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5444214237494291875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5444214237494291875'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2007/01/recently.html' title='Recently...'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-7680206044433436301</id><published>2006-12-31T15:41:00.000+08:00</published><updated>2007-01-01T15:34:36.336+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='descriptor'/><title type='text'>理解 python 的 method 和 function 兼谈 descriptor</title><content type='html'>&lt;div class="document"&gt;总是看到有人对 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;python&lt;/span&gt;&lt;/tt&gt; 中的 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;method&lt;/span&gt;&lt;/tt&gt; 和 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;function&lt;/span&gt;&lt;/tt&gt; 之间关系的困惑，其实初学 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;python&lt;/span&gt;&lt;/tt&gt; 时我也困惑过，不过现在自认为对这个问题还是基本清楚了 ;-)。
&lt;p&gt;我在前面写过的 &lt;a href="http://codeplayer.blogspot.com/2006/12/selfless-python.html"&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;selfless&lt;/span&gt; &lt;span class="pre"&gt;python&lt;/span&gt;&lt;/tt&gt;&lt;/a&gt; 里面说过 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;method&lt;/span&gt;&lt;/tt&gt; 本质上就是 function，这个从它们的形式上也看得出来，呵呵，而让人困惑的问题主要就是那个隐式传入的 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;self&lt;/span&gt;&lt;/tt&gt; 参数。这其实是利用了&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&lt;a href="http://users.rcn.com/python/download/Descriptor.htm"&gt;descriptor&lt;/a&gt;&lt;/span&gt;&lt;/tt&gt;&lt;a href="http://users.rcn.com/python/download/Descriptor.htm"&gt; 机制&lt;/a&gt;，请看代码：
&lt;/p&gt;&lt;pre class="literal-block"&gt;&amp;gt;&amp;gt;&amp;gt; class Temp(object):
...   def test(self, a):
...     print self, a
...
&amp;gt;&amp;gt;&amp;gt; func = Temp.__dict__['test']
&amp;gt;&amp;gt;&amp;gt; func
&amp;lt;function test at 0x00B48170&amp;gt;
&amp;gt;&amp;gt;&amp;gt; func(1, 2)
1 2
&lt;/pre&gt;由此可见 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;test&lt;/span&gt;&lt;/tt&gt; 就是个不折不扣的函数！
&lt;pre class="literal-block"&gt;&amp;gt;&amp;gt;&amp;gt; Temp.test
&amp;lt;unbound method Temp.test&amp;gt;
&amp;gt;&amp;gt;&amp;gt; t = Temp()
&amp;gt;&amp;gt;&amp;gt; t.test
&amp;lt;bound method Temp.test of &amp;lt;__main__.Temp object at 0x00B46CD0&amp;gt;&amp;gt;
&lt;/pre&gt;但是这又是怎么回事了？哪里冒出个 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;bound/unbound&lt;/span&gt; &lt;span class="pre"&gt;method&lt;/span&gt;&lt;/tt&gt; 来了？
&lt;pre class="literal-block"&gt;&amp;gt;&amp;gt;&amp;gt; dir(func)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__ge
tattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__r
educe__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure',
'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_na
me']
&lt;/pre&gt;请注意其中的 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__get__&lt;/span&gt;&lt;/tt&gt; 方法，这就是 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;descriptor&lt;/span&gt;&lt;/tt&gt; 的标志(任何定义了 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__get__&lt;/span&gt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__set__&lt;/span&gt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__delete__ &lt;/span&gt;&lt;/tt&gt;三个方法中的一个或几个的对象都是 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;descriptor&lt;/span&gt;&lt;/tt&gt; ，这几个方法的意思大家应该能猜到了)

根据对象&lt;a href="http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html#id822546"&gt; attribute 的查找策略&lt;/a&gt;，当 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;t.test&lt;/span&gt;&lt;/tt&gt; 时，首先根据 &lt;a href="http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html#id822546"&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;attribute&lt;/span&gt;&lt;/tt&gt;查找策略&lt;/a&gt;找到这个函数对象，然后会发现它有 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__get__ &lt;/span&gt;&lt;/tt&gt;属性，则调用之，并把它的返回值当作该 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;attribute&lt;/span&gt;&lt;/tt&gt; 的值。
&lt;pre class="literal-block"&gt;Temp.test 等价于 Temp.__dict__['test'].__get__(None, Temp)
t.test    等价于 Temp.__dict__['test'].__get__(t, Temp)
&lt;/pre&gt;&lt;p&gt;其实你可以把 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;func.__get__&lt;/span&gt;&lt;/tt&gt; 的实现想象成下面这个等价物：
&lt;/p&gt;&lt;pre class="literal-block"&gt;&amp;gt;&amp;gt;&amp;gt; class Function(object):
...     def __get__(self, obj, objtype=None):
...         import types
...         return types.MethodType(self, obj, objtype)
&lt;/pre&gt;&lt;p&gt;到这里事情已经比较清楚了，不过还有一点可能仍然会让你感到困惑：
&lt;/p&gt;&lt;pre class="literal-block"&gt;&amp;gt;&amp;gt;&amp;gt; Temp.test = test

&amp;gt;&amp;gt;&amp;gt; t.test(1)
&amp;lt;__main__.Temp object at 0x00B46E90&amp;gt; 1
&amp;gt;&amp;gt;&amp;gt; t.test = test
&amp;gt;&amp;gt;&amp;gt; t.test(1)
Traceback (most recent call last):
File "&amp;lt;stdin&amp;gt;", line 1, in ?
TypeError: test() takes exactly 2 arguments (1 given)
&amp;gt;&amp;gt;&amp;gt; t.test
&amp;lt;function test at 0x00B42A30&amp;gt;
&lt;/pre&gt;&lt;p&gt;咦？不是说 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;function&lt;/span&gt;&lt;/tt&gt; 是 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;descriptor&lt;/span&gt;&lt;/tt&gt; 的吗？怎么这里没有去调用它的 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__get__&lt;/span&gt;&lt;/tt&gt; 方法呢？
&lt;/p&gt;&lt;p&gt;另外：
&lt;/p&gt;&lt;pre class="literal-block"&gt;&amp;gt;&amp;gt;&amp;gt; class Meta(type):pass
...
&amp;gt;&amp;gt;&amp;gt; class Temp(object):
...   __metaclass__ = Meta
...
&amp;gt;&amp;gt;&amp;gt; class Desc(object):
...   def __get__(self, instance, type):
...     print instance, type
...
&amp;gt;&amp;gt;&amp;gt; desc = Desc()
&amp;gt;&amp;gt;&amp;gt; Meta.d = desc
&amp;gt;&amp;gt;&amp;gt; Meta.d
None &amp;lt;class '__main__.Meta'&amp;gt;

&amp;gt;&amp;gt;&amp;gt; Temp.d
&amp;lt;class '__main__.Temp'&amp;gt; &amp;lt;class '__main__.Meta'&amp;gt;
&amp;gt;&amp;gt;&amp;gt; Temp.d = desc
&amp;gt;&amp;gt;&amp;gt; Temp.d
None &amp;lt;class '__main__.Temp'&amp;gt;
&amp;gt;&amp;gt;&amp;gt; t = Temp()
&amp;gt;&amp;gt;&amp;gt; t.d
&amp;lt;__main__.Temp object at 0x00B46DD0&amp;gt; &amp;lt;class '__main__.Temp'&amp;gt;

&amp;gt;&amp;gt;&amp;gt; t.d = desc
&amp;gt;&amp;gt;&amp;gt; t.d
&amp;lt;__main__.Desc object at 0x00B46D30&amp;gt;
&lt;/pre&gt;&lt;p&gt;注意到，到最后一步 t.d 的时候也没有对 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;descriptor &lt;/span&gt;&lt;/tt&gt;求值。这个道理和上面那个是一样的，仔细看一下 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;attribute&lt;/span&gt; &lt;span class="pre"&gt;查找策略&lt;/span&gt;&lt;/tt&gt; 就可以找到答案了， &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;descriptor&lt;/span&gt;&lt;/tt&gt; 只有绑定在 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; 上才有效。
&lt;/p&gt;&lt;p&gt;这里我们涉及到了 python对象一种分类： &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; 和 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;非&lt;/span&gt; &lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; ，这两种对象在 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;attribute&lt;/span&gt;&lt;/tt&gt; 查找过程中的待遇是不一样的。
&lt;/p&gt;&lt;p&gt;简单地说 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; 包括 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt;&lt;/tt&gt; 的子类( 也就是 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;metaclass &lt;/span&gt;&lt;/tt&gt;了 )、 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt;&lt;/tt&gt; 的实例( 也就是 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;class&lt;/span&gt;&lt;/tt&gt; 了 )
&lt;/p&gt;&lt;p&gt;一般来说 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; 和 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;非&lt;/span&gt; &lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; 不光在 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;attribute &lt;/span&gt;&lt;/tt&gt;受到不平等待遇，而且非 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; 还不能成为其它对象的基类型，想成为 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;metaclass&lt;/span&gt;&lt;/tt&gt; 更是痴心妄想了。
&lt;/p&gt;&lt;p&gt;不过就像我&lt;a href="http://codeplayer.blogspot.com/2006/12/metaclass-in-python-part-2.html"&gt;以前&lt;/a&gt;说过的那样，python 中的对象本质上都是平等的，区分它们的唯一方法是它们的接口，所以我相信所谓 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object &lt;/span&gt;&lt;/tt&gt;与 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;非&lt;/span&gt; &lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; 的区别也只在于接口而已。也就是说只要实现 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; 所需的接口，任何对象都可以成为 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type&lt;/span&gt; &lt;span class="pre"&gt;object&lt;/span&gt;&lt;/tt&gt; 。&lt;/p&gt;&lt;p&gt;参考：&lt;/p&gt;&lt;p&gt;&lt;a href="http://users.rcn.com/python/download/Descriptor.htm"&gt;How-To Guide for Descriptors&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a class="reference" href="http://www.cafepy.com/article/python_attributes_and_methods/"&gt;Python Attributes and Methods&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-7680206044433436301?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/7680206044433436301/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=7680206044433436301' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7680206044433436301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7680206044433436301'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/12/python-method-function-descriptor.html' title='理解 python 的 method 和 function 兼谈 descriptor'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-362535746930965209</id><published>2006-12-28T20:01:00.000+08:00</published><updated>2006-12-28T20:18:37.317+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><title type='text'>突然想到 之 ajax 和 REST</title><content type='html'>&lt;p&gt;在最近做的 django+jquery 的开发过程中，突然想到： &lt;/p&gt;&lt;ol&gt;&lt;li&gt;感觉有一些框架中自带的一些用来生成 javascript 的 helper 库的作用实在相当有限(至少对于我现在做的，它们完全帮不上忙)。他们应该也就在一些超级简单的 ajax 场景中能发挥一点作用，而对于这些简单场景，使用 jquery 写出来的 javascript 代码还不一定会比 python/ruby 的多。
&lt;/li&gt;&lt;li&gt;其次是关于所谓的 REST 。当然首先申明，我对 REST 了解并不是很深入，我只是就我所知的发发牢骚而已，所以，欢迎大家拍砖 ;-)
REST 本身其实是 web 成功以后从中总结出来的一些东西，也就是说 web 其实一直以来就是 RESTful 的。不过这里说的是老的 web，或者说是“web1.0”，在那个时代说 resource+uri+CRUD 就是一切似乎还是挺恰当的。
不过现在 web 升级了，原来的瘦客户端现在也越来越“富”了，简单的 resource + CRUD 的概念还足以描述现在（以及将来）的 web 世界吗？
当然，也许 REST 并不如我所想的这么简单 ;-) &lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-362535746930965209?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/362535746930965209/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=362535746930965209' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/362535746930965209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/362535746930965209'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/12/ajax-rest.html' title='突然想到 之 ajax 和 REST'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2257291829387144890</id><published>2006-12-24T16:09:00.000+08:00</published><updated>2006-12-24T21:22:05.348+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='pypy'/><category scheme='http://www.blogger.com/atom/ns#' term='IronPython'/><title type='text'>python virtual machines</title><content type='html'>&lt;a href="http://www.jython.org/Project/index.html"&gt;Jython&lt;/a&gt;，&lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython"&gt;IronPython&lt;/a&gt;，&lt;a href="http://pypy.org/"&gt;PyPy&lt;/a&gt;。这几个项目相信玩过 python 的兄弟都不会陌生。Jython 好像是没有继续下去了，就不多说了。IronPython 和 PyPy 两个项目现在都正是如日中天的时候，都有许多让人兴奋的进展！

先来看看 IronPython 吧。在讨论之前，我们不妨先下这么一个定义，对于 python 来说，通常说让它支持某个平台，不光是要让 python 程序能够在该平台上运行，更重要的是 python 程序要能与这个平台进行互操作！

我们说 python 是跨平台的，是因为 CPython 不光能让 python 程序运行在不同的操作系统上，更可以通过一定的接口与 c 语言进行互操作，其实也就是和操作系统平台进行互操作了。

但是如果把 .net、java 两个也看作是平台的话，就更有意思了。.net 和 java 是两个特殊的平台，它们构建于操作系统平台之上，而且它们本身已经拥有了一些比较高级的抽象，比如OO、自动内存管理等。固然，在它们上面实现 python 的时候，某些问题可以(比如内存管理)不用再考虑了，但是解决 python 与这个两个平台之间互操作的问题仍然艰巨。问题的关键还是在于静态与动态的区别，或者说编译期与运行期之间的区别。就拿对 OO 的实现来说吧，静态语言和动态语言就大不一样，比如说静态语言中对象的属性在运行时其实只是编译器算出来的相对对象基地址的一个偏移，取属性值的过程只是个对地址做加法的过程；而 python 的属性却是实打实的 key:value ，名字和值都存在内存中，取属性值的过程实际上是个查哈希表的过程。如何才能让这两种 OO 系统之间的对象之间可以互相使用，甚至进行组合、继承？另外这两个平台本身也拥有一些自己独特的特性，比如 元数据、.net的 attribute、delegate 等，如何让 python 对象拥有这些特征？这些问题就成为 Jython 和 IronPython 要解决的关键问题所在了。

适配！也许你已经联想到这个设计模式了，不过这两个字的答案还是太抽象，等于没说，如何适配才是问题的关键所在。IronPython 在这方面似乎已经做得很不错了，许多 .NET 平台上组件、框架(比如 asp.net)已经可以为 IronPython 所用了。&lt;a href="http://www.cnblogs.com/RChen"&gt;木野狐&lt;/a&gt; 同学已经写了好几篇分析 IronPython 实现的文章，看完后受益匪浅，也期待他更多的分析。从他的文章中可以看出，通过让 .net 对象实现一些由 IronPython 定义的接口便可以让 .net 的对象拥有一些 python 对象的动态特性。其实现在很想知道在 IronPython 中，一个 python 对象究竟被翻译成了一个什么样的 .NET 对象，有时间再研究研究。


再说说 &lt;a href="http://pypy.org/"&gt;PyPy&lt;/a&gt; 吧。今天逛到 pypy 首页的时候发现首页不知何时变了，变成了对项目的一个描述。可以感觉到，PyPy 已经比以前成熟很多了，至少现在对于“什么是PyPy”这个问题有了个明确的答案：“Researching a higly flexible and modular language platform and implementing it by leveraging the Open Source Python Language and Community” 。这是个实验性很强，也是野心很大的项目。我的理解是一套通用的“面向方面”的动态语言转换机制(其实现在只是 python 向其它语言的转换，不过许多东西对于其它语言也是通用的)。

它是从对 python 语言的一个“抽象”的实现开始的，其实这也就是它的名字的由来：用 python 编写的 python 实现。虽然看起来没有多大意义，其实这只是一个开始。为什么说它是个“抽象”的实现呢，因为在这个实现中把 python 实现中的许多“&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation-aspects.html"&gt;方面&lt;/a&gt;”都抽象出来了，比如 &lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation-aspects.html#the-low-level-object-model"&gt;对象模型&lt;/a&gt;、&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/garbage_collection.html"&gt; 自动内存管理&lt;/a&gt;、&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation-aspects.html#concurrency-model-implementations"&gt;并发模型&lt;/a&gt; 等，单就这个实现本身它只是个空壳(从&lt;a href="http://codespeak.net/pypy/dist/pypy/interpreter/"&gt;pypy的源代码&lt;/a&gt;也看得出来，非常少)，而把这些“方面”一加上，它就是个有用的 python 实现了！而这些“方面”或者是可选的，或者是可替换的，这让这个 python 实现拥有了&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/index.html#new-python-features"&gt;巨大的灵活性&lt;/a&gt;！

然后它通过实现一整套&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation.html#overview"&gt;语言转换的流程&lt;/a&gt;成了一个python到其它语言的转换工具！其中有一个 &lt;a href="http://codespeak.net/pypy/dist/pypy/doc/getting-started.html#a-slightly-larger-example"&gt;demo&lt;/a&gt; 演示了一个神经网络的程序在转换成 c 后执行速度提高了十几倍！目前可用的转换后端已经有：&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation.html#the-c-back-end"&gt;c&lt;/a&gt;、&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation.html#the-llvm-back-end"&gt;LLVM&lt;/a&gt;、&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation.html#gencli"&gt;.net&lt;/a&gt;、&lt;a href="http://http://codespeak.net/pypy/dist/pypy/doc/translation.html#gensqueak"&gt;Smalltalk&lt;/a&gt;、&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation.html#genjs"&gt;ECMAScript&lt;/a&gt;、&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation.html#gencl"&gt;Common Lisp&lt;/a&gt; ！

对于研究人员来说 PyPy 自然是一个不可多得的实验平台。而随着 pypy 的成熟，它对于 python 程序员的价值也会越来越大，我觉得最重要的一点就是对 python 程序进行优化，比如向 c 语言的转换，为 python 虚拟机提供 &lt;a href="http://codespeak.net/pypy/dist/pypy/doc/jit.html"&gt;JIT&lt;/a&gt; ，还有在&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/translation.html#backend-optimizations"&gt;转换中进行的优化&lt;/a&gt;等；其次就是 &lt;a href="http://codespeak.net/pypy/dist/pypy/doc/stackless.html"&gt;stackless&lt;/a&gt; ；另外&lt;a href="http://codespeak.net/pypy/dist/pypy/doc/js/using.html"&gt;向 javascript 的转换&lt;/a&gt;也是很有用(也是很好用)的。

最后还有重要的一点不得不提的就是，所有这些全部都是用纯 python 编写而成！

更多的细节也不多说了 (再说下去就要露馅了 ;-) PyPy 涉及的范围广，要研究透彻还得花一番功夫，只能是期待它结出累累硕果的那一天早日来到吧，呵呵。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2257291829387144890?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2257291829387144890/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2257291829387144890' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2257291829387144890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2257291829387144890'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/12/python-virtual-machines.html' title='python virtual machines'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-7757009792251245228</id><published>2006-12-17T11:49:00.000+08:00</published><updated>2006-12-18T12:07:14.627+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='metaclass'/><title type='text'>selfless python</title><content type='html'>&lt;a href="http://www.voidspace.org.uk/python/articles/metaclasses.shtml"&gt;Eliminating self with Metaclasses&lt;/a&gt;

此文利用 metaclass 和字节码，使得在 class 中定义方法时不再需要显式指定 self 参数，当真妙极！

关于这个 self 参数是否多余，本身也是仁者见仁、智者见智的事情。我认为 python 这么做是有它充分的理由的，那就是 class 中定义的方法本质上还是函数，是函数就应该遵循函数的规矩，没必要对方法进行特殊照顾，隐藏掉 self 参数只是增加了一份 magic。
也许你会问了：那这个 self 是怎么传进去的呢？这里不又是一个 magic 吗？其实，这是利用了 &lt;a href="http://users.rcn.com/python/download/Descriptor.htm"&gt;descriptor &lt;/a&gt;对函数进行了包装，而 &lt;a href="http://users.rcn.com/python/download/Descriptor.htm"&gt;descriptor &lt;/a&gt;本身是个应用面很广的概念，并不只是为了实现这个而生的。

不管怎么说，相信总是有一些人(可能还是不少人)不喜欢这个 self 参数，那让我们回到主题，看看去掉 self 参数之后的 class 定义是什么样的：
&lt;blockquote&gt;&lt;pre&gt;class Test(object):

   __metaclass__ = Selfless

   def __init__(x=None):
       self.x = x

   def getX():
       print self.x

   def setX(x):
       self.x = x

test = Test()
test.getX()

test.setX(7)
test.getX()&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-7757009792251245228?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/7757009792251245228/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=7757009792251245228' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7757009792251245228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7757009792251245228'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/12/selfless-python.html' title='selfless python'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4316373995434023749</id><published>2006-12-16T19:27:00.000+08:00</published><updated>2006-12-16T22:02:46.451+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='metaclass'/><title type='text'>python types and objects</title><content type='html'>在探寻 metaclass 的过程中，对以前熟知的 OO 又有了全新的认识。我开始感觉到，只有在动态语言的世界，才有可能对这些概念有如此通透的理解。

在静态语言中，type 和 instance 之间永远隔着编译期和运行期之间的鸿沟。而在动态语言中，简单的 object 的概念统一世界，type 和 instance 突然变得如此的一致(都是object)，其间并没有本质的区别。我们只有按照逻辑对其进行区分。

虽然由于现实世界问题概念本身的局限性，和 python 提供的各种方便的“语法糖”，使得普通的 python 程序和静态语言程序似乎区别不大。但其实当你深入 python 的基础，你会发现表象的下面其实隐藏着动态语言与生俱来的优雅和强大的根基！

这一切，都始于 &lt;a href="http://www.python.org/2.2.3/descrintro.html"&gt;python2.2 那一场翻天覆地的变革&lt;/a&gt;！

&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Everything is an object&lt;/span&gt;&lt;/strong&gt;

而所有 objects 之间存在着两种关系：is-a-kind-of 即类型-子类型，is-an-instance-of 即类型-实例。对应这两种关系，也就存在着两种产生新对象的方式：继承和实例化，前者可通过 class 语句：

&lt;pre&gt;class Temp(object):
  a = 1&lt;/pre&gt;产生；
后者通过“调用”语句：

&lt;pre&gt;obj = Temp()&lt;/pre&gt;产生。

通过这两条规则，python中的对象可以向这两条正交的方向延伸，它们的起点就是内置对象：type 和 object 。

type 是所有对象(包括它自己!)的类型，object 是除了它自己以外所有类型(包括type!)的基类。
理论上说，从这两个起点出发我们可以朝着两个方向无限延伸，不过一般 python 代码中都只出现两层 类型-实例 关系，也就是：
metaclass - class - instance
一般 metaclass 是 type 的子类，class 是 object 的子类，instance 不存在继承关系。

参考：

&lt;a href="http://www.cafepy.com/article/python_types_and_objects/"&gt;Python Types and Objects&lt;/a&gt; 要是你对这个主题有兴趣，那一定要看这篇了，基本上你可以把本文当作是这篇文章的一个摘要。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4316373995434023749?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4316373995434023749/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4316373995434023749' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4316373995434023749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4316373995434023749'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/12/python-types-and-objects.html' title='python types and objects'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-916576594703616459</id><published>2006-12-11T17:34:00.000+08:00</published><updated>2007-05-22T02:32:20.431+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='metaclass'/><title type='text'>metaclass in python (part 2)</title><content type='html'>接着&lt;a href="http://codeplayer.blogspot.com/2006/12/metaclass-in-python.html"&gt;上一篇&lt;/a&gt;的讲。

现在我们知道了，metaclass 生 class，class 生 instance。
但是 metaclass 还可以有它的 metametaclass，metametaclass 还可以有... 如此反复，永无止境。这样想起来，脑袋就有点晕了。
其实在 python 中万物皆对象而已，所有对象皆有其类型，对象的类型也还是对象！而类型对象的类型就是它自己。
而前面说过的所谓 instance、class、metaclass 等东西，都只是不同种类的对象而已。

判断对象是什么对象的唯一方法就是通过其提供的“接口”，这就是所谓的 duck typing！只要一个对象实现了成为一个 class 所需的接口，它就是 class ！metaclass 亦然。
那么我们不如先来讨论讨论 metaclass 的接口吧，看看究竟需要实现哪些接口能使一个对象成为一个 metaclass。
先来看一些等价关系： &lt;pre&gt;class Temp(object):
   __metaclass__ = Meta
   a = 1
   def __init__(self, a):
       self.a = a
&lt;/pre&gt; 上面代码其实等价于： &lt;pre&gt;Temp = Meta('Temp', (object,),
  {'a':1, '__module__':'current module name', '__metaclass__':the object Meta, '__init__':function object __init__})
&lt;/pre&gt; （class的语法原来只是个语法糖而已，汗！）
由此可见 Meta 首先应该是个 callable，并且应该接受如上所示的三个参数。 &lt;pre&gt;t = Temp(2) # 构建 Temp 的 instance
&lt;/pre&gt; 从这一句我们可以看出 Temp 也应该是个 callable 对象。
而我们知道 Temp 对象其实是调用 Meta 所返回的，也就是说 Meta 这个 callable 对象返回的还应该是一个 callable 对象。
典型地，如果 Meta 是一个 class，意味着它应该实现一个 __call__ 方法。这样的话，那么上面那句就可以等价为：
&lt;pre&gt;t = Temp.__call__(2)&lt;/pre&gt;上面说的这几点基本上可以作为判断一个对象能否成为 metaclass 的标准了：&lt;span style="font-weight: bold;"&gt;一个接受三个参数并返回另一个 callable 对象的 callable 对象！&lt;/span&gt;

不急，在继续分析之前我们不妨利用刚才发现的这一点搞点小怪先，呵呵。 &lt;pre&gt;def Meta(name, bases, attrs):
   def _class(a):
       return a
   return _class

class Temp(object):
   '''
   &gt;&gt;&gt; Temp(1)
   1
   &gt;&gt;&gt; Temp('hello')
   'hello'
   '''
   __metaclass__ = Meta
&lt;/pre&gt; 继续分析，虽然可以像上面那样恶搞，不过要想写个有点实际用处的 metaclass ，还是通过 class 来实现比较方便。
最典型的方法便是直接继承 type 了，毕竟那是所有 new-style class 的 metaclass，在 python3000 里就要成为所有 class 默认的 metaclass 了。
可以说大部分 metaclass 的实现都是这么做的，不过下面要分析的&lt;a href="http://www.google.com/codesearch?hl=zh-CN&amp;q=show:nnCtg1uwMeY:7rHeCakI6l0:FCR9bYoN8Dg&amp;amp;sa=N&amp;ct=rd&amp;amp;cs_p=http://www.zope.org/Products/Zope3/3.3.0c1/Zope-3.3.0c1.tgz&amp;cs_f=Zope-3.3.0c1/Dependencies/zope.interface-Zope-3.3.0c1/zope.interface/tests/odd.py" target="blank_" title="这一例"&gt;这一例&lt;/a&gt;却是个例外，虽然不像上面我们写的那个 metaclass 那么奇怪，不过分析起来也不是那么容易的。

不过我们还需要继续澄清一些事实，先看这个例子： &lt;pre&gt;class Temp(object):
   @staticmethod  # 这一句可以忽略，不管有没有这句，__new__ 都是静态方法
   def __new__(cls, a):
       return object.__new__(cls, a)
   def __init__(self, a):
       self.a = a
   def __getattribute__(self, name):
       return super(Temp, self).__getattribute__(name)
   def __getattr__(self, name):
       return super(Temp, self).__getattr__(name)

t = Temp(2)
print t.a
&lt;/pre&gt; 在默认的 metaclass type 的实现中，上面这句，也就是 type 的 __call__ 方法，其实是分以下两步完成的： &lt;pre&gt;t = Temp.__new__(Temp, 2) # 调用 staticmethod __new__，创建 instance
t.__init__(2) # 调用该 instance 的构造函数，初始化 instance
&lt;/pre&gt; 另外，既然 Temp 实现了 __getattribute__， t.a 实际上等价于： &lt;pre&gt;try:
   t.__getattribute__(self, 'a')
except AttributeError:
   t.__getattr__(self, 'a')
&lt;/pre&gt; 到这里基本上一些概念问题已经搞清楚了，下一篇终于可以正式开始研究&lt;a href="http://www.google.com/codesearch?hl=zh-CN&amp;amp;q=show:nnCtg1uwMeY:7rHeCakI6l0:FCR9bYoN8Dg&amp;sa=N&amp;amp;ct=rd&amp;cs_p=http://www.zope.org/Products/Zope3/3.3.0c1/Zope-3.3.0c1.tgz&amp;amp;cs_f=Zope-3.3.0c1/Dependencies/zope.interface-Zope-3.3.0c1/zope.interface/tests/odd.py" target="blank_" title="这里的代码"&gt;这里的代码&lt;/a&gt;了。

参考：
&lt;a href="http://www.python.org/download/releases/2.2.3/descrintro/" title="Unifying types and classes in Python 2.2"&gt;Unifying types and classes in Python 2.2&lt;/a&gt; 这是老大对 python2.2 以后的“python对象模型”的深刻的描述
&lt;a href="http://www.python.org/download/releases/2.3/mro/" target="blank_" title="The Python 2.3 Mehod Resolution Order"&gt;The Python 2.3 Mehod Resolution Order&lt;/a&gt; 这也是今天碰巧看到的好文，虽然与本文没有什么联系，不过，此文深入讲解了 python2.3 以后对多继承的实现， 我也是看完这篇才知道实现个多继承是如此的复杂，不过幸好他们找到了合适的算法。 另外对于平时不经常接触算法的人（比如我）来说，偶尔用数学的思维思考思考还有很有好处的。
&lt;a href="http://www.python.org/doc/newstyle.html" target="blank_" title="New-style Classes"&gt;New-style Classes&lt;/a&gt; 这里是 new-style class 相关的文献的集合。
另外想找这方面中文资料的兄弟可以去啄木鸟：&lt;a href="http://wiki.woodpecker.org.cn/moin/PyNewStyleClass" target="blank_" title="python中的新型类及其实例详解"&gt;python中的新型类及其实例详解&lt;/a&gt; &lt;a href="http://wiki.woodpecker.org.cn/moin/MetaClassInPython" target="blank_" title="Metaclasses(元类)"&gt;Metaclasses(元类)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-916576594703616459?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/916576594703616459/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=916576594703616459' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/916576594703616459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/916576594703616459'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/12/metaclass-in-python-part-2.html' title='metaclass in python (part 2)'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-833852557340955720</id><published>2006-12-11T14:49:00.000+08:00</published><updated>2006-12-12T22:15:03.558+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='metaclass'/><title type='text'>metaclass in python (part 1)</title><content type='html'>python 的东西虽然概念上&lt;a href="http://codeplayer.blogspot.com/2006/09/python-is-obvious.html"&gt;容易理解&lt;/a&gt; ，但是实际用起来却也不都是那么容易的。这个 metaclass 就是典型一例。虽然早知道了它是什么，不过要说出它具体能干点啥，一时半会还真想不起来。
先看看官方文档中的定义吧：
&lt;dl&gt;&lt;dt&gt;&lt;b&gt;&lt;tt id="l2h-218"&gt;__metaclass__&lt;/tt&gt;&lt;/b&gt;  &lt;/dt&gt;&lt;dd&gt;This variable can be &lt;span style="font-weight: bold;"&gt;any callable&lt;/span&gt; accepting arguments for &lt;code&gt;name&lt;/code&gt;,  &lt;code&gt;bases&lt;/code&gt;, and &lt;code&gt;dict&lt;/code&gt;. Upon class creation, the callable is  used instead of the built-in &lt;tt class="function"&gt;type()&lt;/tt&gt;. &lt;span class="versionnote"&gt;New in version 2.2.&lt;/span&gt; &lt;/dd&gt;&lt;/dl&gt; &lt;p&gt;The appropriate metaclass is determined by the following precedence rules:  &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;ul&gt;&lt;li&gt;If &lt;code&gt;dict['__metaclass__']&lt;/code&gt; exists, it is used.   &lt;/li&gt;&lt;li&gt;Otherwise, if there is at least one base class, its metaclass is used (this  looks for a &lt;var&gt;__class__&lt;/var&gt; attribute first and if not found, uses its  type).    &lt;/li&gt;&lt;li&gt;Otherwise, if a global variable named __metaclass__ exists, it is used.   &lt;/li&gt;&lt;li&gt;Otherwise, the old-style, classic metaclass (types.ClassType) is used.  &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The potential uses for metaclasses are boundless. Some ideas that have been  explored including logging, interface checking, automatic delegation, automatic  property creation, proxies, frameworks, and automatic resource  locking/synchronization.&lt;/p&gt;&lt;p&gt;看完这个似乎又能理清了一点东西：所谓 new-style class 和 old-style class 最根本的区别其实正在于它们的 metaclass 一个是 type，一个是 types.ClassType，所以只要一个 class 继承自 object 而又没有指定自己的 __metaclass__ 的话，其 metaclass 就会自动使用基类 object 的 __metaclass__，但是 object 却没有 __metaclass__，那就使用 type(object)，也就是 type 了！
&lt;/p&gt;然后再 google 一下（这次是要 &lt;a href="http://www.google.com/codesearch?q=__metaclass__+lang%3Apython&amp;hl=zh-CN&amp;amp;btnG=%E6%90%9C%E7%B4%A2%E4%BB%A3%E7%A0%81"&gt;google code&lt;/a&gt; 一下了），看看实际生活中的代码都用它来干了点啥。不搜不知道，这一搜还真发现不少有意思的结果：
&lt;ol&gt;&lt;li&gt;第一条[&lt;a href="http://www.google.com/codesearch?hl=zh-CN&amp;q=+lang:python+__metaclass__+show:S97q-fqfoqY:DlIugF_UJjY:H5_0nuC5kZY&amp;amp;sa=N&amp;cd=1&amp;amp;ct=rc&amp;cs_p=svn://svn.twistedmatrix.com/svn/Twisted/trunk&amp;amp;cs_f=twisted/python/lockfile.py#a0"&gt;地址&lt;/a&gt;]，是twisted里的代码&lt;pre&gt;__metaclass__ = type&lt;/pre&gt;真有创意！根据上面定义中 __metaclass__ 查找顺序，在使用 old-style class 的 metaclass (也就是types.ClassType)之前会找一下全局变量 __metaclass__ ，而上面代码中通过定义模块全局变量 __metaclass__ ，使得模块中原来的 old-style class 立刻变成了 new-style class。使用这种方法来将 old-style class 升级为 new-style class，确实省了不少代码，毕竟将来的 python 中将会只存在 new-style class ，那时候便可放心地将这一句去掉了。聪明！(不过这样会导致查找 metaclass 的过程要多了几个步骤，效率上可能就 ... )&lt;/li&gt;&lt;li&gt;第二条[&lt;a href="http://www.google.com/codesearch?hl=zh-CN&amp;q=+lang:python+__metaclass__+show:kn0aA5Q3Jg8:UawDU0cXOrk:SdcmUPGin9I&amp;amp;sa=N&amp;cd=2&amp;amp;ct=rc&amp;cs_p=http://www.python.org/ftp/python/2.5/Python-2.5c2.tar.bz2&amp;amp;cs_f=Python-2.5c2/Tools/framer/framer/bases.py#a0"&gt;地址&lt;/a&gt;]，从这个例子的路径看它是在 python25/tools/ 下面，不过翻了一下自己python25 安装目录下却没有发现这些代码，郁闷！
在这个例子中，__metaclass__ 被当成了一种快捷定义 class 方法的方式了。
我们知道在 class 中定义的方法其实默认都是 instance 方法，要使它们成为 class 方法需要使用 classmethod 进行装饰，对于有大量 class 方法的类来说，这的确是有点小麻烦。
既然 class 中定义的方法是 class 的 instance 方法，那么在 type 中定义的方法岂不就是 type 的 instance 方法，也就正好是 class 方法了？
这个例子便是利用这一点，通过继承 type，添加 type 的 instance 方法，也就是添加了 class 方法了。好聪明啊，呵呵 ;-)&lt;/li&gt;&lt;li&gt;第三条的用法与第一条类似，第四条[&lt;a href="http://www.google.com/codesearch?hl=zh-CN&amp;q=+lang:python+__metaclass__+show:zqjOeDUMGKA:mW4TekceXNk:tUDIi4YQ4tg&amp;amp;sa=N&amp;cd=4&amp;amp;ct=rc&amp;cs_p=http://www.zettai.net/Support/Downloads/py234.tar.gz&amp;amp;cs_f=py/lib/python2.3/site-packages/psyco/classes.py#a0"&gt;地址&lt;/a&gt;]来自传说中的 &lt;a href="http://psyco.sourceforge.net/"&gt;psyco &lt;/a&gt;！一看到这个名字差点没有勇气继续看下去了，不过还好，这个 metaclass 其实并不复杂，它的作用就是在 class 创建之后自动将它或 __psyco_bind__ 中指定的属性 bind 到 psyco，具体 bind 干了什么事情就只有对 psyco 有研究的兄弟来解答了，不过估计这样就可以进行某种特别的优化了。也许你要说了：这个工作也可以在 class 的 __init__ 或是 __new__ 方法里做啊。但是放在 __init__ 里面做的话你就需要其他的 class 都来继承你这个基类了，而使用 __new__ 的问题是它可以被子类 override 掉。
使用 metaclass 的另一个好处是，你可以神不知鬼不觉地修改 class 的创建过程，比如
这个例子里面，在模块中定义好 __metaclass__ 全局变量，那当其他的代码 from module import * 的时候，该 __metaclass__ 的定义就会自动作用于其后所定义的所有 class 了。&lt;/li&gt;&lt;li&gt;第五条和第八条的用法也和第一条类似，第六条貌似只是在使用 __metaclass__ 的情况下对 pickle  进行测试，没有什么特别的。至于第七条。。。。&lt;/li&gt;&lt;/ol&gt;而至于&lt;a href="http://www.google.com/codesearch?hl=zh-CN&amp;q=+lang:python+__metaclass__+show:8RGvh2wYR_E:7rHeCakI6l0:tZ-hgXDh4fE&amp;amp;sa=N&amp;cd=7&amp;amp;ct=rc&amp;cs_p=http://www.zope.org/Products/Zope3/3.3.0c1/Zope-3.3.0c1.tgz&amp;amp;cs_f=Zope-3.3.0c1/Dependencies/zope.interface-Zope-3.3.0c1/zope.interface/tests/test_odd_declarations.py#a0"&gt;第七&lt;/a&gt;（来自zope）和&lt;a href="http://www.google.com/codesearch?hl=zh-CN&amp;q=+lang:python+__metaclass__+show:flV19Zt4I-g:zMTdPsbk4Sg:4ZcJ19e6zvc&amp;amp;sa=N&amp;cd=9&amp;amp;ct=rc&amp;cs_p=http://www.enfoldsystems.com/Products/Entransit/entransit-0.9.3.tar.gz&amp;amp;cs_f=entransit-0.9.3/src/sqlobject/declarative.py#a0"&gt;第九&lt;/a&gt;（来自sqlobject）两条，还是听&lt;a href="http://codeplayer.blogspot.com/2006/12/metaclass-in-python-part-2.html"&gt;下回&lt;/a&gt;分解吧。

不好意思，真的不是我卖关子，实在是被&lt;a href="http://www.google.com/codesearch?hl=zh-CN&amp;q=+lang:python+__metaclass__+show:flV19Zt4I-g:zMTdPsbk4Sg:4ZcJ19e6zvc&amp;amp;sa=N&amp;cd=9&amp;amp;ct=rc&amp;cs_p=http://www.enfoldsystems.com/Products/Entransit/entransit-0.9.3.tar.gz&amp;amp;cs_f=entransit-0.9.3/src/sqlobject/declarative.py#a0"&gt;第七条&lt;/a&gt;整晕了 = ="，真不知道写这些代码的人是怎么想的，呵呵。
希望大家能从这些代码中看到 metaclass 的强大，动态语言的灵活。什么？还没看到？去看看&lt;a href="http://www.google.com/codesearch?hl=zh-CN&amp;q=show:nnCtg1uwMeY:7rHeCakI6l0:FCR9bYoN8Dg&amp;amp;sa=N&amp;ct=rd&amp;amp;cs_p=http://www.zope.org/Products/Zope3/3.3.0c1/Zope-3.3.0c1.tgz&amp;amp;cs_f=Zope-3.3.0c1/Dependencies/zope.interface-Zope-3.3.0c1/zope.interface/tests/odd.py"&gt;这个&lt;/a&gt;去！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-833852557340955720?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/833852557340955720/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=833852557340955720' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/833852557340955720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/833852557340955720'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/12/metaclass-in-python.html' title='metaclass in python (part 1)'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2966238594428345847</id><published>2006-12-04T13:05:00.000+08:00</published><updated>2006-12-04T16:01:32.465+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>a python tutorial</title><content type='html'>&lt;a href="http://www.voidspace.org.uk/python/articles/python_datatypes.shtml"&gt;A Very Brief Introduction To Python And It's Data-Types&lt;/a&gt;

一篇短小精悍的 python tutorial 。对一些容易被忽视的问题讲得很清楚！很专业的 tutorial！摘录片段如下：
&lt;ul&gt;&lt;li&gt;The Python 'philosophy' emphasises &lt;span style="font-weight: bold;"&gt;readability&lt;/span&gt;, &lt;span style="font-weight: bold;"&gt;clarity &lt;/span&gt;and &lt;span style="font-weight: bold;"&gt;simplicity&lt;/span&gt;, whilst maximising the power and expressiveness available to the programmer.
看到这句话我不自觉地就想起了c++：“The c++ 'philosophy' emphasises performance, performance and performance, whilst maximising the power and expressiveness available to the programmer”  ;-)  它们在各自的领域都做得很不错。&lt;/li&gt;&lt;li&gt;The line of code &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;x&lt;/span&gt; &lt;span class="pre"&gt;=&lt;/span&gt; &lt;span class="pre"&gt;3&lt;/span&gt;&lt;/tt&gt; is a &lt;em&gt;statement&lt;/em&gt; (more about that in a bit) which means it does a job. The job it does is to &lt;em&gt;assign&lt;/em&gt; the value 3 to the variable 'x'. In Python terminology we say that it &lt;span style="font-weight: bold;"&gt;binds the name 'x' to the number three&lt;/span&gt;. This idea of variables being &lt;em&gt;names bound to objects&lt;/em&gt; (or names which 'reference' objects) is important in Python.&lt;/li&gt;&lt;li&gt;'Under the hood' Python actually uses two types of integer, the integer and the &lt;span style="font-weight: bold;"&gt;'long integer'&lt;/span&gt; for integers bigger than a certain amount.&lt;/li&gt;&lt;li&gt;If you need to a lot of complicated maths with floating point numbers, then you may be interested in extensions like &lt;a style="font-weight: bold;" class="reference" href="http://numpy.scipy.org/"&gt;numpy&lt;/a&gt; or&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;a style="font-weight: bold;" class="reference" href="http://gmpy.sourceforge.net/"&gt;General Multiprecision Python project&lt;/a&gt;. These extensions provide very fast ways of doing mathematical operations. For normal use the capabilities built in to Python will be sufficient.&lt;/li&gt;&lt;li&gt;The name 'string' &lt;em&gt;probably&lt;/em&gt; comes from the fact that programming languages often treat text as a sequence of characters 'stringed' together.
&lt;/li&gt;&lt;li&gt;The basic string type (which I have called 'normal strings' below) store the text as a sequence of bytes (numbers) with one byte per character. .... &lt;span style="font-weight: bold;"&gt;They can also be used for storing binary data in&lt;/span&gt;. &lt;/li&gt;&lt;li&gt;Unicode strings store text internally using the &lt;a style="font-weight: bold;" class="reference" href="http://en.wikipedia.org/wiki/Unicode"&gt;unicode standard&lt;/a&gt;. They are slightly more complicated, because you must know the 'encoding' the text is stored in whenever you read the text in or save it out. In the long run this can save a great deal of confusion.&lt;/li&gt;&lt;li&gt;Because the interpreter knows the length and types of the members of a tuple, working with them can be more efficient than using a list.&lt;/li&gt;&lt;li&gt;Dictionaries are an extremely useful and flexible datatype. In fact &lt;span style="font-weight: bold;"&gt;Python is built on them&lt;/span&gt;.  &lt;img src="http://www.voidspace.org.uk/smilies/smile.gif" alt="Smile" height="15" width="15" /&gt;&lt;/li&gt;&lt;li&gt;Programs are actually compiled to byte-code before being executed, but the byte-code is then interpreted. In some ways this is similar to Java or .NET which also compile to byte-code. Because these languages are &lt;span style="font-weight: bold;"&gt;statically typed with &lt;/span&gt;&lt;acronym style="font-weight: bold;" title="Just in Time"&gt;JIT&lt;/acronym&gt;&lt;span style="font-weight: bold;"&gt; compiler, they are generally considered as compiled languages whilst Python is generally considered as being interpreted&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2966238594428345847?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2966238594428345847/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2966238594428345847' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2966238594428345847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2966238594428345847'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/12/python-tutorial.html' title='a python tutorial'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-5914100613871865713</id><published>2006-12-02T16:43:00.000+08:00</published><updated>2006-12-04T15:59:50.220+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><title type='text'>django collection</title><content type='html'>Inspired by &lt;a href="http://blog.dowski.com/2006/11/07/collection-implementation-for-cherrypy-22/"&gt;CherryPy Collection&lt;/a&gt; which is inspired by &lt;a href="http://bitworking.org/news/wsgicollection"&gt;wsgicollection&lt;/a&gt; .

&lt;a href="http://code.google.com/p/djangocollection/"&gt;code&lt;/a&gt; &lt;a href="http://code.google.com/p/djangocollection/"&gt;代码&lt;/a&gt;

不知不觉又是好久没有写 blog ，最近被 javascript 和 浏览器折磨得好惨！哎，怀念漂亮的 python。这不，忙里偷闲还是要写点有意思的小程序，希望对某些人有用 ;-)

&lt;blockquote&gt; This project include two applications: the djcollection and a demo app task.

REST is mostly about url dispatching, and djcollection app provide a set of generic RESTful urls for all the models of the project, djcollection app also provide a GenericCollection which uses the django generic views.

the task app is for demonstrate the usage of the djcollection.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-5914100613871865713?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/5914100613871865713/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=5914100613871865713' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5914100613871865713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5914100613871865713'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/12/django-collection.html' title='django collection'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-4011330490262774839</id><published>2006-11-16T11:22:00.000+08:00</published><updated>2006-12-14T10:19:08.436+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='allegra'/><category scheme='http://www.blogger.com/atom/ns#' term='network'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>simple rpc with allegra</title><content type='html'>先安装 &lt;a href="http://laurentszyster.be/blog/allegra" target="blank_" title="allegra"&gt;allegra&lt;/a&gt;
和 &lt;a href="http://huangyilib.googlecode.com/svn/trunk/allegra_rpc/" target="blank_" title="程序"&gt;程序&lt;/a&gt;
然后执行测试服务器和测试客户端！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-4011330490262774839?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/4011330490262774839/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=4011330490262774839' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4011330490262774839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/4011330490262774839'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/11/simple-rpc-with-allegra-allegra.html' title='simple rpc with allegra'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2392133472972212095</id><published>2006-11-15T18:21:00.000+08:00</published><updated>2006-11-15T18:26:38.963+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>使用 google docs 发的第一篇 blog</title><content type='html'>&lt;span style="font-size:7;"&gt;&lt;span style="color: rgb(0, 0, 153);"&gt; G&lt;/span&gt;&lt;span style="color: rgb(153, 51, 0);"&gt;o&lt;/span&gt;&lt;span style="color: rgb(204, 153, 51);"&gt;o&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;g&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;l&lt;/span&gt;&lt;span style="color: rgb(153, 51, 0);"&gt;e&lt;/span&gt;&lt;/span&gt; 的东西就是&lt;span style="color: rgb(255, 255, 255);"&gt;好&lt;/span&gt;，就是&lt;span style="color: rgb(255, 255, 255);"&gt;好&lt;/span&gt;哇就是&lt;span style="color: rgb(255, 255, 255);"&gt;好&lt;/span&gt; ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2392133472972212095?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2392133472972212095/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2392133472972212095' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2392133472972212095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2392133472972212095'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/11/g-o-o-g-l-e.html' title='使用 google docs 发的第一篇 blog'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-7880737766520683403</id><published>2006-11-12T16:51:00.001+08:00</published><updated>2006-12-14T10:24:50.425+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wsgi'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='paste'/><title type='text'>file upload monitor</title><content type='html'>Paste 有不少有意思的 wsgi 组件，这个 progress.py  就是其中之一。
使用它配合ajax编写了一个简单的文件上次进度检测程序，ajax部分是从其他人的代码复制过来稍作修改而得，另外如果你感觉文件上传速度奇慢无比，请不要吃惊，那是因为服务器端用了 sleep 故意获得这种慢的效果的，&lt;a href="http://huangyilib.googlecode.com/svn/trunk/file_upload_monitor.py"&gt;程序在此&lt;/a&gt;。

要运行此程序你需要安装 &lt;a href="http://pythonpaste.org/"&gt;paste&lt;/a&gt; 先！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-7880737766520683403?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/7880737766520683403/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=7880737766520683403' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7880737766520683403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/7880737766520683403'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/11/file-upload-monitor_12.html' title='file upload monitor'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-961492648679762085</id><published>2006-11-08T22:29:00.001+08:00</published><updated>2006-11-12T16:51:06.712+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mochikit'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><title type='text'>MochiKit Animator : 太漂亮了</title><content type='html'>&lt;a href="http://gr.ayre.st/%7Egrayrest/animator/animator.html"&gt;demos&lt;/a&gt;
&lt;a href="http://ajaxian.com/archives/mochikitanimator-new-animation-in-mochikit"&gt;评论&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-961492648679762085?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/961492648679762085/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=961492648679762085' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/961492648679762085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/961492648679762085'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/11/mochikit-animator.html' title='MochiKit Animator : 太漂亮了'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-8611921167493582915</id><published>2006-10-29T16:11:00.000+08:00</published><updated>2006-10-29T21:55:26.497+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='turbogears'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>django new forms and tgwidgets</title><content type='html'>看到一个漂漂亮亮的&lt;a href="http://code.djangoproject.com/svn/django/trunk/django/newforms/" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt;forms库&lt;/a&gt;就这样在大家的&lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/7eceb616b251cbd0/2615be5ec6d13bd1" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt;讨论&lt;/a&gt;中逐渐成型，虽然自己并没有参与(怕说话他们看不懂)，但也已经觉得很开心了。
&lt;div id="mb_0"&gt;另外turbogears中的widgets库也被抽取出来了&lt;wbr&gt;，变成了&lt;a href="http://tgwidgets.toscat.net/" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt;tgwidgets&lt;/a&gt;。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-8611921167493582915?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/8611921167493582915/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=8611921167493582915' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8611921167493582915'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8611921167493582915'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/10/django-new-forms-and-tgwidgets.html' title='django new forms and tgwidgets'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-2229829399780924620</id><published>2006-10-23T19:43:00.000+08:00</published><updated>2006-10-23T21:04:07.410+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>REST，让 web 变得更美好！</title><content type='html'>What is &lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" rel="nofollow"&gt;Representational State Transfer &lt;/a&gt;(REST)?
&lt;a href="http://www.xfront.com/REST-Web-Services.html"&gt;Building Web Services the REST Way&lt;/a&gt;
&lt;a href="http://jtauber.com/blog/2006/01/25/python_web_frameworks_and_rest"&gt;Python Web Frameworks and REST&lt;/a&gt;
&lt;a href="http://www.xml.com/pub/a/2005/08/17/restful-web.html"&gt;Dispatching in a REST Protocol Application&lt;/a&gt;
&lt;a href="http://lukearno.com/projects/selector/"&gt;selector&lt;/a&gt;: a RESTful url dispatcher.
&lt;a href="http://bitworking.org/news/Why_so_many_Python_web_frameworks"&gt;robaccia&lt;/a&gt;: a RESTful web framework. (yes, the mini web framework!)
&lt;a href="http://bitworking.org/news/wsgicollection" rel="bookmark"&gt;wsgicollection&lt;/a&gt;: make robaccia even more RESTful.
&lt;a href="http://bitworking.org/news/JEP"&gt;use JSON RESTfully&lt;/a&gt;
&lt;a href="http://www.onlamp.com/pub/a/python/2006/02/23/using-rest-with-ajax.html"&gt;Using REST with Ajax&lt;/a&gt;


&lt;ol&gt;&lt;li&gt;&lt;strong&gt;什么是REST？&lt;/strong&gt;&lt;/li&gt;REST是网络系统的一种 architecture style，我们的 web 便是这种 architecture style 一个好例子。万物皆资源，web便由这些资源所组成。每项资源都有其标识，即URL。当我们通过客户端访问一个URL，相应资源的一个 &lt;strong&gt;representation&lt;/strong&gt; 便会返回。于是客户端的 &lt;strong&gt;state&lt;/strong&gt; 便发生了改变。所以叫做 &lt;strong&gt;Representation State&lt;/strong&gt; Transfer！而服务器不保存 state ，这使得客户端的请求是相对独立的，只要客户端的 &lt;strong&gt;state&lt;/strong&gt; 不变，那么客户端的相同请求总是得到相同的 &lt;strong&gt;representation&lt;/strong&gt; 。

&lt;li&gt;&lt;strong&gt;设计 RESTful 的web服务的原则
&lt;/strong&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;标识所有需要暴露的资源，&lt;/li&gt;
&lt;li&gt;为每一个资源设计URL，资源应该是名词而非动词，比如应该使用 &lt;a href="http://www.parts-depot.com/parts/00345"&gt;http://www.parts-depot.com/parts/00345&lt;/a&gt; 而非 &lt;a href="http://www.parts-depot.com/parts/getPart?id=00345"&gt;http://www.parts-depot.com/parts/getPart?id=00345&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;根据用户能否修改还是只能查看资源对资源进行分类，前者只能进行 GET 请求，后者可以使用 POST、PUT 和/或 DELETE&lt;/li&gt;
&lt;li&gt;没用孤岛。所有资源的 representations 应该通过超链接联系起来

&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;最后看点 &lt;a href="http://bitworking.org/projects/wsgicollection/"&gt;代码&lt;/a&gt; 吧&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-2229829399780924620?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/2229829399780924620/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=2229829399780924620' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2229829399780924620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/2229829399780924620'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/10/rest-web.html' title='REST，让 web 变得更美好！'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-3757073678978506380</id><published>2006-10-19T10:15:00.000+08:00</published><updated>2006-10-19T11:05:43.844+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Be Pythonic</title><content type='html'>&lt;a href="http://cafepy.com/article/59/"&gt;Be Pythonic&lt;/a&gt;
&lt;a href="http://faassen.n--tree.net/blog/view/weblog/2005/08/06/0"&gt;What is Pythonic&lt;/a&gt;
&lt;a href="http://dirtsimple.org/2004/12/python-is-not-java.html"&gt;Python is not Java&lt;/a&gt;
&lt;a href="http://www.jorendorff.com/articles/python/path/"&gt;path&lt;/a&gt; 操纵文件系统的 pythonic 的做法&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-3757073678978506380?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/3757073678978506380/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=3757073678978506380' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3757073678978506380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/3757073678978506380'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/10/be-pythonic.html' title='Be Pythonic'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-8859556822170058204</id><published>2006-10-17T09:56:00.001+08:00</published><updated>2006-10-17T10:13:58.936+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>I'm back!</title><content type='html'>回家了个把月，也离开了网络个把月。
gmail里几百封邮件和google reader里几百篇文章不知道要看到什么时候咯 = =

回学校的火车上认识了一个14岁的小家伙，一个人逃票坐火车，才念初一就说不想读书了，成天泡网吧，还是包间，5元/小时！除了玩游戏就是视频聊天。哎，想当初我念初一的时候还不知道电脑是个啥样子呢。

网络也害人啊！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-8859556822170058204?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/8859556822170058204/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=8859556822170058204' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8859556822170058204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8859556822170058204'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/10/im-back.html' title='I&apos;m back!'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-5076086577020428142</id><published>2006-09-19T11:28:00.000+08:00</published><updated>2006-09-19T11:58:14.877+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='IronPython'/><category scheme='http://www.blogger.com/atom/ns#' term='dotnet'/><title type='text'>compatibility of IronPython</title><content type='html'>IronPython 1.0 的发布，在邮件列表中引起了很多&lt;a href="http://groups.google.com/group/python-cn/browse_thread/thread/7c120e7546c9c83f/cb4659efddf9f432#cb4659efddf9f432"&gt;争论&lt;/a&gt; ，有的人担心 IronPython 会污染了 CPython 标准的纯洁，也有人希望 IronPython 的兴起会给 Python 社区注入新的力量。
而在我看来，这些争论归根到底，就是一个兼容性的问题。在 .net 程序员看来，它是 IronPython 和 .net 的兼容性，和其它 .net 程序的互操作性如何；而在 python 程序员看来，它就是 IronPython 和 CPython 的兼容性了，和 其它 python 程序互操作性如何。

在 IronPython 与 CPython 2.4.3 的兼容性问题上，有这么一份详细的比较文档 &lt;a href="http://www.codeplex.com/WorkItem/WorkItemFileAttachmentDownload.aspx?ProjectName=IronPython&amp;WorkItemId=2702&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;FileAttachmentId=868"&gt;官网下载&lt;/a&gt; &lt;a href="http://wiki.woodpecker.org.cn/moin/huangyi?action=AttachFile&amp;do=get&amp;amp;target=ironpython-differences4.htm"&gt;啄木鸟下载&lt;/a&gt; 。其中除了众多细小的区别外，在我看来比较重要的几点有：

&lt;p class="MsoNormal"&gt;Some CPython built-in extension modules do not exist in IronPython:&lt;/p&gt;&lt;table class="MsoNormalTable" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; WIDTH: 99pt; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="132"&gt;&lt;p class="MsoNormal"&gt;_bisect&lt;/p&gt;&lt;p class="MsoNormal"&gt;_codecs_hk&lt;/p&gt;&lt;p class="MsoNormal"&gt;audioop&lt;/p&gt;&lt;p class="MsoNormal"&gt;_multibytecodec&lt;/p&gt;&lt;p class="MsoNormal"&gt;parser&lt;/p&gt;&lt;p class="MsoNormal"&gt;array&lt;/p&gt;&lt;p class="MsoNormal"&gt;msvcrt&lt;/p&gt;&lt;p class="MsoNormal"&gt;_codecs_kr&lt;/p&gt;&lt;/td&gt;&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: medium none; WIDTH: 1.5in; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="144"&gt;&lt;p class="MsoNormal"&gt;_heapq&lt;/p&gt;&lt;p class="MsoNormal"&gt;_codecs_jp&lt;/p&gt;&lt;p class="MsoNormal"&gt;imageop&lt;/p&gt;&lt;p class="MsoNormal"&gt;mmap&lt;/p&gt;&lt;p class="MsoNormal"&gt;_subprocess&lt;/p&gt;&lt;p class="MsoNormal"&gt;_codecs_tw&lt;/p&gt;&lt;p class="MsoNormal"&gt;regex&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: medium none; WIDTH: 1.5in; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="144"&gt;&lt;p class="MsoNormal"&gt;zipimport&lt;/p&gt;&lt;p class="MsoNormal"&gt;xxsubtype&lt;/p&gt;&lt;p class="MsoNormal"&gt;_codecs_cn&lt;/p&gt;&lt;p class="MsoNormal"&gt;md5&lt;/p&gt;&lt;p class="MsoNormal"&gt;_codecs_iso2022&lt;/p&gt;&lt;p class="MsoNormal"&gt;rgbimg&lt;/p&gt;&lt;p class="MsoNormal"&gt;_csv&lt;/p&gt;&lt;/td&gt;&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: medium none; WIDTH: 95.4pt; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="127"&gt;&lt;p class="MsoNormal"&gt;signal&lt;/p&gt;&lt;p class="MsoNormal"&gt;_hotshot&lt;/p&gt;&lt;p class="MsoNormal"&gt;sha&lt;/p&gt;&lt;p class="MsoNormal"&gt;cmath&lt;/p&gt;&lt;p class="MsoNormal"&gt;_symtable&lt;/p&gt;&lt;p class="MsoNormal"&gt;_winreg&lt;/p&gt;&lt;p class="MsoNormal"&gt;strop&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p class="MsoNormal"&gt;The doctest module does not run in IronPython.
IronPython doesn’t support the select module.
IronPython has no os.system function. &lt;/p&gt;看来库的问题还是最大的，而且 CPython 中除了标准库还要那么多第三方的“事实上"的标准库！况且 .net 本身有那么一个庞大的库资源(包括官方的、第三方的等等)，也没有必要非得使用 CPython 的标准库了。

不管兼容问题如何，我都不同意所谓 IronPython 污染 Python 之类的说法。是说 IronPython 会让 本来的 python 程序员转向 IronPython 从而导致 Python 社区的分离吗？不管 IronPython 和 CPython 在语法上是如何的接近，让一个不了解 .net框架的 CPython 程序员转向 IronPython ，其难度怎么也算得上是学习半个语言了。因为这就是 .net ，.net框架 对多语言支持好，但实际上众多语言写出的 .net 程序都是一个模子里出来的。
所以 python 程序员的选择应该是很明确的：如果你需要在 .net框架下工作，那 IronPython 是你的不二选择，否则，就完全没有必要使用 IronPython 了，使用 CPython 还有个跨os平台的优势，何乐而不为呢。

至于 IronPython 和 .net 之间的问题应该不大，不是很清楚，也不想做评论。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-5076086577020428142?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/5076086577020428142/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=5076086577020428142' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5076086577020428142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5076086577020428142'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/compatibility-of-iconpython.html' title='compatibility of IronPython'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-5293128015959013624</id><published>2006-09-19T01:23:00.000+08:00</published><updated>2006-09-19T01:40:33.245+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>python is obvious !</title><content type='html'>初识 python 的时候常常会被一些陌生的概念绊倒，而当熟悉了这些概念之后你会发现它们原来是如此的简单明了！由于它们是如此的简单，所以我试图在&lt;font face="arial" size="3"&gt;*一*&lt;/font&gt;篇文章中就想把它们全部都介绍一遍。
&lt;ol&gt;&lt;li&gt;万物皆对象，甚至一个小小的整数也不例外；而变量只是一个名字，它可以绑定到任何一个对象；使用内置函数 id 可以查看绑定的对象的 id ，语言的实现会保证两个不同对象的 id 是绝对不一样的。
&lt;pre&gt;&gt;&gt;&gt; a = 1
&gt;&gt;&gt; id(a)
11541872
&gt;&gt;&gt; a = 2
&gt;&gt;&gt; id(a)
11541860
&gt;&gt;&gt; b=1
&gt;&gt;&gt; id(b)
11541872
&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;callable 对象
函数、方法、类、实现了 __call__ 方法的实例对象 都是 callable 对象。callable 的意思就是在后面写个括号直接就可以进行调用了。调用内置函数 callable 可以检验一个对象是否 callable 对象。
&lt;pre&gt;&gt;&gt;&gt; def check(obj):
...   if callable(obj):
...     obj(1,2)
...   else:
...     print 'not a callable'
...
&gt;&gt;&gt; def func(a,b):print a,b
...
&gt;&gt;&gt; class Temp(object):
...   def __init__(self,a,b):print a,b
...   def __call__(self,a,b):print a,b
...   def method(self,a,b):print a,b
...
&gt;&gt;&gt; check(func)
1 2
&gt;&gt;&gt; check(Temp)
1 2
&gt;&gt;&gt; t = Temp(1,2)
1 2
&gt;&gt;&gt; check(t)
1 2
&gt;&gt;&gt; check(t.method)
1 2
&gt;&gt;&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;参数传递机制
&lt;pre&gt;&gt;&gt;&gt; def a_func(a,b,c=1,d=2):print a,b,c,d
...
&gt;&gt;&gt; a_func(1,2,d=4,c=3)
1 2 3 4
&gt;&gt;&gt; a_func(1,2,3,d=4)
1 2 3 4
&gt;&gt;&gt; a_func(1,2)
1 2 1 2
&gt;&gt;&gt; args = (1,2)
&gt;&gt;&gt; kw = dict(c=3,d=4)
&gt;&gt;&gt; a_func(*args, **kw)
1 2 3 4
&gt;&gt;&gt; def a_func(*args, **kw):
...   print args
...   print kw
...
&gt;&gt;&gt; a_func(1,2,d=4,c=3)
(1, 2)
{'c': 3, 'd': 4}
&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;docorate
一个装饰就是一个接受一个函数作为参数的函数，它返回的还是一个函数。
好像有点绕口，还是让代码说话吧：
&lt;pre&gt;&gt;&gt;&gt; def simple_log(func):
...   def new_func(*arg, **kw):
...     print 'enter',func.func_name
...     func(*arg, **kw)
...     print 'exit',func.func_name
...   return new_func
...
&gt;&gt;&gt; def log(some_args):
...   def simple_log(func):
...     def new_func(*arg, **kw):
...       print some_args,'enter',func.func_name
...       func(*arg, **kw)
...       print some_args,'exit',func.func_name
...     return new_func
...   return simple_log
...
&gt;&gt;&gt; def a_func(a,b):print a,b
...
&gt;&gt;&gt; simple_log(a_func)(1,2)
enter a_func
1 2
exit a_func
&gt;&gt;&gt; @simple_log
... def a_func(a,b):print a,b
...
&gt;&gt;&gt; a_func(1,2)
enter a_func
1 2
exit a_func
&gt;&gt;&gt; log('haha')(a_func)(1,2)
haha enter a_func
1 2
haha exit a_func
&gt;&gt;&gt; @log('haha')
... def a_func(a,b):print a,b
...
&gt;&gt;&gt; a_func(1,2)
haha enter a_func
1 2
haha exit a_func&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;new style class
继承自 object 的都是 new style class，详细内容参考&lt;a href="http://wiki.woodpecker.org.cn/moin/PyNewStyleClass"&gt;这里&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;__new__
&lt;a href="http://wiki.woodpecker.org.cn/moin/PyNewStyleClass#head-ab6da7c43d316bb21a960b290996b827d7e5d5d1"&gt;参考&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;staticmethod, classmethod
&lt;a href="http://wiki.woodpecker.org.cn/moin/PyNewStyleClass#head-4e99fac86c5d061c0e30c7e3d10c21aa20d5d7f7"&gt;参考&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;metaclass
&lt;a href="http://wiki.woodpecker.org.cn/moin/MetaClassInPython"&gt;参考&lt;/a&gt;
实例对象由 class 构造而成，而 class 便是由 metaclass 构造而成。
简单地说一个 metaclass 就是一个接受三个参数（class的名字，基类tuple，class 的属性字典）的 callable 对象，它返回一个 class 。在构建 class 的时候便会调用这个 callable 对象，并使用它返回的 class 。
所有内建类型的 metaclass 和 new style class 默认的 metaclass 都是 &lt;font style="FONT-WEIGHT: bold; FONT-STYLE: italic"&gt;type&lt;/font&gt;
&lt;pre&gt;&gt;&gt;&gt; def meta(name, bases, classdict):
...   print name
...   print bases
...   print classdict
...   return type(name, bases, classdict)
...
&gt;&gt;&gt; class Temp(object):
...   __metaclass__ = meta
...   a = 1
...   def b():pass
...
Temp
(&amp;lt;type 'object'&amp;gt;,)
{'a': 1, '__module__': '__main__', 'b': &amp;lt;function b at 0x00BD5670&amp;gt;, '__metaclass
__': &amp;lt;function meta at 0x00BCEE30&amp;gt;}
&gt;&gt;&gt; class ATemp(Temp):
...   __metaclass__ = meta
...
ATemp
(&amp;lt;class '__main__.Temp'&amp;gt;,)
{'__module__': '__main__', '__metaclass__': &amp;lt;function meta at 0x00BCEE30&amp;gt;}&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;
暂时只想到这些，当然遗漏在所难免了，如有任何意见，欢迎评论 :)

update [2006-9-21]:
结合 callable 和 docorate ，其实 docorate 那个 log 的例子还可以这么写，似乎更好读一些：
&lt;pre&gt;&gt;&gt;&gt; class log(object):
...   def __init__(self, someargs):
...     self.args = someargs
...   def __call__(self,func):
...     def new_func(*args,**kw):
...       print self.args,'enter',func.func_name
...       func(*args,**kw)
...       print self.args,'exit',func.func_name
...     return new_func
...
&gt;&gt;&gt; @log('haha')
... def a_func(a,b):print a,b
...
&gt;&gt;&gt; a_func(1,2)
haha enter a_func
1 2
haha exit a_func&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-5293128015959013624?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/5293128015959013624/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=5293128015959013624' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5293128015959013624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/5293128015959013624'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/python-is-obvious.html' title='python is obvious !'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-8925149840047228147</id><published>2006-09-16T22:01:00.001+08:00</published><updated>2006-09-16T22:01:55.103+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>意外收获：get_caller</title><content type='html'>阅读 &lt;a href="http://codeplayer.blogspot.com/2006/09/ply-lexyacc.html"&gt;PLY&lt;/a&gt; 的 lex.py 的时候，看到这么一段代码 （line：449）：
&lt;pre&gt;try:
  raise RuntimeError
except RuntimeError:
  e,b,t = sys.exc_info()
  f = t.tb_frame
  f = f.f_back           # Walk out to our calling function
  ldict = f.f_globals    # Grab its globals dictionary
&lt;/pre&gt;哈哈，这种用法还真是前所未见（也许是见识还不够吧）！自己抛出异常自己捕捉，然后就可以访问到 frame stack 了！那还不无法无天了啊，呵呵。

你可以在这个 frame stack 中前后移动，这样你可以获得调用者的信息：比如 f_globals、f_locals、f_builtins、f_code 等，你还可以获得调用者的调用者的信息，你还可以获得 ... 。

而且获得了调用者的字节码（ f_code ）之后，你还可以直接把它再执行一遍！
&lt;pre&gt;import sys

count = 0

def get_caller():
   global count
   try:
       raise RuntimeError
   except RuntimeError:
       e,b,t = sys.exc_info()
       f = t.tb_frame
       f = f.f_back
       count += 1
       print count
       eval(f.f_code, f.f_globals, f.f_locals)

def caller():
   get_caller()

if __name__=='__main__':
   caller()
&lt;/pre&gt;大家还有什么变态的想法，尽管留言哈 ^_^ .


另外，查看 sys.exc_info 的文档时候，看到有一个警告，大意是说 sys.exc_info() 返回的那个 traceback 对象( 返回的 tuple 中第三个)，最好不要赋值给当前捕捉到异常的这个函数的局部变量，如果你不需要用到 traceback 对象的话可以这么干：
&lt;pre&gt;exctype, value = sys.exc_info()[:2]
&lt;/pre&gt;如果你确实需要使用这个对象，那你最好用完后 delete 掉这个变量，或者在另外开一个函数来调用 sys.exc_info()。
理由是将 traceback 对象赋值给当前函数的局部变量会产生引用循环，而这个东西是引用计数垃圾回收方式的软肋，python2.2 以前的版本它直接就会导致内存泄露了，虽然随后版本的gc能搞定引用循环问题，不过考虑到效率，最好还是不要创建引用循环了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-8925149840047228147?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/8925149840047228147/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=8925149840047228147' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8925149840047228147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/8925149840047228147'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/getcaller.html' title='意外收获：get_caller'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-6287921785874717893</id><published>2006-09-16T20:37:00.001+08:00</published><updated>2006-09-16T20:37:15.504+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='compiler'/><category scheme='http://www.blogger.com/atom/ns#' term='ply'/><title type='text'>PLY: 一个以教学为目的的lex、yacc实现</title><content type='html'>&lt;a href="http://www.dabeaz.com/ply/"&gt;官方网站&lt;/a&gt;
想学或正在学编译原理的同学可不要错过了，要是上个学期我就看到了它的话，我的编译原理课也不至于考得这么糟糕吧。 = =|||
现在突然又涌起研究下编译原理的冲动，谁知道能持续多久呢。
不过现在实现一门语言的关键技术还在虚拟机上，编译器的技术已经太成熟了！
不过原理呢还是懂点为好，不是吗  :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-6287921785874717893?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/6287921785874717893/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=6287921785874717893' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6287921785874717893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/6287921785874717893'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/ply-lexyacc.html' title='PLY: 一个以教学为目的的lex、yacc实现'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-84924619127998539</id><published>2006-09-14T15:19:00.001+08:00</published><updated>2006-09-14T15:19:37.120+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>laying out an application</title><content type='html'>好文推荐：&lt;a href="http://www.b-list.org/weblog/2006/09/10/django-tips-laying-out-application" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt;&lt;span&gt;Django tips: laying out an application&lt;/span&gt;&lt;/a&gt;

我想这篇文章能帮助你对 django 有个全面的理解。

它对 project 和 app 的区别，和 django 中对 project 和 app 代码布局的约定有很详细的讲解，这些知识对于编写可重用可扩展的 app ，或是整合定制扩展第三方的 app 都是必不可少的。

其中还花费了一些笔墨介绍了 django 的一个很有意思的机制 signal 。它允许应用程序可以通过监听 signal ，在某些事件发生的时候获得通知并执行特点代码，并且 app 也可以编写自己的 signal。这个机制使得 app 的某些代码可以“侵入”核心框架和其他 app 的执行过程中，对于 app 的重用性是大有裨益啊!

文章剩下的部分还介绍了其他一些不成文的代码组织规范。

希望这些东西对你有用 ^_^&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-84924619127998539?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://codeplayer.blogspot.com/2006/09/laying-out-application.html' title='laying out an application'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/84924619127998539/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=84924619127998539' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/84924619127998539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/84924619127998539'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/laying-out-application.html' title='laying out an application'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-209200960966706564</id><published>2006-09-14T14:52:00.001+08:00</published><updated>2006-09-14T14:52:48.373+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>django 的 contribs 之 comments</title><content type='html'>comments ，顾名思义，它是用来处理用户评论的。

托 &lt;a href="http://codeplayer.blogspot.com/2006/09/django-contribs-contenttype.html"&gt;contenttypes &lt;/a&gt;的福，它可以处理对任意 model 的评论！是一个通用的 comment 框架！并且它自带有相关的urls配置、templates、templatetags、控制器，可以很方便地将它们整合到项目中来。

comments 框架围绕两个关键 model 分成相对独立的两部分：Comment 和 FreeComment ，前者是一个相当复杂的评论系统，包括reviews, ratings, attached images, reputation over time, flagging of potentially bad content, user bans and groups of moderators who can remove comments 等许多功能！后者是个简单的版本，只有一些基本的评论的功能。

关于 FreeComment 部分已经有一些不错的文档了：&lt;a href="http://code.djangoproject.com/wiki/UsingFreeComment" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt;&lt;span&gt;Using Django's Free Comments &lt;/span&gt;&lt;/a&gt; ，&lt;a href="http://www.b-list.org/weblog/2006/07/16/django-tips-hacking-freecomment" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt; &lt;span&gt;Django tips: Hacking FreeComment&lt;/span&gt;&lt;/a&gt; 。

Comment 部分虽然功能多一些，不过结合对 FreeComment 使用方法的介绍和对代码的阅读，应该搞清楚也不是难事，也许有时间有机会会去仔细研究一下。

&lt;a href="http://code.djangoproject.com/wiki/UsingFreeComment" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt; &lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-209200960966706564?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/209200960966706564/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=209200960966706564' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/209200960966706564'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/209200960966706564'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/django-contribs-comments.html' title='django 的 contribs 之 comments'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-115803874658170697</id><published>2006-09-12T13:25:00.000+08:00</published><updated>2006-09-12T13:25:46.803+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Rails/Django comparison synopsis</title><content type='html'>&lt;a href="http://groups.google.com/group/django-users/browse_thread/thread/c59a3b4e1fb9cae7/4621f580a6386c02#4621f580a6386c02"&gt;&lt;span class="fontsize5"&gt;Rails/Django comparison synopsis (a BIG summary)&lt;/span&gt;&lt;/a&gt; &lt;br&gt;&lt;br&gt; 这是 django 邮件列表中的一个帖子，收集了一些比较 rails/django 的观点。&lt;br&gt;当然几乎所有人都强调的一点就是，django 和 ror 是非常相似的。&lt;br&gt;不过也许是因为 django 社区中的缘故，似乎说 django 好话的多些。&lt;br&gt;总结一下他们的意见，django 表现得好的方面主要有：&lt;br&gt;&lt;ul&gt;&lt;li&gt;灵活的app，&lt;br&gt;"If you're creating a single monolithic application, Rails is pretty sweet."  &lt;br&gt;"With Django you can build an app, put it on the server somewhere, and for as many sites (projects) as you like you can pull in that app, skin it and use it."&lt;/li&gt;&lt;li&gt;部署，通过 mod_python 部署在 apache 上&lt;/li&gt;&lt;li&gt;文档，虽然 ror 有一本好书，不过站点上的文档比较糟糕 &lt;/li&gt;&lt;li&gt;模版语言，这个主要看个人爱好，不过似乎多数人偏爱 django 的方式&lt;br&gt; &lt;/li&gt;&lt;li&gt;admin 界面&lt;/li&gt;&lt;/ul&gt;django 做得不好的地方：&lt;br&gt;&lt;ul&gt;&lt;li&gt;admin 界面还不够灵活&lt;/li&gt;&lt;li&gt;没有内置 ajax 支持&lt;/li&gt;&lt;/ul&gt;当然，我对 ror 的了解有限，各位有何意见大可留言回复，非常欢迎 ^_^&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-115803874658170697?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/115803874658170697/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=115803874658170697' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115803874658170697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115803874658170697'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/railsdjango-comparison-synopsis.html' title='Rails/Django comparison synopsis'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-115799749036125672</id><published>2006-09-12T01:48:00.000+08:00</published><updated>2006-09-12T02:07:49.936+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='framework'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='pocoo'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Pocoo: 半个框架</title><content type='html'>xiaoping.tang 兄向我推荐这个&lt;a href="http://www.pocoo.org/"&gt;论坛程序&lt;/a&gt;，说它写得不错。我于是下了代码来研究了一下，发现它确实有点意思。这是个&lt;a href="http://flying.circus.pocoo.org"&gt;demo&lt;/a&gt;。
与其说它是个应用程序，不如说它是半个web框架，想必从中抽取出一个完整的框架也不是什么难事。

模版：&lt;a href="http://wsgiarea.pocoo.org/"&gt;jinja&lt;/a&gt;（独立后的 django 模版），orm：&lt;a href="http://www.sqlalchemy.org/"&gt;sqlalchemy&lt;/a&gt;，基于&lt;a href="http://www.wsgi.org/"&gt;WSGI&lt;/a&gt;。
而我认为其中最有特色的部分还在 package 的配置管理这一块，它的整个系统都建立在这个机制之上。而这个论坛程序只是这个机制下面一个叫做 core 的 plugin 而已。这一块让我联想起稍微接触过一下的zope3。
它的配置文件的语法就挺有意思，很像 python ：
&lt;pre&gt;components = list:
   db.CoreTableObserver
   captcha.CaptchaImage
   session.SessionWrapper
   pages.IndexPage&lt;/pre&gt;一个 package 只是一个普通的 python 包，不过下面可以放个配置文件描述包中的内容，分这么几类：components、tables、template_tags、 template_filters、middlewares。在初始化时按照配置文件指示加载并初始化这些东西，将所有包的内容分门别类放在一起进行统一管理。pocoo/pkg/core/package.conf 便是 core 的配置文件。

&lt;span style="font-weight: bold;"&gt;components&lt;/span&gt; 范围比较广，只要它是 Component 的子类的子类即可。Component 的直接子类可以看作是实际组件的抽象基类，并不能直接当作组件使用。组件必须继承自这些抽象基类。框架会将组件按照其基类进行分类管理。
我看到在 core 中有这么几个 component 的类型：
&lt;ul&gt;&lt;li&gt;RequestWrapper：将 request 对象交给 RequestHandler 之前交给它们处理一遍先，cache、session等就是以这种方式实现 &lt;/li&gt;&lt;li&gt;RequestHandler：这就是我们熟悉的控制器了，处理请求并返回内容，每一个 RequestHandler 都有一个 handler_regexes 的属性，指定匹配 url 的正则表达式，类似 django ，&lt;/li&gt;&lt;li&gt;RemoteCallable：处理 web服务 的请求，&lt;/li&gt;&lt;li&gt;AuthProvider：提供用户验证的组件，&lt;/li&gt;&lt;li&gt;PostProcessor ：对帖子进行处理，&lt;/li&gt;&lt;li&gt;DatabaseObserver：在创建数据表的前后进行一些处理，&lt;/li&gt;&lt;/ul&gt;等等。
&lt;span style="font-weight: bold;"&gt;tables&lt;/span&gt; 便是 package 使用到的 sqlalchemy 的 Table，Pocoo 对 sqlalchemy 进行了一层封装，还没仔细看。
&lt;span style="font-weight: bold;"&gt;template_tags、template_filters&lt;/span&gt; 是 jinja 模版的东西。
&lt;span style="font-weight: bold;"&gt;middlewares&lt;/span&gt; 便是 WSGI 中间件！

ps:&lt;a href="http://flying.circus.pocoo.org/pony/plugins/"&gt;这里&lt;/a&gt;列出了&lt;a href="http://flying.circus.pocoo.org"&gt;demo&lt;/a&gt;站安装的所有package  ，这个功能本身也是通过一个package来实现的:)  -- update [2006-9-12]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-115799749036125672?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://codeplayer.blogspot.com/2006/09/pocoo.html' title='Pocoo: 半个框架'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/115799749036125672/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=115799749036125672' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115799749036125672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115799749036125672'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/pocoo.html' title='Pocoo: 半个框架'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-115789685843511214</id><published>2006-09-10T21:57:00.000+08:00</published><updated>2006-09-10T22:50:24.806+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='stackless'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>usable stackless</title><content type='html'>所谓士别三日当刮目相看，有一段时间没有注意看 StacklessPython 的邮件列表了，没想到现在 &lt;a onclick="return top.js.OpenExtLink(window,event,this)" href="http://svn.python.org/projects/stackless/sandbox" target="_blank"&gt;sandbox&lt;/a&gt; 中已经有了这么多有意思的代码了 ^_^ 。
最有意思的莫过于 examples/stacklesssocket.py 了，只要把标准库中的 socket 替换成stacklesssocket，然后使用 urllib 就自动成为异步的和StacklessPython兼容的。演示程序如下(摘自StacklessPython邮件列表)：

&lt;pre&gt;import sys
import stacklesssocket
import stackless

sys.modules["socket"] = stacklesssocket

import urllib
import time

def download(uri):
    t1 = time.time()
    f = urllib.urlopen(uri)
    s = f.read()
    t2 = time.time()
    print "Downloaded", uri, "in", "%.1f" % (t2-t1), "seconds"
    return t2-t1


print " === Serial === "
t1 = time.time()
download("http://www.stackless.com/wiki/Tasklets")
download("http://www.stackless.com/wiki/Channels")
t2 = time.time()
print " ---&gt;", t2-t1

print " === Parallel === "
t1 = time.time()
stackless.tasklet(download)("http://www.stackless.com/wiki/Tasklets")
stackless.tasklet(download)("http://www.stackless.com/wiki/Channels")
stackless.run()
t2 = time.time()
print " ---&gt;", t2-t1&lt;/pre&gt;效果：

&lt;pre&gt;% spython async_fetch.py
 === Serial ===
Downloaded http://www.stackless.com/wiki/Tasklets in 2.6 seconds
Downloaded http://www.stackless.com/wiki/Channels in 2.7 seconds
 ---&gt; 5.34717988968
 === Parallel ===
Downloaded http://www.stackless.com/wiki/Channels in 4.0 seconds
Downloaded http://www.stackless.com/wiki/Tasklets in 5.4 seconds
 ---&gt; 5.43875193596

% spython async_fetch.py
 === Serial ===
Downloaded http://www.stackless.com/wiki/Tasklets in 2.6 seconds
Downloaded http://www.stackless.com/wiki/Channels in 2.7 seconds
 ---&gt; 5.32963705063
 === Parallel ===
Downloaded http://www.stackless.com/wiki/Channels in 2.2 seconds
Downloaded http://www.stackless.com/wiki/Tasklets in 2.7 seconds
 ---&gt; 2.71087312698&lt;/pre&gt;
还有 examples/threadchannels.py ，examples/threadscheduling.py 演示了 Stackless 如何与多线程一起使用！

还有更新过的 uthread 模块：libraries/uthread-ccp/uthread.py，这可是大名鼎鼎的 EVE-online 用到的东西哦 ^_^

有时间再好好研究研究这些东西吧!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-115789685843511214?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://codeplayer.blogspot.com/2006/09/usable-stackless.html' title='usable stackless'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/115789685843511214/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=115789685843511214' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115789685843511214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115789685843511214'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/usable-stackless.html' title='usable stackless'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-115786308844833414</id><published>2006-09-10T12:37:00.000+08:00</published><updated>2006-09-10T22:02:38.650+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>django 的 contribs 之 contenttype</title><content type='html'>上一篇blog介绍到了那个 &lt;a href="http://svn.sourceforge.net/svnroot/django-userlibs/trunk/libs.dojo/examples/"&gt;repository&lt;/a&gt; ，其中 &lt;a href="https://svn.sourceforge.net/svnroot/django-userlibs/trunk/libs.common/src/common/mptt/models.py"&gt;trunk/libs.common/src/common/mptt/models.py&lt;/a&gt; 里有一个很有意思的叫做 Node 的 model。实现了一个叫 &lt;a href="http://www.sitepoint.com/print/hierarchical-data-database"&gt;Modified Preorder Tree Traversal &lt;/a&gt;的算法，相关内容还可以参考 &lt;a href="http://code.djangoproject.com/wiki/ModifiedPreorderTreeTraversal"&gt;这个&lt;/a&gt; 页面。

算法细节刚才链接到的文章都讲得很详细了，吸引我注意的是代码中两个陌生的词语：ContentType, GenericForeignKey。django 文档中 model-api 中对 GenericForeignKey 完全没有涉及，add_ons 中对 contenttype 的描述也只有简单的一句：

&lt;blockquote style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;" class="gmail_quote"&gt;A light framework for hooking into "types" of content, where each installed
Django model is a separate content type. This is not yet documented.
&lt;/blockquote&gt;
通过 google 也只搜到了这么 &lt;a href="http://feh.holsman.net/articles/2006/06/03/django-contenttype"&gt;一篇文章&lt;/a&gt; ，也只是泛泛而谈而已。经过研究，越发地感觉有意思了，于是写下心得，这么有意思的东西被埋没了可真可惜。

简单得说，ContentType 就是一个 model，也就是一张数据表，其中保存着当前 project 中所有 models 的元数据，具体就是 name、app_label 和 model 三个字段，其中 app_label 和 model 这两个字符串组合起来便可以唯一标识一个 model 。通过调用 django.db.models.get_model(app_label, model) 就可以获得该 model 类。

这样一个奇怪的 model 会有什么用处呢？可以设想一下，如果你需要一个和任意 model 都建立有关系的 model 时，你会怎么做？比如：用户评论！ 假设你的 project 中有电影、有文章、有音乐等等内容，它们分别对应不同的 model ，而用户对它们每一种内容都可以进行评论，那么最简单的做法就是为每一种内容建立相应的评论表，比如：movie_comments, article_comments 等。不过这种做法的弊端是很明显的：首先是增加了 model 的数量也增加了代码的复杂度；而且没有扩展性，增加其他内容的话还需要增加相应的 comments 表；还有就是统计用户所有评论的时候比较麻烦，需要在多个表中进行查询。

要是我们有了一个记录了项目中所有 model 的元数据的表，表中一条记录便对应着一个 model ，那么我们只要通过一个元数据表的 id 和 一个具体数据表中的 id ，便可以找到任何 model 中的任何记录。ContentType 正是这个表（不过有个前提就是：相关 model 的主键类型必须是相同的，使用django默认的主键就ok了）。

有了 ContentType ，我们的用户评论就只需要一个 model 就可以搞定！

下面开始介绍具体做法吧，首先通过执行以下命令
&gt;django-admin.py startproject ContentType
创建一个 project。
然后修改 settings.py ，配置合适的数据库后端。
然后通过
&gt;cd ContentType
&gt;manage.py startapp contents
创建一个 app，修改 contents/models.py 如下：
&lt;pre&gt;from django.db import models
from django.contrib.contenttypes.models import ContentType

class Movie(models.Model):
   title = models.CharField(maxlength=100)

class Article(models.Model):
   title = models.CharField(maxlength=100)

class Music(models.Model):
   title = models.CharField(maxlength=100)

class Comment(models.Model):
   content_type = models.ForeignKey(ContentType)
   object_id = models.IntegerField()
   content_object = models.GenericForeignKey()
   title = models.CharField(maxlength=100)&lt;/pre&gt;然后在 settings.py 的 INSTALLED_APPS 中加入：
"ContentType.contents",
执行命令:
&gt;manage.py syncdb
然后执行：
&gt;manage.py shell
现在就可以好好地享受享受劳动果实了。
&lt;pre&gt;&gt;&gt;&gt; from ContentType.contents.models import *
&gt;&gt;&gt; a = Article()
&gt;&gt;&gt; a.title = 'article1'
&gt;&gt;&gt; a.save()
&gt;&gt;&gt; m = Movie()
&gt;&gt;&gt; m.title = 'movie1'
&gt;&gt;&gt; m.save()
&gt;&gt;&gt; mu = Music()
&gt;&gt;&gt; mu.title = 'music1'
&gt;&gt;&gt; mu.save()
&gt;&gt;&gt; c = Comment()
&gt;&gt;&gt; c.content_object = a
&gt;&gt;&gt; c.title = 'comment1'
&gt;&gt;&gt; c.save()
&gt;&gt;&gt; c = Comment()
&gt;&gt;&gt; c.content_object = m
&gt;&gt;&gt; c.title = 'comment2'
&gt;&gt;&gt; c.save()
&gt;&gt;&gt; c = Comment()
&gt;&gt;&gt; c.content_object = mu
&gt;&gt;&gt; c.title = 'comment3'
&gt;&gt;&gt; c.save()
&gt;&gt;&gt; for c in Comment.objects.all():
...   print c.content_type,c.object_id
...
article 1
movie 1
music 1
&gt;&gt;&gt; c.content_object.title
'music1'&lt;/pre&gt;还有一个值得提一下的地方就是 Comment 的 content_object 字段。实际上根据上面的解释它只要有 content_type 和 object_id 两个字段就够了，不过你总是需要亲自指定两个字段的值。而 GenericForeignKey 出现的目的就是要把这个过程给自动化了，只要给 content_object 赋一个对象，就会自动得根据这个对象的元数据 ，给 content_type 和 object_id 赋值了。
GenericForeignKey 的构造函数接受两个可选参数：
 def __init__(self, ct_field="content_type", fk_field="object_id"):
你可以在构造 GenericForeignKey 时指定另外的字段名称。

另外还有值得注意的一点就是：contenttype 的表是在 syncdb 时创建的，不过一开始其中并没有元数据，其中的数据是在需要的时候才添加上去的，正如你所想的，它使用的是get_or_create方法。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-115786308844833414?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://codeplayer.blogspot.com/2006/09/django-contribs-contenttype.html' title='django 的 contribs 之 contenttype'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/115786308844833414/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=115786308844833414' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115786308844833414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115786308844833414'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/django-contribs-contenttype.html' title='django 的 contribs 之 contenttype'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-115785998184017369</id><published>2006-09-10T11:46:00.000+08:00</published><updated>2006-09-10T11:53:36.016+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>django apps repository！</title><content type='html'>最近django的邮件列表热烈讨论一个叫做 apps repository 的东西。就是建立一个保存用户提交的 app 的统一的存储中心。&lt;br&gt;&lt;br&gt;我想这么一个东西的存在一定程度上是直接得益于 django 的一些优秀的设计：&lt;br&gt;&lt;br&gt;在 django 中一个 project 由多个 app 组成，一个 app 由相关的 urls、views、models、templates、templatetags(自定义的模版标签) 等组成，一个 app 就是一个文件夹，一个包，一个重用单位。而 pylons 等框架是将所有 controllers (对应django的views) 放一处、 所有 models 放一处、所有 templates 放一处。相比之下，django 提供一个相对 project 更小粒度的 app 成为重用的最小单元，使得代码重用变得更为方便。 &lt;br&gt;&lt;br&gt;这样一个好机制其实是得益于 django 中许多细节上的设计的，比如 url dispatcher 的 include 机制，使 app 可以独立设计自己的 urls ；灵活的可扩展的 template 加载机制使 app 可以和自己的模版、自定义模版标签一起分发；...；最后还有最重要的一点原因就是：django &amp;quot;一块式&amp;quot; 的设计哲学。因为这些便利都是基于一个前提的，那就是：这些 app 使用着同一套url dispatcher，同一套模版引擎，同一套 orm 等。 &lt;br&gt;&lt;br&gt;目前 django 代码里面 contrib 目录下那些东西，就是些可重用的 app 。 简单如 sites 的，只有一个 models(和相关的managers)； 更复杂一些如 comments 的，便连 views、templates 也都有了；还有庞大如 admin 的，甚至连自己的 urls 都有了！&lt;br&gt;&lt;br&gt;貌似目前还没有推出正式的 django apps repository 吧，倒是有个兄弟公开了自己一个私有的repository： &lt;br&gt;&lt;a onclick="return top.js.OpenExtLink(window,event,this)" href="http://svn.sourceforge.net/svnroot/django-userlibs/" target="_blank"&gt;http://svn.sourceforge.net/svnroot/django-userlibs&lt;/a&gt;&lt;br&gt;虽然数量还不多，不过还是有了一些很有意思的代码了 :) &lt;br&gt;&lt;br&gt;希望正式的 repository 快快建立起来，希望用 app 组装 project 的日子快快到来吧！&lt;br&gt;&lt;br&gt;ps：据说 ror 有个 plugin 的东西，不知是什么样的一个机制，希望有了解的朋友也介绍介绍吧. ^_^&lt;br&gt; &lt;a href="http://codeplayer.blogspot.com/" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"&gt; &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-115785998184017369?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://codeplayer.blogspot.com/2006/09/django-apps-repository.html' title='django apps repository！'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/115785998184017369/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=115785998184017369' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115785998184017369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115785998184017369'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/django-apps-repository.html' title='django apps repository！'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-115744434654874426</id><published>2006-09-05T16:19:00.000+08:00</published><updated>2006-09-05T16:30:21.373+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='stackless'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='continuation'/><title type='text'>使用 python2.5 中增强的 yield 模拟 StacklessPython</title><content type='html'>&lt;p class="line874"&gt;今天邮件列表里讨论 python2.5 中增强的 yield 特性，讨论得热火朝天。 &lt;span class="anchor" id="line-4"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-5"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="line862"&gt;顿觉心血来潮，就用这增强型的 yield 大致模拟了下 &lt;a class="nonexistent" href="http://www.stackless.com/"&gt; StacklessPython&lt;/a&gt; 的基本功能 。 &lt;span class="anchor" id="line-6"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-7"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="line874"&gt;虽然不能一模一样，不过感觉也只能做到这一步了。 &lt;span class="anchor" id="line-8"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-9"&gt; &lt;/span&gt;&lt;/p&gt;&lt;p class="line862"&gt;主要是因为相对 &lt;a class="nonexistent" href="http://www.stackless.com/"&gt;StacklessPython&lt;/a&gt; 来说 yield 有这么几个限制： &lt;span class="anchor" id="line-10"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-11"&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul&gt; &lt;li&gt;&lt;p class="line862"&gt;函数只能通过 yield 来挂起，这导致实现 &lt;a href="http://www.stackless.com/wiki/Channels"&gt;channel &lt;/a&gt;的时候只能通过  &lt;tt&gt;yield&amp;nbsp;command(c.send,&amp;nbsp;value)&lt;/tt&gt;，&lt;tt&gt;value&amp;nbsp;=&amp;nbsp;yield&amp;nbsp;command(c.receive)&lt;/tt&gt; 这样的语法来使当前 tasklet 挂起 (一定条件下) ，不像  &lt;a href="http://www.stackless.com/"&gt;StacklessPython &lt;/a&gt;直接 some_channel.send(...) 就有可能挂起当前 tasklet 。 &lt;span class="anchor" id="line-12"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;yield 只能向上一层，而不能直接 yield 到调用栈的最上层（或者甚至是指定 yield 到哪一层!!），这导致我们的 tasklet 只能在函数调用的第一层进行 yield 才能将执行权切换给调度程序，像下面:  &lt;span class="anchor" id="line-13"&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="line867"&gt;&lt;span class="anchor" id="line-14"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-15"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-16"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-17"&gt; &lt;/span&gt;&lt;span class="anchor" id="line-18"&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="codearea" dir="ltr" lang="en"&gt;   &lt;a href="http://wiki.woodpecker.org.cn/moin/huangyi/2006-09-05#" onclick="return togglenumber('CA-59f0aef051ede021ac78878ec817e0228e7f637e_000', 1, 1);" class="codenumbers"&gt;&lt;/a&gt; &lt;pre dir="ltr" id="CA-59f0aef051ede021ac78878ec817e0228e7f637e_000" lang="en"&gt;&lt;span class="line"&gt;&lt;span class="ResWord"&gt;def&lt;/span&gt; &lt;span class="ID"&gt;a_task&lt;/span&gt;&lt;span class="Operator"&gt;(&lt;/span&gt;&lt;span class="Operator"&gt;)&lt;/span&gt; &lt;span class="Operator"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="ID"&gt;a_func&lt;/span&gt;&lt;span class="Operator"&gt;(&lt;/span&gt;&lt;span class="Operator"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="ResWord"&gt;def&lt;/span&gt; &lt;span class="ID"&gt; a_func&lt;/span&gt;&lt;span class="Operator"&gt;(&lt;/span&gt;&lt;span class="Operator"&gt;)&lt;/span&gt;&lt;span class="Operator"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="Comment"&gt;# 在这个函数里是没用办法将执行权切换给调度程序的。&lt;/span&gt;&lt;span class="Text"&gt;&lt;/span&gt; &lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/div&gt;&lt;span class="anchor" id="line-19"&gt;&lt;/span&gt;&lt;p class="line862"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不像 &lt;a class="nonexistent" href="http://www.stackless.com/"&gt;StacklessPython&lt;/a&gt; ，随便哪里调用 stackless.schedule() 都可以把执行权交出去。 &lt;span class="anchor" id="line-20"&gt; &lt;/span&gt;&lt;span class="anchor" id="line-21"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="line874"&gt;谁叫人家c写的呢。:( &lt;span class="anchor" id="line-22"&gt;&lt;/span&gt;&lt;span class="anchor" id="line-23"&gt;&lt;/span&gt;&lt;/p&gt;本来想顺便把 &lt;a href="http://wiki.woodpecker.org.cn/moin/evolution"&gt; evolution&lt;/a&gt; 也转过来的，发现 &lt;a href="http://www.pygame.org/news.html"&gt;pygame &lt;/a&gt;还没为 windows 编译 python2.5 的版本，自己编译太麻烦，还是等 python2.5 正式发布了再说吧。&lt;br&gt;&lt;br&gt;具体代码请看 &lt;a href="http://wiki.woodpecker.org.cn/moin/huangyi/2006-09-05"&gt;http://wiki.woodpecker.org.cn/moin/huangyi/2006-09-05 &lt;/a&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-115744434654874426?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://codeplayer.blogspot.com/2006/09/python25-yield-stacklesspython.html' title='使用 python2.5 中增强的 yield 模拟 StacklessPython'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/115744434654874426/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=115744434654874426' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115744434654874426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115744434654874426'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/python25-yield-stacklesspython.html' title='使用 python2.5 中增强的 yield 模拟 StacklessPython'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-115733378983891370</id><published>2006-09-04T09:36:00.000+08:00</published><updated>2006-09-05T16:30:53.256+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='framework'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>python web 框架可真多!</title><content type='html'>python web 框架可真多！几乎所有比较python web框架和ruby web框架的时候都会提到这个现象。&lt;br&gt;最近几天我也基本上是钻在这一堆框架（和一堆评论比较的文章）里面度过的。&lt;br&gt;现在开学了，轻松了一天，似乎可以回过头来好好看看这个问题了。&lt;br&gt;首先我想产生众多框架的关键原因在于：开发一个新框架实在太简单了，而开发一个满足所有人需要和喜好的框架却是不可能的！&lt;br&gt;每个框架都有它的特色，都有它存在的理由。而当你稍微走近看的时候你会发现这些框架的结构是如此的相似，毕竟都逃不过mvc的框框。也有仁兄把这些个结构归纳为: url dispatcher,controller ( 就是django的view ) ,model,template.  &lt;br&gt;不光结构相似，使用到的组件也都是那么几个 python 模块，基本上都是可以轻松替换的。所以为什么说这些个才开发了几个月的web框架就已经如此的成熟，因为这些模块早已久经考验。&lt;br&gt;框架的差别基本只存在于细节，只存在于底层实现，只存在于对快速开发与灵活性之间的权衡。&lt;br&gt;&lt;br&gt;常用的组件都有哪些呢？不妨收集一下&amp;nbsp; :)&lt;br&gt;&lt;br&gt;1、url dispatcher：&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; django 的基于正则表达式的&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cherrypy 的基于 object publisher 的&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; routes 学 ror 的&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 还有 paste 的简单的 urlmap&lt;br&gt;&lt;br&gt;2、templating：&lt;br&gt;模板系统比较多，详细列表请看http://wiki.python.org/moin/Templating&lt;br&gt;我所知的几个比较常用的是：&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; django template system （简单易用，适合设计人员使用） &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; myghty （功能强大，基于组件）&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; kid （基于xml，对xml文档的生成相当自然）&lt;br&gt;&lt;br&gt;3、orm：&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sqlalchemy&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sqlobject&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; django orm&lt;br&gt;&lt;br&gt;另外python中还有webpy这类的"微型"框架，不熟悉，也就不敢多加评论了。&lt;br&gt;&lt;br&gt;而对于 ror vs python web frameworks 的争论，我感觉这种争论更多的是集中在ruby or python的争论上，框架本身区别并不大。而这两种语言区别其实也不大，争论更多集中在一些 features 的比较和美学观念上差异。而ruby 和 python 最大的观念的差别就是： &lt;br&gt;&lt;br&gt;ruby：there is more than one way to do it.&lt;br&gt;python：there should be one obvious way to do it.&lt;br&gt;&lt;br&gt;了。&lt;br&gt;不管怎么说百家争鸣是个好事，web框架如此，ruby和python的存在也是如此。具体选择取决于你自己了。&lt;br&gt;&lt;br&gt;------------------------------------&lt;br&gt;web框架详细列表： &lt;br&gt;&lt;br&gt;&amp;nbsp;&lt;a href="http://wiki.python.org/moin/WebFrameworks"&gt;http://wiki.python.org/moin/WebFrameworks&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;a href="http://wiki.woodpecker.org.cn/moin/PyWebFrameList"&gt;http://wiki.woodpecker.org.cn/moin/PyWebFrameList&lt;/a&gt; &lt;br&gt;&lt;br&gt;所有研究python web框架的朋友不得不看（至少我是这么认为）的一个东西：&lt;br&gt;&lt;br&gt;&lt;a href="http://wsgi.org/"&gt;http://wsgi.org/&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.python.org/dev/peps/pep-0333/"&gt;http://www.python.org/dev/peps/pep-0333/&lt;/a&gt;&lt;br&gt;&lt;a href="http://wiki.woodpecker.org.cn/moin/WSGI"&gt; http://wiki.woodpecker.org.cn/moin/WSGI&lt;/a&gt;&lt;br&gt;&lt;br&gt;最后还有两篇好文想与大家共欣赏：&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://www.sixwise.com/newsletters/06/06/25/people_who_drive_silver_or_blue_cars_should_not_read_this.htm"&gt;&lt;font class="newsletterHeading"&gt; People Who Drive Silver or Blue Cars Should NOT Read This&lt;/font&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://www.jacobian.org/writing/2006/aug/22/pronouncement/"&gt;Pronouncement&lt;/a&gt; &lt;br&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-115733378983891370?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://codeplayer.blogspot.com/2006/09/python-web.html' title='python web 框架可真多!'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/115733378983891370/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=115733378983891370' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115733378983891370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115733378983891370'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/python-web.html' title='python web 框架可真多!'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-33791960.post-115728560180885013</id><published>2006-09-03T19:55:00.000+08:00</published><updated>2006-09-03T21:07:46.116+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='others'/><title type='text'>有家的感觉，真好 ！</title><content type='html'>好多天没写blog了，上次blogbus服务器出了点问题，弄丢了我两篇文章，给他们写邮件也没人理，郁闷一回后就没有再写了。这段时间有什么想法或是直接在人家blog里评论一下，或是邮件列表里讨论讨论，或是在啄木鸟的wiki上编辑个页面什么。

流浪的日子颇为不好受，没有根的感觉，害怕被人遗忘。

甚至想过干脆完全整个自己的，不过照了照镜子后终于没有动手。突然发现blogger貌似居然解封了，虽然似乎没有看到官方的什么消息，不过我还是强烈感觉到，漂泊的日子该结束了。

顺便记下上个blog的地址吧，就像在上个blog中记下了上上个blog的地址一样。

&lt;a href="http://codeplayer.blogbus.com/"&gt;http://codeplayer.blogbus.com/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/33791960-115728560180885013?l=codeplayer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://codeplayer.blogspot.com/2006/09/blog-post.html' title='有家的感觉，真好 ！'/><link rel='replies' type='application/atom+xml' href='http://codeplayer.blogspot.com/feeds/115728560180885013/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=33791960&amp;postID=115728560180885013' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115728560180885013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/33791960/posts/default/115728560180885013'/><link rel='alternate' type='text/html' href='http://codeplayer.blogspot.com/2006/09/blog-post.html' title='有家的感觉，真好 ！'/><author><name>黄毅</name><uri>http://www.blogger.com/profile/01060629900676151700</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry></feed>
