<?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-3792639039530184077</id><updated>2012-02-17T02:27:28.754+08:00</updated><category term='Python History'/><category term='Python Inside'/><title type='text'>The History of Python</title><subtitle type='html'>The History of Python</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://python3.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3792639039530184077.post-3398277158278533237</id><published>2011-07-09T10:05:00.001+08:00</published><updated>2011-07-09T10:05:51.723+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>Karin Dewar, 缩进 和 冒号</title><content type='html'>Karin Dewar, 缩进 和 冒号&lt;br /&gt;&lt;br /&gt;我在&lt;a href="http://neopythonic.blogspot.com/2011/06/depth-and-breadth-of-python.html"&gt;另一个博客近期一篇博文&lt;/a&gt;中说了一个轶闻，是关于Robert Dewar的妻子如何发明Python缩进的趣事。当时我就提到自己并不十分确认具体细节，现在看来此举颇为明智，因为真相与之颇有偏差。我收到了Lambert Meertens一封详述此事的长电子邮件。我准备在此复述此信，除了部分他要求不要直接引用的部分外基本是信的全部内容了。摘要：Karin Dewar提供了ABC(因为也是Python)中在缩进开始前使用冒号的灵感，而不是缩进本身。下面是Lambert的电子邮件：&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dewar的贡献不在缩进本身，而是发明了缩进前冒号的使用。&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 首先是&lt;i&gt;B&lt;/i&gt;中的缩进。在&lt;i&gt;B&lt;/i&gt;0(&lt;i&gt;B&lt;/i&gt;0，&lt;i&gt;B&lt;/i&gt;1，&lt;i&gt;B&lt;/i&gt;2, ... 是创建ABC时的一系列设计，&lt;i&gt;B&lt;/i&gt;0最早)中就采用了强制缩进来分组代码，并且把分组代码用BEGIN和ENG分隔符包含起来。关于这点可以参考[GM76]的4.1节(布局)。如同打印美观一样，缩进被提议由专门的B编辑器来负责，而用户无法对此修改：用户没有被赋予取消这一设置的选择，以免缩进的强制性被破坏。&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 有了强制性缩进后，额外的BEGIN和END分隔符自然就显得多余了，&lt;i&gt;B&lt;/i&gt;1时我们就取消了BEGIN，只保留了END IF、END FOR等结束分隔符，在&lt;i&gt;B&lt;/i&gt;2时结束分隔符也被取消了，只利用缩进作为分组代码的唯一标识。这一点可参考[ME81]第四章(语句语法)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ABC中缩进的本意仅是为了使源代码看起来整洁，易于表达语义逻辑，把尚未强制的习俗固化下来，取消额外的BEGIN ... END可能受[PL75]影响，后者提倡仅用缩进来分组代码。occam出现(1983)的要晚，因此缩进这一特性不可能源自occam，同一原因，也不会是借鉴自Miranda(1985)。据我所知，B语言是最早采用缩进作为分组语句特性的且正式发布(并且有实现)的语言&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 现在到了 Dewar 的故事，也就是我得知采用冒号的由来，我在此将其记录下来，也算是ABC设计理念的回忆录：&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;依 Lambert 要求，下面的内容由我组织语句而不是直接引用。&lt;br /&gt;&lt;br /&gt;1978年，一次在Jablonna(亚布翁纳)召开的设计会议上，Robert Dewar, Peter King, Jack Schwartz 和 Lambert比较各种为&lt;i&gt;B&lt;/i&gt;提议的语法，通过比较采用各种语法实现同样的(代码质量一般的)冒泡排序。他们僵持不下时便去Robert Dewar妻子的房间将她喊来，想听听她的观点，像是现代版的让Paris来从Hera, Athena, 和 Aphrodite之间选美。但是刚刚向她解说了第一个语法形式后，她说道：“你的意思是说，这样一行'FOR i ...'，必然会影响接下来的一组语句，而不会仅是影响当前行本身?!”于是，这些科学家们意识到在这样的行结束后附加一个冒号，就能避免误解。&lt;br /&gt;&lt;br /&gt;Lambert 还提到如下相关文献：&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [PL75] P. J. Plauger. Signal and noise in programming language. In J. D. White, editor, Proc. ACM Annual Conference 1975, page 216. ACM, 1975.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [GM76] Leo Geurts and Lambert Meertens. Designing a beginners' programming language. In S.A. Schuman, editor, New Directions in Algorithmic Languages 1975, pages 1–18. IRIA, Rocquencourt, 1976.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ME81] Lambert Meertens. Issues in the design of a beginners' programming language. In J.W. de Bakker and J.C. van Vliet, editors, Algorithmic Languages, pages 167–184. North-Holland Publishing Company, Amsterdam, 1981.&lt;br /&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/3792639039530184077-3398277158278533237?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/3398277158278533237/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=3398277158278533237' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/3398277158278533237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/3398277158278533237'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2011/07/karin-dewar-indentation-and-colon.html' title='Karin Dewar, 缩进 和 冒号'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-6046204365421511245</id><published>2011-03-25T11:29:00.000+08:00</published><updated>2011-03-25T11:29:40.568+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python Inside'/><title type='text'>2011 Language Summit Report</title><content type='html'>http://blog.python.org/2011/03/2011-language-summit-report.html&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;2011年语言峰会报告&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;今年语言峰会于3月10日星期四在亚特兰大召开，在 PyCon 会议前一天。出席人员包括来自 &lt;a href="http://www.python.org/"&gt;CPython&lt;/a&gt;、 &lt;a href="http://www.pypy.org/"&gt;PyPy&lt;/a&gt; 、 &lt;a href="http://www.jython.org/"&gt;Jython&lt;/a&gt; 、 &lt;a href="http://www.ironpython.net/"&gt;IronPython&lt;/a&gt; 和 &lt;a href="http://www.parrot.org/"&gt;Parrot&lt;/a&gt;&amp;nbsp; 等 VM 代表，以及来自 &lt;a href="http://www.fedoraproject.org/"&gt;Fedora&lt;/a&gt; 、 &lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt; 和 &lt;a href="http://www.debian.org/"&gt;Debian&lt;/a&gt; 的系统包维护人员；还有 &lt;a href="http://www.twistedmatrix.com/"&gt;Twisted&lt;/a&gt; 项目开发人员和若干其他人士。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;开发 Blog&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;首先讨论的事项之一正是这个 Blog 本身，由 PSF 通信员 Doug Hellmann 发起。由于 python-dev 邮件列表日常讨论过多，希望借由这个 Blog 来方便用户获取开发资讯。我们计划包含 PEP 、重要决策、新特性与关键 bug 修复，将来还会包括下一步开发计划的非正式通报。&lt;br /&gt;&lt;br /&gt;Blog 发文对所有 Python 实现开放。例如，即便 PyPy 当前已有&lt;a href="http://morepypy.blogspot.com/"&gt;自己的 Blog 且相当活跃&lt;/a&gt;，也欢迎他们在这儿发布信息。还有一个相关讨论就是在&lt;a href="http://www.python.org/getit"&gt; python.org 的 download 页面&lt;/a&gt;提供对其它 Python 实现的介绍。这些实现的新版本发布时也将会在 &lt;a href="http://www.python.org/"&gt;python.org 主页&lt;/a&gt;作为新闻项目列出。 &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Compatibility Warnings&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;在 Python 3.2中我们引入了 ResourceWarning ，用于方便用户定位依赖 CPython reference counting 的代码。 ResourceWarning 不仅有利于用户书写高质量代码，也对书写跨 VM 代码有帮助。为进一步提高跨 VM 兼容性，提出了一个新的警告类型：CompatibilityWarning。&lt;br /&gt;&lt;br /&gt;之所以这么做，是源于最近由 PyPy 开发人员提交的一个 CPython bug 。 &lt;a href="http://bugs.python.org/issue11455"&gt;Issue #11455&lt;/a&gt;指出 CPython 允许用户创建一个新类型时，其 __dict__ 可以有“非字符串” key ，而目前至少 PyPy 和 Jython 不支持这样做。现在，用户就可以类似 ResourceWarning 那样抛出 CompatibilityWarning 警告，以便于定位此类问题。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;独立的标准库&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;现在 CPython 源代码已完成从 Subversion 到 Mercurial 的转换过程，再次兴起了将标准库放在单独 repo 的提议。其它实现的开发人员对此十分关注，因为这样将很大程度的简化其开发过程。其它实现现有方法比较繁琐，先对 CPython 的源代码做个快照，然后应用自身实现相关补丁，转换部分 C 扩展为纯 Python 实现，等等。&lt;br /&gt;&lt;br /&gt;讨论结果的实施会由接下来的一个相应 PEP 来体现，其中之一是版本号规划问题。既然库不再依附任一具体实现而是独立存在，则应有自己的版本号，以后的测试也应有版本相关考虑。&lt;br /&gt;&lt;br /&gt;标准库相关的讨论还涉及纯 Python 代码和对应 C 扩展的问题。PyPy 项目的 Maciej Fijalkowski 指出随着时间的推移，某些模块的 C 与 Python 版本出现细微差异，并建议修订这些模块时采取严谨审慎的策略，以便两种用户(纯 Python 实现的和 C 扩展的)都能平滑升级，这一点也达成了共识。另外，还决定，以纯 Python 实现优先，C 实现只用在能明显增加性能的场合。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;测试性能网站&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;PyPy 的 Speed 中心十分成功的展示了 PyPy 的性能，由此讨论了在 python.org 设立类似网站的想法，初步打算命名为 performance.python.org ，各种 VM 实现均包含进来。不仅进行性能测评，还可包含内存占用、测试通过程度以及语言兼容性等指标。由于当前只包含 PyPy 和 CPython ，为了支持其它 Python 实现还需要进行系统安装设置方面的工作。&lt;br /&gt;&lt;br /&gt;Allison Randal 在会上提议了在 &lt;a href="http://osuosl.org/"&gt;Oregon State University 的开源实验室&lt;/a&gt;托管若干高性能电脑，恰好可用来作为新的 Speed 中心。Jesse Noller 谈了购置硬件事项--欢迎捐助！&lt;br /&gt;&lt;br /&gt;如果您或者您的机构愿意资助 Speed 中心或其它方面的 Python 开发，请联系 &lt;a href="http://www.python.org/psf/about"&gt;Python 软件基金会&lt;/a&gt;，这儿是&lt;a href="http://www.python.org/psf/donations"&gt;捐赠页面&lt;/a&gt;。&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;暂停解除&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;随着 CPython 3.3 开发的起步，暂停语言变化的限制已经失效。虽然闸门已经打开，语言变化仍然会采取保守态度，我们希望减慢进化的速度，这也有利于其它实现赶上 CPython 。虽然在暂停语言变化期间没有其它实现升级到3.x版本， PyPy 和 IronPython 最近已经实现了兼容2.7版本， IronPython 也开始3.x的规划。&lt;br /&gt;&lt;br /&gt;至于 Python 3.3会有哪些变化，首先 &lt;a href="http://www.python.org/dev/peps/pep-0380/"&gt;PEP 380&lt;/a&gt;已被接受，该 PEP 引入了 "yield from &lt;expr&gt;" 语法，允许在一个 generator 中 yield 另一个 generator 。除此之外，近期内尚无其它语言变化。&lt;/expr&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;异常属性&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;接下来简略讨论了异常提供属性以增加易用性的问题，而不局限现在这样迫使用户依赖字符串信息。例如在 ImportError 时，不应通过 parsing 手工分析何处 import 失败，而是提供相应属性。&lt;br /&gt;&lt;br /&gt;实现很可能在初始化异常对象时依赖显式关键词( keyword-only )参数，当前已有针对 &lt;a href="http://bugs.python.org/issue8754"&gt;ImportError 情况的补丁&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;贡献者协议&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;与会者还讨论了贡献者协议，并准备若干形式的电子协议。&lt;a href="http://code.google.com/legal/individual-cla-v1.0.html"&gt; Google 个人贡献者协议&lt;/a&gt;是设计新协议时的参考之一。这个话题的讨论已有很长时间，许多人希望能有电子版本的解决方案。由此，需要调研以保证将来使用电子版本的协议时在美国之外也有效。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Google Summer of Code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Martin von Lowis 简短介绍了今年在 PSF 名下的 Google Summer of Code 。我们鼓励开发者不仅作为导师，还鼓励他们提议项目，便于学生参与--而且提出项目并不意味着一定要作为导师。如果您有兴趣帮助我们，请参阅 &lt;a href="http://pyfound.blogspot.com/2011/03/google-summer-of-code-call-for-projects.html"&gt;PSF 的项目与导师征集通知&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Distutils&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Tarek Ziade 带来了 &lt;a href="https://bitbucket.org/tarek/distutils2/wiki/Home"&gt;Distutils2&lt;/a&gt; ，指出他们正进行的 sprint ，目标在于完成到 Python 3 的移植并为最终合并回 Python 标准库做准备。另外，到时将会采用一个新的名称： packaging 。 packaging 项目组计划还提供单独的 Distutils2 库，以支持 Python 2.4到 Python 3.2。&lt;br /&gt;&lt;br /&gt;packaging sprint 是 PyCon sprints 中规模最大的 sprint 之一，结果十分理想。当前代码在 &lt;a href="https://bitbucket.org/tarek/cpython"&gt;Bitbucket&lt;/a&gt; ，只待合并回标准库。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;其它VM展望&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;IronPython提到下一步计划，已包含 3.x 发布。他们在 PyCon 宣布了 2.7.0 ，这也是项目由微软转交为开源社区驱动后第一次新版本发布，然后准备接下来几个月向3.x进发&lt;br /&gt;&lt;br /&gt;最近发布了2.5.2，而且计划实现2.6。有些人建议直接跳级到2.7，因为2.6和2.7之间的区别并不大，但是如果跳级，可能接下来新版本的发布会耽搁一段时间。“早发布，多发布”是会上一句格言，他们也有考虑2.6之后直接升级到3.x，然后再考虑2.6到2.7的问题。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;开发资助&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;3.x计划还谈论了如何资助开发，以及资助对加速其它实现赶上3.x版本的重要性。目前有相应资金，需要向 PSF 提交申请后才会进行可行性论证。对此感兴趣，希望得到资金支持者请联系 PSF 。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Python 基准&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Jim Fulton 谈到他称作“基准” Python 的概念。在部署 Python 应用时，他发现有的操作系统难以设置 Python 。恰好 Fedora 和 Ubuntu/Debian 的打包专家也在，我们得以进一步考察这个问题。&lt;br /&gt;&lt;br /&gt;对 Fedora 而言，基准 Python 安装需要考虑操作系统是利用一张 Live CD 来完成的，因此只能是一个最小安装，和极少的依赖，这种最小化安装简化到仅能使系统运行起来。因此做了目录名称的变动，也没有包含 distutils 等标准库，而且有些库即使包含版本也较陈旧。&lt;br /&gt;&lt;br /&gt;当前尚未有一个明晰的解决方案，但相关成员将会进一步研究以期解决该问题。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;3.3 特性&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;会上还讨论了3.3可能引入的特性，包括两个 PEP 。&lt;a href="http://www.python.org/dev/peps/pep-0382"&gt;PEP 382&lt;/a&gt; 讨论了 Namespace Packages ，会在将来合适时机实施，在合并 distutils 时也有提及。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.python.org/dev/peps/pep-0393"&gt;PEP 393&lt;/a&gt;， 定义了一个灵活的字符串表示机制，也引起了讨论，而且有些同学希望将其作为 GSoC 项目。除了功能上的实现之外，还需要考虑性能与内存占用等方面以决定实现能否被接受。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Unladen Swallow&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Unladen Swallow 目前处在 “休眠” 状态，当前并不适宜合并到 CPython 3.3。由于缺乏相关领域的专家参与，要取得进展需要数个方面的突破。在讨论时还提到是否资助有利于推动 Unladen Swallow 前进，若有兴趣，致函联系 PSF。&lt;br /&gt;&lt;br /&gt;尽管 Unladen Swallow 处在休眠期，且前途未卜，它仍然对 Python 和开源社区很有积极意义。 例如 Unladen Swallow 的性能测评部分就对评测其它实现很有帮助。另外 Unladen Swallow 开发人员对 LLVM 和 Clang 的贡献也对这些项目有帮助。&lt;br /&gt;&lt;br /&gt;还有两个性能相关的想法被简单提及，包括 Dave Malcolm 的函数内联提议。 Martin von Lowis 提及了他正在着手的 JIT 扩展模块，虽然 PyPy 开发人员对这种 JIT 的有效性持怀疑态度。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;通往异步框架之路&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;临近结束时讨论了在某种程度上将 Twisted 集成到标准库中来的问题。基本想法是这样一个异步实现有助于把程序迁移到 Twisted 或者其它异步编程框架。&lt;br /&gt;&lt;br /&gt;接下来就会有一个 PEP ，和 WSGI 参考类似，但是是针对异步事件循环( asynchronous event loops )的。除PEP 作者外还需要 Twisted 项目和其它相关项目人士须致力于达成共识。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;更多信息&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;更多信息请参考 CPython 开发人员 Nick Coghlan 的&lt;a href="http://www.boredomandlaziness.org/2011/03/python-language-summit-rough-notes.html"&gt;笔记&lt;/a&gt;和&lt;a href="http://www.boredomandlaziness.org/2011/03/python-language-summit-highlights.html"&gt;要点&lt;/a&gt;。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-6046204365421511245?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/6046204365421511245/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=6046204365421511245' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6046204365421511245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6046204365421511245'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2011/03/2011-language-summit-report.html' title='2011 Language Summit Report'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-5822957799399813480</id><published>2010-08-25T10:30:00.003+08:00</published><updated>2011-03-25T10:37:14.002+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>Why Python's Integer Division Floors</title><content type='html'>英文原文链接: &lt;a href="http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html"&gt;http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者: Guido van Rossum&lt;br /&gt;&lt;br /&gt;Why Python's Integer Division Floors&lt;br /&gt;为何Python整除运算采用向下取整的规则&lt;br /&gt;&lt;br /&gt;今天(又)有人问我，为什么Python中的整除(integer division)返回值向下取整(floor)而不是像C语言中那样向0取整。&lt;br /&gt;&lt;br /&gt;在正整数范围内，两者并无实质差别，例如：&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; 5//2&lt;/div&gt;&lt;div&gt;2&lt;br /&gt;&lt;br /&gt;但是当操作数之一为负时，结果是向下取整的，也就是远离0(接近负无穷方向)：&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; -5//2&lt;/div&gt;&lt;div&gt;-3&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; 5//-2&lt;/div&gt;&lt;div&gt;-3&lt;br /&gt;&lt;br /&gt;或许部分人不太适应，数学上有一个较好的解释为何这样做。整除运算(//)和与之密切相关的取模运算(%)满足如下优美的数学关系式(所有变量均为整数)：&lt;br /&gt;&lt;br /&gt;a/b = q 余数为 r&lt;br /&gt;有&lt;br /&gt;b * q + r = a 而且 0 &amp;lt;= r &amp;lt; b (假设a和b都&amp;gt;=0)&lt;br /&gt;&lt;br /&gt;如果希望将这一关系扩展到a为负(b仍为正)的情况，有两个选择：一是q向0取整，r取负值，这时约束关系变为 0 &amp;lt;= abs(r) &amp;lt; b，另一种选择是q向下(负无穷方向)取整，约束关系不变，依然是 0 &amp;lt;= r &amp;lt; b。 &lt;/div&gt;&lt;br /&gt;&lt;br /&gt;在数学的数论中，数学家总是倾向于第二种选择(参见如下&lt;a href="http://en.wikipedia.org/wiki/Modulo_operation"&gt;Wikipedia链接&lt;/a&gt;)。在Python语言中我也做了同样选择，因为在某些取模操作应用中a取什么符号并不重要。例如从POSIX时间戳(从1970年初开始的秒数)得到其对应当天的时间。因为一天有24*3600 = 86400秒，这一操作就是简单的t % 86400。但是当表达1970年之前的时间，这时是一个负数，向0取整规则得到的是一个毫无意义的结果！而向下取整规则得到的结果仍然是正确的。&lt;br /&gt;&lt;br /&gt;另外一个我能想到的应用是计算机图形学中计算像素的位置。我相信这样的应用还有更多。&lt;br /&gt;&lt;br /&gt;顺便说一下，b取负值时，仅需要把符号取反，约束关系变为：&lt;br /&gt;&lt;br /&gt;0 &amp;gt;= r &amp;gt; b&lt;br /&gt;&lt;br /&gt;那么，现在的问题变成，C为啥不采取(Python)这样的选择呢？可能是设计C时硬件不适合这样做，所谓硬件不适合这样做是说指那些最老式的硬件把负数表示为“符号+大小”而不是像现在的硬件用二进制补码表示(至少对整数是用二进制补码)。我的第一台计算机是一台Control Data大型机，它用1的补码来表示整数和浮点数。60个1的序列表示负0！&lt;br /&gt;&lt;br /&gt;Tim Peters对Python的浮点数部分洞若观火，对于我想把这一规则推广到浮点数取模运算有些担心。可能他是对的，因为向负无穷取整的规则有可能导致当x是绝对值特别小的负数时x%1.0会丢失精度。但是这还不足以让我对整数取模，也就是//进行修改。&lt;br /&gt;&lt;br /&gt;附言：注意我用了//而不是/，这是一个Python 3 语法，而且在Python 2 中也是有效的，它强调了使用者是要进行整除操作。Python 2 中的 / 有可能产生歧义，因为对两个操作数都是整数时或者一个整数一个浮点数或者两个都是浮点数时，返回的结果类型不同。当然，这是另外的故事，详情参见&lt;a href="http://www.python.org/dev/peps/pep-0238/"&gt;PEP238&lt;/a&gt;。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-5822957799399813480?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/5822957799399813480/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=5822957799399813480' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5822957799399813480'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5822957799399813480'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2010/08/why-pythons-integer-division-floors.html' title='Why Python&apos;s Integer Division Floors'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-5566793068283265376</id><published>2010-07-06T17:14:00.006+08:00</published><updated>2010-07-22T08:58:48.631+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>From List Comprehensions to Generator Expressions</title><content type='html'>英文原文链接: &lt;a href="http://python-history.blogspot.com/2010/06/from-list-comprehensions-to-generator.html"&gt;http://python-history.blogspot.com/2010/06/from-list-comprehensions-to-generator.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者: Guido van Rossum&lt;br /&gt;&lt;br /&gt;From List Comprehensions to Generator Expressions&lt;br /&gt;&lt;br /&gt;从 List Comprehension 到 Generator Expression&lt;br /&gt;&lt;br /&gt;List comprehension 在 Python 2.0版本添加进来。这一特性始于Greg Ewing的一套补丁，Skip Montanaro 和 Thomas Wouters参与贡献。(如果我没记错，Tim Peters也很提倡这个想法。)本质上，可以看做众所周知的数学家采用的集合符号的Pythonic化解释。例如，通常认为如下&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;{x | x &gt; 10}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;代表所有满足x &gt; 10的x组成的集合。数学里这种形式隐含了读者可接受的全集(例如根据上下文，可能是所有实数或者所有整数)。在Python中没有全集的概念，在 Python 2.0  时连集合的概念也没有。(Sets是一个有趣的故事，我将来会在另一篇博文讨论。)&lt;br /&gt;&lt;br /&gt;基于此以及其它方面考虑，Python中采用如下语法形式来表示：&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;[f(x) for x in S if P(x)]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这条语句产生一个list(列表)，包含的值来自 sequence (序列) S，满足 predicate (判定) P，且被function(函数) f map (映射)。if-从句是可选项，且可以存在多个for-从句(每个for-从句可以有自己可选的if-从句)来表示嵌套循环(多for-从句会把多维元素映射到一维列表中，这一需求比较少见，因此实用中不常用)。&lt;br /&gt;&lt;br /&gt;List comprehension 提供了内置函数map() 和 filter() 的替代。 map(f, S) 等价于 [f(x) for x in S]，filter(P, S) 等价于 [x for x in S if P(x)]。或许有人认为 map() 和 filter() 的语法形式更紧凑，所以 list comprehension 没有多少值得推荐的。然而，如果考察一个更加实际的例子，观点或许就会改变了。假设我们想对一个list中的每个元素增加1，生产一个新的list。list comprehension 的写法是 [x+1 for x in S] 。map() 的写法是 map(lambda x: x+1, S)。这儿的"lambda x: x+1" 部分是Python语法中用于内嵌的匿名函数。&lt;br /&gt;&lt;br /&gt;两种形式(list comprehension和map()/reduce())孰优孰劣引起了争论，有人认为争论的关键在于 Python 的 lambda 语法过于繁琐，如果匿名函数能有更简洁的表示形式，那么map()就更有吸引力了。我不同意，我发觉 list comprehension 形式比函数式语法更易读，尤其是当映射函数变得复杂时。另外 list comprehension 比 map和lambda 执行速度更快。这是因为调用一个 lambda 函数就创建了一个新的堆栈结构(stack frame)，而 list comprehension 中的表达式无需创建新的堆栈结构。&lt;br /&gt;&lt;br /&gt;在list comprehension获得成功，在发明generator(关于generator，将来会在另外一篇展开)之后，Python 2.4 增加了一种近似的语法用以表示结果构成的序列(sequence)，但是并不将它具体化(concrete)为一个实际的list。新特征称作 "generator expression"。例如：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;sum(x**2 for x in range(1, 11))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这条语句调用内置函数 sum()，参数为一个generator expression, 它 yield 从1到10(包括10)的平方。 sum() 函数把参数中的值加和起来，得到答案385。该语句相对于 sum([x**2 for x in range(1, 11)]) 的优势应当是明显的。后者生成了一个包含所有平方数的list，然后再遍历一次，最后(得到结果后)丢弃该list。对于数量较大的数据，前者在内存方面的节省是一个重要考虑因素。&lt;br /&gt;&lt;br /&gt;我还应该提到 list comprehension 和 generator expression 微妙的区别。例如，在Python 2，如下是一个有效的 list comprehension：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;[x**2 for x in 1, 2, 3]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;然而，这是一个无效的 generator expression：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;(x**2 for x in 1, 2, 3)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;我们可以通过给"1, 2, 3"部分添加括号来修复它：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;(x**2 for x in (1, 2, 3))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;在Python 3，你甚至对list comprehension也必须使用括号了：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;[x**2 for x in (1, 2, 3)]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;然而，对于"常规的"或者"显式的"for-循环，你仍然可以省略括号：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;for x in 1, 2, 3: print(x**2)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;为何有这种区别，而且为何在Python 3 对 list comprehension 变得更严格了？影响设计包括反向兼容，避免歧义，注重等效，和语言的进化等因素。最初，Python(还没有版本号的时候:-)只有明确的for-循环形式。在'in'之后的部分不会带来歧义，因为它总是最后伴随着一个冒号。我清楚你要做的是对一些已知数值进行循环，因此，你不需要因为必须增加括号而烦恼。写到这里，又让我想起来在Algol-60，你可以这样写：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;for i := 1, 2, 3 do Statement&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Algol-60 还额外支持利用step-until从句决定表达式的步长，如下:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;for i := 1 step 1 until 10, 12 step 2 until 50, 55 step 5 until 100 do Statement&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(追忆往事，如果当初Python的foo-循环也能这样支持对多个序列的遍历，也挺酷的，哎。。。)&lt;br /&gt;&lt;br /&gt;当我们在Python 2.0 中增加 list comprehension 时，原来的规则依然有效：序列表达式只可能被伴随的右中括号 ']' 或者 'for' 关键词或者 'if' 关键词结束。而且这是好事。&lt;br /&gt;&lt;br /&gt;但是，到了 Python 2.4 增加 generator expression 时，我们遇到了歧义性方面的问题: 语法上看一个 generator expression 的括号部分并不是它语法上必须的部分。例如下面例子：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;sum(x**2 for x in range(10))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;外括号是属于被调用的函数sum()的一部分，里面的 "裸" generator expression 作为第一个参数。因此理论上，如下语句可以有两种解释：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;sum(x**2 for x in a, b)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;可以有意解释为这样:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;sum(x**2 for x in (a, b))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;也可以解释为:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;sum((x**2 for x in a), b)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(如果我没记错)犹豫了一阵子之后，我决定这种情况不应该猜测，而是 generator comprehension 的 'in' 关键词之后必须是单个表达式(当然，它是 iterable 的)。但是当时我们也不想破坏已存在于 list comprehension 中的代码，因为它已经广为流行了。&lt;br /&gt;&lt;br /&gt;设计 Python 3 时，我们决定 list comprehension:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;[f(x) for x in S if P(x)]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;完全等价于如下利用内置函数 list() 展开的 generator expression:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;list(f(x) for x in S if P(x))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;于是我们将稍微更严格的 generator expression 语法也同样适用于 list comprehension。&lt;br /&gt;&lt;br /&gt;在 Python 3 我们还做了另外的变动，以增加 list comprehension 和 generator expression 的等效程度。Python 2时，list comprehension 会"泄露" 循环控制变量到外边：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;x = 'before'&lt;br /&gt;a = [x for x in 1, 2, 3]&lt;br /&gt;print x # this prints '3', not 'before'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这是最初的 list comprehension 实现造成现象；也是数年间 Python 的"肮脏的小秘密"之一。开始由于这样可以使得 list comprehension 性能"越快越好"而作为折衷保留了，虽然偶然会刺痛人毕竟对新手来说算不上常见缺陷。然而对于 generator expression 我们不会再这样做了。 Generator expression 利用 generator 实现，执行 generator 时需要一个隔离的执行帧(separate execution frame)。由此还使得 generator expression (特别是在遍历比较短的序列时) 比 list comprehension 效率略低。&lt;br /&gt;&lt;br /&gt;然而到了 Python 3，我们决心利用和 generator expression 的同样实现策略来修缮这个 list comprehension 的 "肮脏的小秘密"。 于是在 Python 3，上例(当然，最后一句修改为 print(x) :-) 将会打印 'before', 这证明 list comprehension 中的'x'只是暂时遮蔽而不是直接使用 list comprehension 之外的'x'。&lt;br /&gt;&lt;br /&gt;在你开始担心 list comprehension 在 Python 3 中变慢之前要说的是：感谢大量的 Python 3 实现方面的努力，list comprehension 和 generator expressions 都比 Python 2 中更快了！(而且两者也不再有速度上的差别。)&lt;br /&gt;&lt;br /&gt;更新: 当然，我忘了说 Python 3 还支持 set comprehension 和 dictionary comprehension。这是 list comprehension 思路的自然推广。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-5566793068283265376?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/5566793068283265376/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=5566793068283265376' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5566793068283265376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5566793068283265376'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2010/07/from-list-comprehensions-to-generator.html' title='From List Comprehensions to Generator Expressions'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-2944986432344117119</id><published>2010-07-06T12:32:00.001+08:00</published><updated>2011-01-10T14:10:43.145+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>Method Resolution Order</title><content type='html'>Method Resolution Order&lt;br /&gt;&lt;br /&gt;英文原文链接: &lt;a href="http://python-history.blogspot.com/2010/06/method-resolution-order.html"&gt;http://python-history.blogspot.com/2010/06/method-resolution-order.html&lt;/a&gt;&lt;br /&gt;原文作者: Guido van Rossum&lt;br /&gt;&lt;br /&gt;方法解析顺序&lt;br /&gt;&lt;br /&gt;在支持多重继承的编程语言中，查找方法具体来自那个类时的基类搜索顺序通常被称为方法解析顺序(Method Resolution Order)，简称MRO。(Python中查找其它属性也遵循同一规则。)对于只支持单重继承的语言，MRO十分简单；但是当考虑多重继承的情况时，MRO算法的选择非常微妙。Python先后出现三种不同的MRO：经典方式、Python2.2 新式算法、Python2.3 新式算法(也称作C3)。Python 3中只保留了最后一种，即C3算法。&lt;br /&gt;&lt;br /&gt;经典类采用了一种简单MRO机制：查找一个方法时，搜索基类简单的深度优先从左到右。搜索过程中第一个匹配的对象作为返回结果。例如，考虑如下类：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class A:&lt;br /&gt; def save(self): pass&lt;br /&gt;&lt;br /&gt;class B(A): pass&lt;br /&gt;&lt;br /&gt;class C:&lt;br /&gt; def save(self): pass&lt;br /&gt;&lt;br /&gt;class D(B, C): pass&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;对于类D的实例x，它的经典MRO结果是类D，B，A，C顺序。因此查找方法x.save()将会得到A.save()(而不是C.save())。这个机制对于简单情况工作良好，但是对于更复杂的多重继承关系，暴露出的问题就比较明显了。其中问题之一是关于"菱形继承"时的方法查找顺序。例如：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class A:&lt;br /&gt;  def save(self): pass&lt;br /&gt;&lt;br /&gt;class B(A): pass&lt;br /&gt;&lt;br /&gt;class C(A):&lt;br /&gt;  def save(self): pass&lt;br /&gt;&lt;br /&gt;class D(B, C): pass&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;此处类D继承自类B和类C，类B和类C均继承自类A。应用传统的MRO，查找方法时在类中的搜索顺序是D, B, A, C, A。因此，语句x.save()将会如前一样调用A.save()。然而，这可能非你所需！既然B和C都从A继承，别人可以争辩说重新定义的方法C.save()可以被看做是比类A中的方法"更具体"(实际上，有可能C.save()会调用A.save())，所以C.save()才是你应该调用的。如果save方法是用于保持对象的状态，不调用C.save()将使C的状态被丢弃，进而程序出错。&lt;br /&gt;&lt;br /&gt;虽然当时的Python代码很少存在这种多重继承代码，"新类"(new-style class)的出现则使之成为常见现象。这是由于所有的新类都继承自object这一基类。因此涉及到新类的多重继承总是会产生前面所述的菱形关系。例如：&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class B(object): pass&lt;br /&gt;&lt;br /&gt;class C(object):&lt;br /&gt;  def __setattr__(self, name, value): pass&lt;br /&gt;&lt;br /&gt;class D(B, C): pass&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;而且，object定义了一些方法(例如__setattr__())可以由子类扩展，这时解析顺序更是至关重要。上面代码所属例子中，方法C.__setattr__应当被应用到类D的实例。&lt;br /&gt;&lt;br /&gt;为了解决在Python2.2引入的新类所带来的方法解析顺序问题，我采取的方案是在类定义时就计算出它的MRO，并存储为该类对象的一个属性。官方文档中MRO的计算方法为：深度优先，从左到右遍历基类，这个与经典MRO一致，但是如果任何类在搜索中是重复的，只有最后一个出现的位置被保留，其余会从MRO list中删除。因此我们前面这个例子中，搜索顺序将会是D, B, C, A(经典类采用经典MRO，则会是D, B, A, C, A)。&lt;br /&gt;&lt;br /&gt;实际上MRO的计算比文档所说的要更复杂。我发现某些情况下新的MRO算法结果不理想。因此还存在一个特例，用于处理两个基类在两个不同的派生类中顺序不同，而这两个派生类又被另外一个类继承的情况。如下代码所示：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class A(object): pass&lt;br /&gt;class B(object): pass&lt;br /&gt;class X(A, B): pass&lt;br /&gt;class Y(B, A): pass&lt;br /&gt;class Z(X, Y): pass&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;利用文档中描述的新MRO算法，Z关于这些类的MRO为Z, X, Y, B, A, object。(这儿的object是通用基类。)。然而，我不希望结果中B出现在A之前。因此实际的MRO会交换其顺序，产生Z, X, Y, A, B, object。直观上说，算法尝试保持基类在搜索时过程中首次出现的顺寻。例如，对于类Z，他们基类X应当被首先搜索到，因为在继承的list中排序最靠前。既然X继承自A和B，MRO算法会尝试保持其顺寻。这是在我在Python2.2中实际实现的算法，但是文档只提到了前面的不包括特例处理的算法(我幼稚的认为这点小差别不需明言。)。&lt;br /&gt;&lt;br /&gt;然而，就在Python 2.2 引入新类不久，Samuele Pedroni就发现了文档中MRO算法与实际代码中观察到结果不一致的现象。而且，在上述特例之外也可能发生不一致情况。详细讨论的结果认为Python2.2采用的MRO是坏的，Python应当采用C3线性化算法，该算法详情见论文"A Monotonic Superclass Linearization for Dylan"(K. Barrett, et al, presented at OOPSLA'96)。&lt;br /&gt;&lt;br /&gt;本质上，Python 2.2 MRO的主要问题在于不能保持单调性(monotonicity)。在一个复杂的多层次继承情况，每个继承关系都决定了一个直接的查找顺序，如果类A继承类B，则MRO明显应当先查找A后查找B。类似，如果类B多重继承类C和类D，则搜索顺序中类B应该在类C之前，且类C应该在类D之前。&lt;br /&gt;&lt;br /&gt;在复杂的多层次继承情况，始终能满足这一规则就称为保持了单调性。也就是说，当你决定类A会在类B之前查找到，应当再也不会遇到类B需要在类A之前查找的情况(否则，结果是未定义的，应该拒绝这种情况下的多层次继承)。以前的MRO算法未能做到这一点，新的C3算法则在保证单调性方面发挥了效用。基本上，C3的目的在于让你依据复杂多层次继承中所有的继承关系进行排序，如果所有顺序关系都能满足，则排序结果就满足单调性。否则，无法得到确定的顺序，算法会报错，拒绝运行。&lt;br /&gt;&lt;br /&gt;于是，在Python 2.3，摈弃了我手工作坊的 2.2 MRO算法，改为采用经过学术审核检验的C3算法。带来的结果之一就是当多层次继承中存在基类顺序不一致情况时，Python将会拒绝这种类继承。还是参加前面例子，对于类X和类Y就存在顺序上不一致，对于类X，规则判定类A应该在类B之前被检查。然而对于类Y，规则认为类B应该在类A之前被检查。单独情况下，这种不一致是可以接受的，但是如果X和Y共同作为另外一个类(例中定义的类Z)的基类，C3算法就会拒绝这种继承关系。这个也算是对应了Zen of Python的"errors should never pass silently"规则。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-2944986432344117119?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/2944986432344117119/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=2944986432344117119' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/2944986432344117119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/2944986432344117119'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2010/07/method-resolution-order.html' title='Method Resolution Order'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-7931839034652105681</id><published>2010-07-05T15:24:00.001+08:00</published><updated>2010-07-05T15:25:49.868+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>import antigravity</title><content type='html'>英文原文链接: &lt;a href="http://python-history.blogspot.com/2010/06/import-antigravity.html"&gt;http://python-history.blogspot.com/2010/06/import-antigravity.html&lt;/a&gt;&lt;br /&gt;原文作者: Guido van Rossum&lt;br /&gt;&lt;br /&gt;反重力(antigravity)模块源自一幅XKCD漫画，由Skip Montanaro 添加至Python 3中。进一步的详情可以参考如下链接，这是我所知道最早提及此事的出处: &lt;a href="http://sciyoshi.com/blog/2008/dec/30/import-antigravity/"&gt;http://sciyoshi.com/blog/2008/dec/30/import-antigravity/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;但是反重力(antigravity)模块实际起源于更早时候的Google App Engine!App Engine于2008年4月7号发布，反重力(antigravity)模块在临近发布前才添加进来。在距离发布前几周时间，App Engine大多数代码已经冻结，Google的App Engine项目组认为我们应对添加一个复活节彩蛋，当时征集到许多提案，有的过于复杂，有的难于理解，还有些则存在危险性，最后我们选择了“反重力(antigravity)”模块。App Engine的反重力(antigravity)模块比Python3中的对应实现稍微多了一点变化。它定义了一个fly函数可以随机的做如下两件事情之一：有10%的可能重定向到XKCD的反重力(antigravity)漫画；另外90%的可能则是简单的把漫画中的文字显示在HTML页面中(最后一行有漫画链接地址)。要在App Engine的应用中调用反重力(antigravity)模块，需要如下简单代码:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;import antigravity&lt;br /&gt;&lt;br /&gt;def main():&lt;br /&gt;  antigravity.fly()&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;  main()&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;更新: Python 3 标准库中的反重力模块还有一个彩蛋中的彩蛋，如果你查看源码会发现它定义了一个实现XKCD 中 GEO 哈希算法(geohashing)的函数.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-7931839034652105681?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/7931839034652105681/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=7931839034652105681' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/7931839034652105681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/7931839034652105681'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2010/06/import-antigravity.html' title='import antigravity'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-5405623386669754986</id><published>2010-07-05T09:17:00.000+08:00</published><updated>2010-07-05T09:18:00.526+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>import this and The Zen of Python</title><content type='html'>英文原文链接: &lt;a href="http://python-history.blogspot.com/2010/06/import-this-and-zen-of-python.html"&gt;http://python-history.blogspot.com/2010/06/import-this-and-zen-of-python.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者: Guido van Rossum&lt;br /&gt;&lt;br /&gt;Barry Warsaw 撰写了一篇关于import this和the Zen of Python的有趣博文，我希望更多人关注Python history上由于年代久远而变得晦暗的这一段： &lt;a href="http://www.wefearchange.org/2010/06/import-this-and-zen-of-python.html"&gt;http://www.wefearchange.org/2010/06/import-this-and-zen-of-python.html&lt;/a&gt; 。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-5405623386669754986?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/5405623386669754986/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=5405623386669754986' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5405623386669754986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5405623386669754986'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2010/06/import-this-and-zen-of-python.html' title='import this and The Zen of Python'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-4306833589441176800</id><published>2010-06-24T03:27:00.007+08:00</published><updated>2010-07-05T01:21:42.564+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>The Inside Story on New-Style Classes</title><content type='html'>The Inside Story on New-Style Classes&lt;br /&gt;&lt;br /&gt;新类内幕&lt;br /&gt;&lt;br /&gt;英文原文链接: &lt;a href="http://python-history.blogspot.com/2010/06/inside-story-on-new-style-classes.html"&gt;http://python-history.blogspot.com/2010/06/inside-story-on-new-style-classes.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者: Guido van Rossum&lt;br /&gt;&lt;br /&gt;[提醒，本篇是长文，且多技术细节。]&lt;br /&gt;&lt;br /&gt;表面看新类和原来的类实现十分相似，实际上新类还引入了一些新概念：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;低级构造方法__new__()&lt;/li&gt;&lt;li&gt;descriptors，泛化个性化属性(attribute)存取方式&lt;/li&gt;&lt;li&gt;静态方法与类方法(static methods and class methods)&lt;/li&gt;&lt;li&gt;properties (即时计算的attributes)&lt;/li&gt;&lt;li&gt;decorators (Python2.4引入)&lt;/li&gt;&lt;li&gt;slots&lt;/li&gt;&lt;li&gt;新的MRO(Method Resolution Order， 方法解析顺序)&lt;/li&gt;&lt;/ul&gt;接下来几个章节我将尝试介绍一下这些概念&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;低级构造方法和__new__()&lt;/span&gt;&lt;br /&gt;往常，类的实例创建后，通过__init__()方法进行初始化。然而有时类的作者希望能控制实例的创建过程-例如，当对象是从存储数据恢复而来时。旧式类(Old-style classes)从未真正提供定制对象创建的机制，虽然有些库模块(例如，"new"模块)提供了某些情况的对象创建非标准方式。&lt;br /&gt;&lt;br /&gt;新类引入了新的类方法__new__()，以方便类作者控制类实例创建。类作者通过重载__new__()可以实现一些设计模式，例如(从空闲列表)返回已创建实例的单模式(Singleton Pattern)，或者返回其它类(可能是原来类的子类)的实例。__new__还有其它重要用途值得关注，例如，在pickle模块中，在反序列化对象时__new__用于创建实例。这时实例已经生成，而__init__方法尚未调用。&lt;br /&gt;&lt;br /&gt;__new__还可用于辅助子类化不可变类型(immutable types)。因为"不可变"这一特性，这类对象无法通过标准的__init__()方法来初始化。于是任何特殊的初始化，需要在对象创建时进行；例如，如果类希望能修改不可变对象包含的值，可在__new__方法对此进行处理，向基类的__new__方法传递修改后的值来实现。&lt;br /&gt;&lt;br /&gt;Descriptors&lt;br /&gt;&lt;br /&gt;Descriptors 是绑定方法(bound methods)这一概念的泛化，绑定方法对于经典类(classic classes)实现至关重要。在经典类情况，当要查询的实例属性(instance attribute)在实例字典(instance dictionary)中未找到时，就继续在类字典中(class dictionary)查找，然后是递归遍历基类的类字典。当属性是在类字典(class dictionary)中查找到时(而不是在实例字典中)。解释器会检查查找到的对象是否是一个Python函数对象(function object)。如果是，则返回值不是该查找到的查找到的对象，而是将该对象的包装对象(wrapper object)作为一个currying function返回。当包装对象被调用时，它会把实例插入到参数列表最前面，然后调用原来的函数对象。&lt;br /&gt;&lt;br /&gt;例如，类C有实例x。假设要做方法调用x.f(0)。这个操作会查找x的属性名"f"，然后将0作为参数进行调用。如果"f"是类方法，在查找该属性时会返回一个包装函数(wrapper function)，可用如下Python伪代码近似描述：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;def bound_f(arg):&lt;br /&gt;   return f(x, arg)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;当传递参数0来调用包装函数时，它会传递两个参数调用"f"：x和0。这是类方法得到"self"参数的基本机制。&lt;br /&gt;&lt;br /&gt;另外一种调用函数对象(function object)f(无包装)的方式是通过调用类C的属性名"f"。这时返回的不是包装后的对象而是函数f本身。换句话说，x.f(0)等价于C.f(x, 0)。这是Python中的一种相当基本的等价方式。&lt;br /&gt;&lt;br /&gt;对经典类而言，如果查找到的属性是其它类型对象(非函数类型)，则不创建包装对象，而是不做变化直接将该类属性返回。这使得类属性可以作为实例变量"缺省"值。例如在上例中，如果类C有一个名为"a"的属性，它的值是1，且x的实例字典中没有"a"，那么x.a等于1。对x.a赋值则会在x的实例字典创建名为"a"的键，它的值将会遮蔽(shadow)同名类属性(因为属性查找顺序)。当x.a被删除后，被遮蔽的值(1)又能访问到了。&lt;br /&gt;&lt;br /&gt;不幸的是，一些Python开发人员发现这种机制存在缺陷。缺陷之一是这种机制下无法创建"混合"类，也就是部分方法用Python实现，部分方法用C实现的类，因为这种机制下只有Python函数才会被包装，使得调用时能访问实例，而且这一行为是硬编码在语言中。而且也没有明显的方式来定义其它类型函数，例如C++和Java程序员熟悉的静态成员函数。&lt;br /&gt;&lt;br /&gt;为了解决这一问题，Python 2.2对上述包装行为的进行了直观的泛化。不再用硬编码方式指定只对Python函数对象进行包装，而对其它对象不做包装。包装相关行为完全留给属性搜索到的对象来处理(上例中是函数f)。如果查找属性时的查找结果是有一个名为__get__特殊方法的对象，则该对象被认为是一个"descriptor"对象，这时__get__方法被调用，由它的返回值都作为属性查找结果。如果该对象没有__get__方法，则不作变化直接返回查找到的对象。要得到原有行为(对函数对象进行包装)而且不需要在实例属性查找代码中对函数对象特殊处理，现在拥有一个__get__方法的函数对象将如同以前一样返回包装对象。而且，用户还可以定义含有名为__get__方法的另外一个类，当这种类的实例在原来的类字典中被属性查找过程找到时，可以按需灵活进行包装。&lt;br /&gt;&lt;br /&gt;在对属性查找这一概念进行泛化后，同样思路也有必要推广到属性的赋值与删除操作。因此，对赋值操作x.a=1或者删除操作 del x.a也有相似的处理机制。这时，如果属性"a"是在实例的类字典(而不是实例字典)中，检查类字典的中该对象是否含有名为__set__和__delete__的特殊方法(__del__已另有它用)。这样，通过实现这些函数，一个descriptor对象可以完全控制一个属性的get、set和delete含义。要强调的是，这些定制操作仅是对类字典中descriptor实例而言的，对象实例字典中则无效。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;staticmethod, classmethod, and property&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Python2.2利用这一新的descriptors机制增加了三个预定义类：类方法(classmethod)，静态方法(staticmethod)和property，类方法和静态方法只是简单包装函数对象，通过__get__方法的具体实现，来返回不同种类的封装器(wrappers)。例如，静态方法在函数调用时封装器对参数列表不做任何修改。类方法在函数调用时将封装器将实例的类对象增加为第一个参数，而不是增加实例本身。这两种类型的方法都可以通过实例或者类来调用，且在不同调用者情况下调用时的参数相同。&lt;br /&gt;&lt;br /&gt;property类封装器将取值和赋值这一对方法转换为一个"属性"。例如，如果你有如下一个类，&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class C(object):&lt;br /&gt;    def set_x(self, value):&lt;br /&gt;        self.__x = value&lt;br /&gt;    def get_x(self):&lt;br /&gt;        return self.__x&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;property封装器可用来产生一个属性"x"，当存取x时隐含方式调用了get_x和set_x方法。&lt;br /&gt;&lt;br /&gt;一开始引入类方法、静态方法和property这些descriptors时，并没有同时引入相应的新语法。当时看起来同时引入比较重要的新特性以及相应的语法引起的争议过大(新语法的讨论总是引起激烈争论)。因此使用这些特性时，先依照常规定义类和方法，然后用额外语句来"包装"方法，例如：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class C:&lt;br /&gt;    def foo(cls, arg):&lt;br /&gt;        ...&lt;br /&gt;    foo = classmethod(foo)&lt;br /&gt;    def bar(arg):&lt;br /&gt;        ...&lt;br /&gt;    bar = staticmethod(bar)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;对properties也有类似机制:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class C:&lt;br /&gt;    def set_x(self, value):&lt;br /&gt;        self.__x = value&lt;br /&gt;    def get_x(self):&lt;br /&gt;        return self.__x&lt;br /&gt;    x = property(get_x, set_x)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Decorators&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;这种方式有一个不利之处，用户阅读类的代码时，只有读完一个方法的声明，到了结尾部分才知道该方法是不是类方法或者静态方法(或其它用户自定义形式)。终于，Python2.4引入了新的语法，允许以如下方式撰写代码：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class C:&lt;br /&gt;    @classmethod&lt;br /&gt;    def foo(cls, arg):&lt;br /&gt;        ...&lt;br /&gt;    @staticmethod&lt;br /&gt;    def bar(arg):&lt;br /&gt;        ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;在函数声明前一行构造的@表达式(@expression)称为decorator。(不要和前面的descriptor混淆，实现__get__包装时所讨论到的才是descriptor。)选择这个decorator语法(decorator syntax)(从Java的annotations借鉴而来。)引起了无休止的争论，最终由BDFL宣告(BDFL pronouncement)来确定。(David Beazley写了一篇关于术语BDFL的历史典故，我会另外单独写一篇贴出。)&lt;br /&gt;&lt;br /&gt;decorator特性已成为最成功的Python语言特性之一，各种decorator应用超过我当初最乐观的期待。特别是在Web框架中大量应用。鉴于如此成功，在Python2.6中，decorator语法从函数定义进一步扩展到类定义。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Slots&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;descriptor的引入带来了另外一个新特性，也即类的__slots__属性。例如一个类，定义如下：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class C:&lt;br /&gt;    __slots__ = ['x','y']&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这儿的__slots__有如下含义。首先，对象的有效属性名被限制为__slots__值的列表。其次，由于属性名范围已经确定，__dict__属性因不再需要而被移除(除非某个基类已经包含了__dict__属性，子类化当前类且不包含__slots__属性可以再次拥有__dict__属性)。这样各属性存储在预先确定顺序的array中。因此，每一个slot属性实际是一个descriptor对象，利用该属性在array中的位置(index)来调用其set/get方法。在具体实现方面，该特性完全由C语言实现，性能优异。&lt;br /&gt;&lt;br /&gt;一些人错误的认为__slots__的目的在于(通过限制属性名)增加代码的安全性。实际上，我的终极目标聚焦在性能方面。__slots__是一个有趣的descriptor应用，我担心对类的改动总是带来性能方面的不利影响。以descriptor而言，为了使之正常工作，对象属性的任何操作都需要首先检查类字典来判定该属性是否实际上是一个数据descriptor(data descriptor)。如果确实是，则由该descriptor负责属性存取，而不是通常情况下直接操作属性字典。这个额外的检查也意味着检查每个实例的字典之前要有一个额外的查找操作。因此，__slots__可以作为一种优化数据属性的方法，作为当有人对新类的性能不满意时的补救。结果证明这种性能的担心并不必要，但是撤除__slots__也为时已晚了。而且，正确使用slots确实能增加性能，尤其是创建大量小对象时有利于降低内存占用。&lt;br /&gt;&lt;br /&gt;我把Python MRO(Method Resolution Order方法解析顺序)的介绍留在下一篇。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-4306833589441176800?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/4306833589441176800/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=4306833589441176800' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/4306833589441176800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/4306833589441176800'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2010/06/inside-story-on-new-style-classes.html' title='The Inside Story on New-Style Classes'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-952654024464603197</id><published>2010-06-22T08:00:00.003+08:00</published><updated>2010-06-23T23:58:08.940+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>New-style Classes</title><content type='html'>新类&lt;br /&gt;&lt;br /&gt;英文原文链接: &lt;a href="http://python-history.blogspot.com/2010/06/new-style-classes.html"&gt;http://python-history.blogspot.com/2010/06/new-style-classes.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者: Guido van Rossum&lt;br /&gt;&lt;br /&gt;[漫长的间歇，本系列blog回归了！我将接着去年的写，我尽量加快速度。]&lt;br /&gt;&lt;br /&gt;前面我提到Python中对类(Class)的支持是后来添加的。具体实现符合典型的Python式“抄近路”哲学(cut corners)，然而随着Python的发展，类(Class)的实现暴露出各种问题，也成为了Python高级用户的热门话题。&lt;br /&gt;&lt;br /&gt;类(Class)实现问题之一是限制了对内置类型(built-in types)的子类化(subclass)，例如lists, dictionaries, strings和其它一些对象(object)成为无法子类化的“特殊”类型。对于一门“面向对象(object oriented)”语言来说，这种限制多少有些尴尬。&lt;br /&gt;&lt;br /&gt;另一问题是整个类型系统(type system)对于用户自定义类(user defined classes)来说是“错”的。假如你创建两个对象a和b，即使a和b是毫无关联的两个类的实例，语句type(a) == type(b)的值仍为真。无须讳言，对于熟悉C++或者Java语言的程序员来说，由于C++和Java等语言中类(Class)与底层的类型系统(type system)紧密相连，该现象相当诡异。&lt;br /&gt;&lt;br /&gt;在Python的2.2版本，我重写了类实现，而且是“正确的实现”。这次重写一个Python主要子系统是目前为止最为野心勃勃的变动，肯定会有人因此说我得了“第二系统综合症(second-system syndrome)”。这次重写，不仅解决了内置类型的子类化这一直接问题，我还增加了对真正的元类(metaclass)的支持，并尝试改善原来多重继承(multiple inheritance)时过于简陋的方法解析顺序(method resolution order)。这项工作的主要受Ira Forman和Scott Danforth撰写的《Putting Metaclasses to Work》影响，书中阐明了元类的概念，及其与Smalltalk中类似概念的区别。&lt;br /&gt;&lt;br /&gt;这次重写类实现的一个特点是，新类(new-style class)是作为语言的一个新特性引入，而不是完全替换掉旧的类。实际上为了保持向后兼容，Python 2中缺省生成的类仍然是旧的类。要创建一个新类，你只需子类化一个现存的新类，例如object(object是新类类层次的根)。例如：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class A(object):&lt;br /&gt;    statements&lt;br /&gt;    ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这次新类的引入取得的成绩斐然。新的元类得到了框架实现者的积极支持，实际上由于例外情况变少也使得讲解类更为容易。向后兼容使得新类进化过程中旧类依然正常工作。最后，虽然旧类终将从语言中移除，用户已习惯了用"class MyClass(object)"来声明一个类，也不错。&lt;br /&gt;--&lt;br /&gt;cut corners可参考前期博文:&lt;a href="http://python-history.blogspot.com/2009/01/pythons-design-philosophy.html"&gt;英文&lt;/a&gt;或&lt;a href="http://python3.blogspot.com/2009/04/python.html"&gt;中文译文&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;second-system syndrome可参考：&lt;a href="http://en.wikipedia.org/wiki/Second-system_effect"&gt;http://en.wikipedia.org/wiki/Second-system_effect&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-952654024464603197?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/952654024464603197/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=952654024464603197' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/952654024464603197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/952654024464603197'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2010/06/new-style-classes.html' title='New-style Classes'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-4981106304143288579</id><published>2009-05-01T12:30:00.000+08:00</published><updated>2009-05-01T16:26:14.079+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>元类与扩展类(传说中“杀手的笑话”)</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/04/metaclasses-and-extension-classes-aka.html"&gt;http://python-history.blogspot.com/2009/04/metaclasses-and-extension-classes-aka.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;在Python本来的实现中，类是一类公民对象，可以像处理其它对象一样来操作类。然而创建一个类的过程却固定不变。具体来说，当你定义如下一个类时：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class ClassName(BaseClass, ...):&lt;br /&gt;     ...method definitions.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;类的内容将会运行在它自身的局部字典。类的名字，基类组成的tuple，和这个局部字典将会传递给内部负责生成类对象的类创建函数。类对象生成的动作隐藏在幕后，一般用户对实现细节不需关心。&lt;br /&gt;&lt;br /&gt;Don Beaudry是第一个指出如此设计让专业用户失去深层次控制机会的人。具体来说，既然类只是诸多对象的一种，为何不能创建新种类的类来定制其行为呢？他还提出了一个方案，只需对解释器稍加修改就可以利用C代码生成允许新类型的类对象了。关于相关修改的介绍最初出现在1995年，长期被称作“Don Beaudry hook”或者“Don Beaudry hack”，命名不明确是故意开玩笑的结果了。Jim Fulton随后对修改进行了通用性改善，这个修改一直保留在语言中(尽管文档中未说明)直到Python2.2版本为止，那时通过new-style class的引入对元类有了真正的支持(详情见下文)。&lt;br /&gt;&lt;br /&gt;Don Beaudry hook的基本想法是，如果在类生成的最后阶段能支持由用户提供的函数，那么专业用户就可以创建定制的类对象。具体来说，如果类名、基类、局部字典可以传递给不同的构建函数，那么该函数在创建类对象时就可以随心所欲，自由发挥了。我唯一的顾虑是不希望由此对类语法做过多更动，毕竟已很稳固。&lt;br /&gt;&lt;br /&gt;为了实现目的，这个hook要求用C语言创建一个可被调用(callable)的新类型对象。然后，当这样一个可调用类型的实例在类语句中作为基类时，类创建代码会神秘的调用相应类型对象，而不是标准的类对象。创建类(及其实例)的行为完全依赖于扩展模块提供的可调用对象。&lt;br /&gt;&lt;br /&gt;现代Python用户可能会觉得奇怪，感觉有些绕弯。但在当时，类型对象是不可调用的--例如‘int’不是一个内置类型而是一个内置函数，该函数可以返回int对象的实例，而int类型本身即不易存取也难以调用。用户自定义类当然是可以调用的，不过这是因为最初设计类时就将其当做调用指令的特殊情况。Don Beaudry最终说服我接受这个想法，随后又导致了元类和new-style类，并最终导致经典类的消亡。&lt;br /&gt;&lt;br /&gt;一开始，只有Don Beaudry自己的Python扩展MESS是唯一利用这一特性的。然而到了1996年，Jim Fulton开发了一个十分流行的第三方模块，称为Extension Classes，也利用了Don Beaudry hook。Extension Classes包在Python2.2引入元类作为对象机制的标准部分后最终失去意义。&lt;br /&gt;&lt;br /&gt;在Python1.5中，我去掉了需要写C扩展才能使用Don Beaudry hook的限制。另外为了检查基类类型是否可调用，类生成代码会检查基类中一个名为“__class__”的属性，若存在就调用它。我写了一篇短文介绍这一特性，这是许多Python用户第一次听闻元类的说法。由于这个想法令人头大，很快这篇短文就被冠以昵称“杀手的笑话(The Killer Joke，一个Monty Python里的典故)”。&lt;br /&gt;Don Beaudry hook贡献影响最长的部分应当是类创建函数的API，在Python2.2中新的元类机制中得以保存。如前所述，类创建函数调用时需要三个参数：一个表示类名的string、一个给定基类的tuple(包括基类为空或者只有单个基类情况)和一个内容为方法定义缩进代码块(不仅限于方法，也可以是其它类级别的语句)的字典。类创建函数的返回值是一个类名为名称的变量。&lt;br /&gt;&lt;br /&gt;最初，创建类只有简单的内部API。The Don Beaudry hook运用了同样的调用机制，由此成为公开API。这个API重要一点是包含方法定义的块在类创建函数被调用前就执行了。这一点限制了元类的效用，因此元类不能改变方法定义运行时命名空间的初始内容。&lt;br /&gt;&lt;br /&gt;Python 3000中对此做了改动，现在一个元类在类体运行时可以提供一个替代映射对象。为支持这一点，明确指定元类的语法也做了变动：在基类中使用关键词参数就是为了这个目的而引入的。&lt;br /&gt;&lt;br /&gt;下一篇我会接着写元类如何导致2.2中new-style class的出现(以及在3.0中经典类的消失)。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-4981106304143288579?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/4981106304143288579/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=4981106304143288579' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/4981106304143288579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/4981106304143288579'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/metaclasses-and-extension-classes-aka.html' title='元类与扩展类(传说中“杀手的笑话”)'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-6605682169470757607</id><published>2009-05-01T12:13:00.000+08:00</published><updated>2009-05-01T12:16:20.932+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>新闻！有日语翻译版本啦!</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/04/new-now-in-japanese.html"&gt;http://python-history.blogspot.com/2009/04/new-now-in-japanese.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;现在有一个&lt;a href="http://python-history-jp.blogspot.com/"&gt;日语翻译&lt;/a&gt;的blog了。耶！还有一个&lt;a href="http://elornitorrincoenmascarado.blogspot.com/"&gt;西班牙版本&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/3792639039530184077-6605682169470757607?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/6605682169470757607/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=6605682169470757607' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6605682169470757607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6605682169470757607'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/new-now-in-japanese.html' title='新闻！有日语翻译版本啦!'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-163100079758332200</id><published>2009-05-01T11:24:00.000+08:00</published><updated>2009-05-01T11:30:41.861+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>大蛇在行动</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/04/and-snake-attacks.html"&gt;http://python-history.blogspot.com/2009/04/and-snake-attacks.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Greg Stein&lt;br /&gt;&lt;br /&gt;好，当1995年我第一次接触Python语言的时候，任何把Python和“蛇”联系起来的做法都是禁止的。Python得名于&lt;a href="http://en.wikipedia.org/wiki/Monty_Python"&gt;Monty Python&lt;/a&gt;，而不是爬行动物。如果有人敢说不，那一定是&lt;a href="http://en.wikipedia.org/wiki/Knights_who_say_Ni"&gt;Knights who say Ni&lt;/a&gt;，或者&lt;a href="http://en.wikipedia.org/wiki/Rabbit_of_Caerbannog"&gt;the Rabbit of Caerbannog&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;再往前，回到1994年，当时我正在LPMUD里面玩的乐不思蜀。那时Web还很罕见，宽带更没听说过。大家在玩这些低带宽的娱乐。&lt;br /&gt;&lt;br /&gt;等一下，再往前回一步，到1979年。那时我有了第一台电脑苹果II，&lt;a href="http://en.wikipedia.org/wiki/Colossal_Cave"&gt;Colossal Cave&lt;/a&gt;是我最喜欢的游戏之一。之后不久，我学习和玩Zork。我深深迷恋通过计算机和虚拟故事交互并在故事中流连忘返。游戏勾住了我，让我在计算机里面有了另一个生命。(于是，你可以想象时隔四分之一世纪多之后当我遇到Don Woods时是如何的欣喜若狂！)&lt;br /&gt;&lt;br /&gt;MUD里面的场景深深打动了我。但是我更想从事建立游戏。我遇到了&lt;a href="http://viega.org/"&gt;John Viega&lt;/a&gt;，他是一个&lt;a href="http://en.wikipedia.org/wiki/Lima_Mudlib"&gt;LPMUD游戏的资深作者&lt;/a&gt;、程序员和设计师。当时他在维吉尼亚大学计算机图形实验室工作，参与一个称作Alice的系统。系统设计目的希望降低对计算机知识的要求，需要容易学习以方便用户创见动画人物形象。他们选择了Python语言，这是因为Python的清晰强大易用。&lt;br /&gt;&lt;br /&gt;John是Python的极力拥护者，对我说“你一定要学习Python！”“好的，好的。”，我说。这门语言易学易用又功能强大。Python做任何事情都方便。&lt;br /&gt;&lt;br /&gt;这是1995年二月的事情了，从那以后我在学习使用Python的路上再没有回头。&lt;br /&gt;&lt;br /&gt;当时我根本不知道Python对我的职业和生活有如此关键的作用。感谢Guido，发明了Python。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-163100079758332200?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/163100079758332200/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=163100079758332200' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/163100079758332200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/163100079758332200'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/and-snake-attacks.html' title='大蛇在行动'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-6211984304651118860</id><published>2009-05-01T09:46:00.000+08:00</published><updated>2009-05-01T10:03:55.328+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>Python函数编程特性的起源</title><content type='html'>&lt;p&gt;英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html"&gt;http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;原文作者：Guido van Rossum &lt;/p&gt;&lt;p&gt;&lt;br /&gt;不管别人怎么说的想的，我是从来也没想到Python会被函数式编程语言影响如此之深。我对C和Algol 68这类命令式编程语言更为熟悉，而且即使我设定函数为一类公民对象，我也没有将Python看做是函数式编程语言。然而从一开始，就清楚的发现用户希望利用list和函数做更多的事情。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;一个对list的常见操作是对其每一个元素调用某个函数并将结果生成一个新的list，例如：&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;def square(x):&lt;br /&gt;    return x*x&lt;br /&gt;&lt;br /&gt;vals = [1, 2, 3, 4]&lt;br /&gt;newvals = []&lt;br /&gt;for v in vals:&lt;br /&gt;    newvals.append(square(v))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Lisp和Scheme等函数式编程语言会提供内置函数来实现类似操作。因此熟悉这些语言的早期用户会自己动手在Python中实现类似功能的函数，例如：&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;def map(f, s):&lt;br /&gt;    result = []&lt;br /&gt;    for x in s:&lt;br /&gt;            result.append(f(x))&lt;br /&gt;    return result&lt;br /&gt;&lt;br /&gt;def square(x):&lt;br /&gt;    return x*x&lt;br /&gt;&lt;br /&gt;vals = [1, 2, 3, 4]&lt;br /&gt;newvals = map(square,vals)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;上述代码的一点小问题是许多人不喜欢应用到列元素的操作被分开定义为一个的单独函数。Lisp等语言允许在进行映射函数调用时直接“当场”定义函数。例如，在Scheme语言中你可以利用lambda在一条语句中创建匿名函数并执行映射操作，像下面这样：&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;    (map (lambda (x) (* x x)) '(1 2 3 4))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;虽然Python中函数是一类公民对象，当时并没有任何创建类似匿名函数的机制。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;到1993年底，用户已经提出了各种创建匿名函数的思路，和各种list操纵函数如map()、filter()和reduce()。例如，Mark Lutz(《Programming Python》的作者)贴过一段利用exec来产生函数的函数代码：&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;def genfunc(args, expr):&lt;br /&gt;    exec('def f(' + args + '): return ' + expr)&lt;br /&gt;    return eval('f')&lt;br /&gt;&lt;br /&gt;# Sample usage&lt;br /&gt;vals = [1, 2, 3, 4]&lt;br /&gt;newvals = map(genfunc('x', 'x*x'), vals)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Tim Peters又跟进提出了一个语法上略微简化的方案，允许用户这样写代码：&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;vals = [1, 2, 3, 4]&lt;br /&gt;newvals = map(func('x: x*x'), vals)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;这些都表明了对这一功能确有实际需求。然而当时利用exec手工将包含代码的字符串转换为匿名函数过于“儿戏”。于是1994年1月，map()、filter()和reduce()被添加到标准库。另外，lambda操作符也被语法上直观的引入以创建匿名函数(或称匿名表达式)。例如：&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;vals = [1, 2, 3, 4]&lt;br /&gt;newvals = map(lambda x:x*x, vals)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;这些是早期的重要贡献代码。不幸的是我想不起作者是谁了，而SVN的日志也没有记录。如果是你的话，请留言！&lt;/p&gt;&lt;p&gt;&lt;br /&gt;我从来也没有喜欢过“lambda”这个术语，但是又找不到更合适的替代者，于是也只好用了这个。毕竟lambda是当时无名代码贡献者的选择，那时大的改动比现在需要的讨论要少的多，讨论少的影响&lt;a href="http://www.python.org/dev/peps/pep-0001/"&gt;有好&lt;/a&gt;也&lt;a href="http://yellow.bikeshed.com/"&gt;有坏&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Lambda最初只用来当做定义匿名函数的语法工具。然而选择lambda这个词带来了许多意外后果。例如熟悉函数式编程语言的用户希望Python中的lambda能和其它语言相似。结果他们发现Python的实现缺少对高级特性的支持。例如一个小问题是lambda表达式无法引用上下文中变量。于是下面代码中map()函数将会出错，提示lambda函数中引用了未定义的变量“a”。&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;def spam(s):&lt;br /&gt;    a = 4&lt;br /&gt;    r = map(lambda x: a*x, s)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;可以用下面代码来凑活着解决这个问题，不过涉及设置缺省参数和传递隐含参数很不直观：&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;def spam(s):&lt;br /&gt;    a = 4&lt;br /&gt;    r = map(lambda x, a=a: a*x, s)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;这个问题的“标准”答案是对所有被函数引用的相关上下文中局部变量，内部函数隐含支持对这些变量的引用。这也就是“闭包(closure)”，函数式编程语言中的一个关键特性。然后Python直到2.2版本才引入对闭包的支持(python2.1版本也可以通过“from the future”方式使用)。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;有意思的是，map、filter和recude函数，他们是最初引入lambda和其它函数式编程语言特征的源动力，自身却很大程度上被list comprehensions和generator expressions盖过了风头。以至于在Python3.0中reduce函数已经从内置函数列表中移除。(不必担心lambda、map和filer，他们已经被保留了:-)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;要提到的是，即使我还是没有把Python当做函数式编程语言的情况下，闭包的引入却成功的用于开发其它高级语言特性。例如new-style class的某些方面，decorator和依赖它的其它现代特性。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;最后，即使一部分函数式编程语言特征已引入多年，Python仍然缺乏一些“真正”函数式编程语言的特性。例如Python不支持特定情况的优化(例如尾递归)。总起来说，因为Python的深度动态本质，无法做到Haskell或者ML这类函数式编程语言的编译时优化。&lt;a href="http://hugunin.net/story_of_jython.html"&gt;这是好事&lt;/a&gt;。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-6211984304651118860?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/6211984304651118860/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=6211984304651118860' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6211984304651118860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6211984304651118860'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/origins-of-pythons-functional-features.html' title='Python函数编程特性的起源'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-5606046891450307587</id><published>2009-05-01T07:23:00.000+08:00</published><updated>2009-05-01T07:37:07.636+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>大改名</title><content type='html'>&lt;p&gt;英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/03/great-or-grand-renaming.html"&gt;http://python-history.blogspot.com/2009/03/great-or-grand-renaming.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Python初创时期，我总是将其作为一个独立程序来用，偶尔连接一些第三方库进来。因此源代码随意定义全局名称(当然要符合C/连接器要求)例如“object”、“getlistitem”和“INCREF”诸如此类。随着Python流行开来，人们开始要求“嵌入”版本的Python，以便Python自身作为一个库供其它应用程序连接-这和Emacs与Lisp解释器之间混合的方式还不一样。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;糟糕的是，嵌入由于命名冲突而复杂化，Python全局名和那些嵌入Python的应用之间会发生名称冲突-特别是“object”很常见。为了解决这个问题而进行了命名约定，约定所有的Python全局名称开头为“Py”或者“_Py”(用于因技术原因不得不作为全局变量的内部名称)或者“PY”(用于宏)。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;为了向下兼容(已经有许多第三方扩展模块)和方便核心开发人员转换(在他们的大脑中原来的旧名字已经根深蒂固)分成了两个阶段。第一个阶段连接器看到的是旧名字，而源代码使用的是新名称，用一个包含许多规则的C语言预编译宏来完成转换。第二个阶段连接器看到的是新名字，但是为了继续支持还没移植的原有扩展模块，另外一套宏用于旧名字转换为新名字。在任一阶段，代码都可以在新旧名字混合情况下正常工作。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;我研究了一下&lt;a href="http://svn.python.org/view/python/trunk/"&gt;Subversion日志&lt;/a&gt;中名称改变的历史。我发现1995年1月12日的&lt;a href="http://svn.python.org/view?view=rev&amp;amp;revision=4583"&gt;r4583&lt;/a&gt;在所有头文件中引入新名称，标志伟大改名(great renaming)第二阶段的开始。然而直到1996年12月C源代码中的改名工作仍在继续进行中。也是大约在这个时候，重命名本身也被重新称呼，checkin comments常称之为“宏大命名(Grand Renaming)”了。在2000年5月，作为Python1.6版本发布的成果之一，向下兼容的宏被移除。check-in comment &lt;a href="http://svn.python.org/view?view=rev&amp;amp;revision=15313"&gt;r15313&lt;/a&gt;庆祝了此一事件。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;此事归功于Barry Warsaw和Roger Masse，他们做了大量细致的工作，对源文件内容逐个进行重新命名(有些脚本来帮助这一过程)。对大量标准库进行unit test也有助于他们重命名，这是又一个繁琐的工作。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Wikipedia上对Great Renaming有一个早期条目，是指USENET groups的改名。我称Python的改名为Great Renaming时可能正模糊记得这一事情。我还看到有些参考资料指向随后Sphinx的Grand Renaming，这是用于生成Python文档的包。看起来Zope也有一个Grand Renaming，最近Py3k也讨论到了术语PyString到PyBytes的重命名(当然这个和前面那些比要小得多)。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;伟大改名或者宏大改名(Great or Grand Renamings)对软件开发社区来说是一个长期的创伤，因为这需要程序员的脑袋接受再教育、重写文档、对改名前提议的补丁集成到到改名后的分支变得困难。(尤其是还存着未改名分支时更是如此。)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-5606046891450307587?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/5606046891450307587/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=5606046891450307587' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5606046891450307587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5606046891450307587'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/great-or-grand-renaming.html' title='大改名'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-1240346519849071901</id><published>2009-04-30T20:04:00.000+08:00</published><updated>2009-04-30T20:11:48.679+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>模块动态载入机制</title><content type='html'>&lt;p&gt;英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/03/dynamically-loaded-modules.html"&gt;http://python-history.blogspot.com/2009/03/dynamically-loaded-modules.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;原文作者：Guido van Rossum &lt;/p&gt;&lt;p&gt;&lt;br /&gt;Python的实现架构使得从一开始就容易使用C写扩展模块。然而最初动态连接技术相当不成熟以至于只能在构建时由Python解释器时静态链接扩展。因此C扩展模块需要附带shell脚本用以给Python和它的扩展模块生成Makefile文件。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;虽然这个方法对小项目来说可以凑活，Python社区产生新扩展模块的速度之快出乎意料，这样可以单独编译和加载模块就成了迫切需求。很快，有人贡献了平台相关的动态链接API编程接口，允许import语句在磁盘上如同以前处理“.py”文件一样寻找共享库。CVS日志中最早提到动态加载是1992年1月的事情，支持主流操作系统要到1994年底才完成。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;动态链接支持被证明是很有用的技术，可惜却带来了维护上的困扰。每个平台有各自独有的API，有的平台还有附加的限制。1995年1月，重构动态链接支持之后，所有相关代码集中在同一个源文件中。然而，这只是集合成一个到处都有条件编译指令(#ifdef)的大文件。1999年12月，在Greg Stein的帮助下，再次重构将每个平台相关的代码保存为专为该平台(或满足同样条件的一系列平台)的设定文件。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;虽然Python支持动态加载模块，对许多用户来说，构建这些模块的过程仍然感觉神秘莫测。许多用户，而且数量还在增长开始构建模块--尤其是SWIG为代表的扩展构建工具出现之后。但是，当用户准备发布一个扩展模块时又要面对巨大障碍了，需要处理模块在各种平台、编译器、连接器的各种组合情况。以至于有时用户需要自己动手写Makefile文件和设置编译器连接器参数的配置脚本。还有一种选择就是用户也可以将自己的模块添加到Python的Makefile，然后设定合适选项后执行部分Python重构建。但是这需要用户手头上就有Python源代码。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;最终，distuils这一Python扩展构建工具出现了，致力于统一解决模块构建和安装问题。必要的编译器和连接器参数写入一个Python makefile文件作为数据文件，在distutils构建扩展模块时会用到。主要由Greg Ward完成，distutils第一个版本单独发布以支持以前的Python版本。从Python1.6开始，Python把distutils当做标准库模块包含进来。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;要提到的是distutils能做的远比从C源代码构建扩展模块要多。它也可以安装纯Python代码的模块和包，创建Windows可执行安装包，以及运行SWIG等第三方工具。哎，distutils由于复杂而被很多人诅咒，也没有得到应有的维护。结果，最近又有第三方替代方案(特别是ez_install，也就是“eggs”)开始流行，可悲的导致了开发社区的分裂，而且也由于同样难以使用在每当不灵的时候就被抱怨。看起来，这问题本质上就是一个难事吧。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-1240346519849071901?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/1240346519849071901/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=1240346519849071901' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1240346519849071901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1240346519849071901'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/dynamically-loaded-modules.html' title='模块动态载入机制'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-6478331482009393867</id><published>2009-04-29T19:14:00.000+08:00</published><updated>2009-04-29T19:49:36.730+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>整数除法问题</title><content type='html'>&lt;p&gt;英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/03/problem-with-integer-division.html"&gt;http://python-history.blogspot.com/2009/03/problem-with-integer-division.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;原文作者：Guido van Rossum &lt;/p&gt;&lt;p&gt;&lt;br /&gt;Python对整数除法的处理是一个早期犯错导致后患无穷的典型范例。前面已经提到创立Python时我抛弃了ABC中采用的数值处理方法。例如，在ABC中当你进行两个整数相除，结果是一个准确的有理数。而在Python中，整数除法的结果被截断为一个整数。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;依据我的经验，ABC中的精确有理数并没有达到设计者的期望。写一个商业应用软件小软件就可以发觉(例如，计算一个人缴税多少)，比通常想象的慢太多。调试程序可发现原因在于程序内部在运算时用数千位精度的有理数来表示数值，这些值在最后输出时精度只要求到小数点后两三位就足够了。这个问题可以利用计算起始时附加一个不完全精确的0来解决，但是这个思路对初学者来说并不直观，且难以调试。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;所以在设计Python时，我参考了自己已经熟悉的C语言的数值模型。C包括各种长度的整数和浮点数。我就选了C的long类型为Python的整数(integer)(可以保证至少有32位精度)，选择C的double表示Python的浮点数(floating point number)。然后我又增加了一个任意精度的整数类型，称为“long。”&lt;/p&gt;&lt;p&gt;&lt;br /&gt;我从C语言还借鉴了一条规则：标准的算术运算，包括除法，返回值总是和操作数同一类型，这条在C中实用的规则在Python这种十分高级的语言(very-high-level language)中则铸成大错。更糟的是，我最初还设定了一个禁止混合类型运算的错误规则，当时这么做的目的是为了让各个类型实现之间互不关联。所以，一开始不能计算int和floating相加，即使int和long也不行。Python公开发布之后，Time Peters很快就说服我禁止混合类型运算是个坏点子，于是我引入常用的强制转换规则(coercion rules)来支持混合类型运算。例如int和long的运算会先把int类型的参数转换为long类型，然后返回long类型的运算结果，任何一个参数为float时就把另外一个参数转换为float类型并返回float类型的运算结果。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;至此大错已成--整数相除返回整数类型结果。你可能会奇怪“不会是杞人忧天吧？”或者庸人自扰吧？随后为了改变这一设定多次遭受Python社区用户坚韧的反对，他们坚持能明白“整除”的含义对是所有程序员必经的“成人礼”。那么，请让我来解释一下我认为这是一条设计缺陷的原因。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;当你写一个实现数值运算的函数(假设，计算月相)你通常希望参数是浮点数类型。然而，由于Python没有类型声明，就无法阻止函数调用者传递整数参数。对于C这类静态类型语言，编译器可以强制转换参数为浮点数，然而这在Python中不存在-算法中各步骤将会一直用整形计算直到遇到和浮点数的混合运行后才会恢复中间计算结果为浮点数类型。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;除了除法之外的其它运算，整数和浮点数的行为是一致的。例如1+1等于2，恰如1.0+1.0是2.0，其它运算也是。这就很容易造成一种假象：数值算法的参数是整数还是浮点数无关紧要。然而，当除法参与进来，两个运算数都是整数时，运算结果直接截断，这造成运算中一个潜在质的误差。虽然可以通过在函数入口强制转换所有参数为浮点数来进行保护，这样很不方便，也无助与代码的可读性和可维护性。另外，这样也限制了算法同时支持复数类型参数(当然这种情况很罕见)。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;回过来还是要说，问题原因全在于Python不能自动转换参数到预先声明的类型。传递一个无效参数，例如字符串，通常很容易发现，因为很少有运算支持字符串/数值混合类型的运算(除了乘法)。然而传递整数参数时，可能会得到和正确答案相近却可能有相当大误差的结果-很难调试甚至不容易发现问题。(最近我又遇到这样的情况，是在画一个模拟时钟时候--表针的位置由于整除截断而不准确，但是错误却不容易看到，只有每天某些特定时刻才比较明显。)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;修正整除错误不是一件简单的事情，因为程序已经依赖整除截断行为了。语言增加了整除运算符(//)来提供原有截断语义。另外通过(“from __future__ import division”)机制可使整数除法使用不再截断的新语义。最后，还可以通过添加命令行参数(-Qxxx)使用新语义或者辅助代码转换到新语义。幸运的是，Python3000中除法的缺省行为是正确的。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-6478331482009393867?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/6478331482009393867/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=6478331482009393867' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6478331482009393867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6478331482009393867'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/problem-with-integer-division.html' title='整数除法问题'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-7983963092438059361</id><published>2009-04-29T10:52:00.001+08:00</published><updated>2009-04-29T10:57:46.975+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>用类来表示异常</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/03/how-exceptions-came-to-be-classes.html"&gt;http://python-history.blogspot.com/2009/03/how-exceptions-came-to-be-classes.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;在初期我就希望Python用异常来处理出错。然而让异常有效工作的关键之一便是设定识别不同种类异常的方案。现代语言(包括现代Python:-)，异常是通过用户自定义类来表示的。然而在Python的早期版本，我是用字符串来表示异常的。这很糟糕，但是我有两个借口来解释为何这样做。首先我是从Modula-3中学习异常的，那里就是用特定标识符来表示异常。其次，我引入异常时，还没有引入用户自定义类。&lt;br /&gt;&lt;br /&gt;理论上我是可以建立一个新的内置对象类型来用于表示异常，然而实现内置类型需要相当的C语言编程工作，我决定还是重用已有的内置类型。而且，既然异常时总有伴随的出错信息，看起来用字符串来表示异常也很自然。&lt;br /&gt;&lt;br /&gt;不幸的是，我选择的语义是不同字符串对象表示不同异常，即使两者有相同的值(即由同样的字符序列构成)。我之所以选择这样的语义是因为我希望定义在不同模块的异常即使值相同仍然互相独立。意思是说，异常是通过对其名字的引用(异常对象)来判定，而不是通过它的值(字符串值)。&lt;br /&gt;&lt;br /&gt;这个方法受到了Modula-3异常机制的影响，在Modula-3中每个异常声明都建立一个唯一的不会和其它异常混淆的“异常标识符”。我想我也希望能优化异常处理，就是通过指针比较而不是串比较，这样做属于过早优化运行时间的一个错误尝试(罕见-我通常是优化自己写代码的时间！)。当然主要的原因还是我担心不同模块的无关异常会发生同名冲突。我设定的应用模式是在某一模块中定义异常，然后在所有代码中将其作为全局常量来抛出或捕获。(这也比字串值会自动“interned”早很多。)&lt;br /&gt;&lt;br /&gt;哎，真是好事多磨。早期的Python用户发现在同一个模块内，字节码编译器会将值相等的字符串统一表示(也就是说创建单一的对象来表示所有值相同的字符串)。因此，用户偶尔会发现异常可被指定异常名捕获，也可以被同值的字符串捕获。好吧，至少看起来大多数情况下是工作的。但是实际上只是在同模块情况下才存在这一情况--如果要捕获其它模块定义的异常错误信息，就会发生神奇的实效。不必说，这引起了普遍的困扰。&lt;br /&gt;&lt;br /&gt;1997年在Python1.5版本我引入类异常到语言中。虽然类异常从此就是推荐方法，字符串异常也为了继续支持一些已有应用代码而被支持，直到Python2.5。最终在Python2.6才移除了字符串异常。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-7983963092438059361?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/7983963092438059361/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=7983963092438059361' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/7983963092438059361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/7983963092438059361'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/how-exceptions-came-to-be-classes.html' title='用类来表示异常'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-7422282268823061156</id><published>2009-04-28T22:16:00.000+08:00</published><updated>2009-04-28T22:21:16.225+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>为何实现一切皆成为可执行语句</title><content type='html'>&lt;p&gt;英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/03/how-everything-became-executable.html"&gt;http://python-history.blogspot.com/2009/03/how-everything-became-executable.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;原文作者：Guido van Rossum &lt;/p&gt;&lt;p&gt;&lt;br /&gt;Python新用户有时对语言的任一部分，包括函数和类定义，均能作为可执行语句产生惊奇。这意味着任何语句可以出现在程序的任意地方。例如，如果需要，函数定义可以出现在“if”语句中。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Python语法的初期版本，情况并不是这样的：具有“申明特征”的语法元素，例如import语句和函数定义，只允许出现在模块和脚本(被执行的那个程序)的顶级。然而，当我增加类的时候，我觉得这样过于限制。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;我的推理过程如下。与其定义类为纯粹的一系列函数定义语句，看起来允许赋值常规变量也有意义。然而，既然允许这样，我何不更进一步，允许任意的可执行代码呢？或者，更彻底一些呢，例如允许在“if”语句中允许函数定义？很快就发现这样可用于简化语法，对它们可以采用相同的字节码生成函数。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;虽然这个原因使我简化了语法，也允许用户在任意位置放置Python语句，这个特性并不意味着一定要支持某个特定编程风格。例如，Python语法在技术上允许定义嵌套函数，然而Python并不支持嵌套命名空间的潜在语义。因此，类似的代码常会运行怪异或者“坏掉”，毕竟不能和那些专门设计出来的语言特性相比。随着时间的过去，许多“坏掉”的特性被修正。例如嵌套函数定义在Python2.1之后才开始工作的正常起来。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-7422282268823061156?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/7422282268823061156/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=7422282268823061156' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/7422282268823061156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/7422282268823061156'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/how-everything-became-executable.html' title='为何实现一切皆成为可执行语句'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-6990064954963013305</id><published>2009-04-28T21:39:00.000+08:00</published><updated>2009-04-28T21:49:03.450+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>一切都是一类公民</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/02/first-class-everything.html"&gt;http://python-history.blogspot.com/2009/02/first-class-everything.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;[朋友们，请不要在这个Blog的评论部分提问题。如果你想建议这个Blog将来写些什么，给我发email(用Google可以搜到我的主页，那儿有我的email地址。)如果你想提出Python的改进建议或者讨论某种替代设计的价值，用python-ideas邮件列表在python.org。]&lt;br /&gt;&lt;br /&gt;我的Python设计目标之一就是所有的Python对象都是“一类公民”。也就是说我希望所有可以在语言中命名的对象(例如整数、字符串、函数、类、模块、方法等)都有同样的地位。这样他们都可以有赋值给变量、放入list、存储在dictionary、传递给参数等操作。&lt;br /&gt;&lt;br /&gt;Python的内部实现机制使得这个目标变得简单。所有的Python对象都基于一个共同的C语言数据结构，可在解释器中任意地方调用。变量，list、函数以及其它任一对象都是这个数据结构的变种--这个结构是表示一个如整数这样简单的对象还是像类这样复杂的对象并不重要。&lt;br /&gt;&lt;br /&gt;虽然拥有“一切都是一类公民”想法在概念上很简单，仍然有一点和类相关的细微之处值得我再谈谈--也就是让方法成为“一类公民”对象的问题。&lt;br /&gt;&lt;br /&gt;考虑如下简单的代码(从上周的博文拷贝而来)：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class A:&lt;br /&gt;     def __init__(self,x):&lt;br /&gt;         self.x = x&lt;br /&gt;     def spam(self,y):&lt;br /&gt;        print self.x, y&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;如果方法是“一类公民”对象，那么在Python中它就应该可以像其它对象那样赋给其它变量。例如，一个人可以写“s = A.spam”的代码。这时变量“s”代表了类的一个方法，实际上是一个函数。然而方法和一个普通函数不尽相同。具体来说，方法的第一个参数应当是方法被定义时所在类的实例。&lt;br /&gt;&lt;br /&gt;为了解决这个问题，我创建了一个新的类型，它是可调用对象，称为“未绑定方法(unbound method)”。一个未绑定方法实际上是实现方法的函数对象的简单封装，强制第一个参数必须是方法所在类的实例。因此，需要像调用函数那样调用未绑定方法“s”时，就必须传递类A的一个实例作为第一个参数。例如"a = A(); s(a)"[译者注:根据上下文，为能运行，需补全参数，如“a = A(1); s(a, 2)”]。 (*)&lt;br /&gt;&lt;br /&gt;一个相关联问题在Python语句是某对象特定实例的方法时会遇到。例如，可以创建一个实例“a=A()”然后再写一句“s = a.spam”。此处变量“s”还是指向类的spam方法，然而这次“s”是通过类的实例“a”得到方法引用的。为了处理这种情况，创建了另一种被称为“绑定方法(bound method)”的可调用对象。这个对象也是表示方法的函数对象的简单封装。但是这次封装隐含的将得到方法时用到的实例存储起来。因此，对随后的“s()”语句，将会在调用方法时把实例“a”作为隐含的第一个参数。&lt;br /&gt;&lt;br /&gt;实际上，表示绑定和未绑定方法是同一个内部对象类型。该对象一个某个属性指向对实例的引用。设置为None时，方法是未绑定的。否则就是绑定的。&lt;br /&gt;&lt;br /&gt;虽然绑定与否可能看起来没什么重要的，确是类内部工作的一个关键部分。当程序中出现“a.spam()”时，这条语句的执行实际上分为两步。首先，查找“a.spam”发生之处。返回一个绑定方法--这是一个可调用对象。然后，在附加用户提供的参数之后，对这个对象进行函数调用“()”&lt;br /&gt;__________(*)&lt;br /&gt;在Python 3000中，未绑定方法的概念被去除，表达式“A.spam”返回一个简单的函数对象。这是以前的应用经历证明的：由于限制第一个参数必须是A的一个实例对于诊断问题帮助甚微，反而经常成为高级应用的障碍--这种高级应用有人称作“self的鸭子类型(duck type self)”，看起来是个不错的名字。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-6990064954963013305?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/6990064954963013305/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=6990064954963013305' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6990064954963013305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/6990064954963013305'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/first-class-everything.html' title='一切都是一类公民'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-5461713738785144354</id><published>2009-04-28T18:31:00.000+08:00</published><updated>2009-04-28T19:13:29.114+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>增加对用户自定义类的支持</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html"&gt;http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;信不信由你，Python在CWI开发了一年之后才增加了类(class)，当然这仍在首次公开发布Python之前了。要知道如何添加类，有必要先知道一些Python的实现细节。&lt;br /&gt;&lt;br /&gt;Python是用C语言实现的，属于一个典型的基于堆栈的字节码解释器也可以称作“虚拟机”外加一些也是用C实现的基本类型。虽然Python中到处都是对象(“object”)，然而C语言中并不直接支持对象而是通过结构(structure)和函数指针(function pointer)来实现。Python虚拟机对每个对象类型定义了几十个必须或者可选支持的操作(例如，“get attribute”、“add”和“call”)。于是一个对象类型就表示为一个含有一系列函数指针的静态分配结构，每个函数指针对应一个标准操作。这些函数指针通常初始化为静态函数。但是对可选操作，类型对象选择不做对应实现时可以将其函数指针指向空地址。调用该操作时虚拟机或者产生一个运行时错误，或者在某些情况下提供一个该操作的缺省实现。一个类型的结构还包含各种数据域，其中之一是对该类型特有方法list的引用，表示为一个结构数组，该数组包含string(作为函数名)和函数指针(对应函数实现)。Python特有的自省就源于一个对象可以在运行时如同访问其它对象一样访问自身类型的结构。&lt;br /&gt;&lt;br /&gt;Python实现的重要一个特点就是完全以C为中心。实际上所有的标准操作和方法(method)都是用C语言的函数现的。最初字节码解释器只能支持纯Python的函数或者C实现的函数和方法。我记得是同事Siebren van der Zee第一个建议Python应当允许和C++类似的类定义以便在Python代码中定义对象。&lt;br /&gt;&lt;br /&gt;在实现用户定义对象时我遵守了设计尽量简单原则；方案是使用一种新的内置(built-in)对象来表示该对象，它存储类引用作为指向为该类所有实例共享“类对象”的指针，配合一个“实例字典”来保存实例的变量。&lt;br /&gt;&lt;br /&gt;这个实现方案中，实例字典包括每个单独对象的实例变量而类对象则包括该类所有实例的共享部分--特别是方法。在实现类对象时我再次运用设计尽量简单原则；一个类拥有的方法存储在一个字典中，以函数名为key。于是我配套了一个类字典。为了支持继承，类对象还需要另外保存表示基类对象的引用。当时我对类所知甚少，却也知道C++刚刚支持的多重继承。我想既然要支持继承，最好也支持一个简单版本的多重继承。于是每个类对象可以有一个或多个基类。&lt;br /&gt;&lt;br /&gt;在这个实现中对象操作的机理十分简单。对实例和类变量的操作只是简单的对应到其字典对象上。例如，给实例变量赋值就是更新它的局部实例字典。同样的，在实例对象中查找变量的值只是简单检查它的实例字典中对应变量。如果没有找到该变量，事情会变得复杂一点。这时会在类字典中进行查找，然后遍历类的基类类字典进行查找。&lt;br /&gt;&lt;br /&gt;查找类对象及基类属性(attribute)的过程通常都是和定位方法一致的。如前所述，方法存储在类对象字典里为该类所有实例共享。因此，调用一个方法时，通常在具体实例对象的实例字典里面是找不到对应入口。相反，你需要先在类字典里面查找，然后顺序在其基类的类字典里查找，一旦找到就立即停止查找过程。对每个基类来说也递归的实现同样的查找策略。这个策略通常称为深度优先，从左至右，也是Python原来大多数版本采用的缺省方法解析顺序(MRO：method resolution order)。新近的Python版本采用了一个更复杂的MRO，后面的博文会讨论到。&lt;br /&gt;&lt;br /&gt;实现类时尽量简单是我的目标之一。因此Python定位方法时不执行复杂的错误检查或者一致性检查。例如，如果某个类重载了基类的某个方法，并不进行检查以确保重新定义的方法和原基类实现有相同的参数个数或者一致的调用方式。前述的方法解析算法只是简单的返回第一个找到的结果，然后不论有什么参数，都在调用该结果时提供给它。&lt;br /&gt;&lt;br /&gt;其它一些特性也在设计中引入。例如，虽然类字典最初设计时是为了存储方法的，也没有理由说一定不能存储其他类型的对象。因此，如果某个integer或者string对象存储在类字典中，它就成为一个类变量--它不存储在每个实例变量中，而是存在类中为所有该类实例共享。&lt;br /&gt;&lt;br /&gt;类的实现不仅简单，还提供了令人惊奇的灵活性。例如，具体实现不仅使得类成为“一类公民”从而在运行时很容易进行自省，还使得动态进行类的修改成为可能。例如类对象已经生成之后，通过简单的增加或者修改类字典就可以修改类的方法！(*) Python的动态本质使得修改立刻对所有该类及其子类的的实例生效。同样，单个对象可以通过动态的增加、修改和删除实例变量来进行修改。(这个我后来才知道的特性使得Python实现的对象比Smalltalk中的更灵活，后者局限在对象创建时指定的属性范围内)。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;类语法开发&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;设计了用户定义类和实例的运行时表示之后，我的下一个任务是设计类定义的语法，特别是类包含的方法定义。设计时一条主要约束原则是我不希望给方法添加与函数不同的语法。重构语法和字节码解释器来处理如此相似的不同事物看起来是个艰巨任务。然而，即使在我成功的保持了语法一致之后，仍然需要找到处理实例变量的合适途径。开始，我想模拟C++中处理实例变量的隐含方式。例如，C++中，类定义代码如下：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:c"&gt;&lt;br /&gt;class A {&lt;br /&gt;public:&lt;br /&gt;   int x;&lt;br /&gt;   void spam(int y) {&lt;br /&gt;        printf("%d %d\n", x, y);&lt;br /&gt;   }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;在类中，实例变量x被声明，在方法中，对x的引用到实例变量是通过隐含方式的。例如在spam() 方法中，变量x既不是函数参数，也不是局部变量，又在类中声明为实例变量的情况下，很简单x就是该实例变量。虽然我也想提供类似的方法，很快就发现对于没有变量声明的语言不存在这样的方法，因为无法简洁的区分实例变量和局部变量。&lt;br /&gt;&lt;br /&gt;虽然理论上得到一个实例变量的值很容易。Python已有的变量名查找顺序是：局部、全局和内置。每个都表示为变量名和值映射的字典。因此，查找任一变量名就是一系列的字典搜索，直到找到第一个匹配成功。例如，当运行一个包含局部变量p和全局变量q的函数时，语句“print p, q”首先查找p，并在搜索顺序的第一个字典(包含局部变量)找到。接下来，在第一个字典中查找q，找不到，然后在第二个字典(全局变量)中继续查找，并找到q。&lt;br /&gt;&lt;br /&gt;把当前对象实例字典放在方法运行时搜索顺序的最前面是很容易实现的。这时，假设一个对象的实例方法包含实例变量x和局部变量y，语句“print x, y”将会在实例字典找到x(搜索路径的第一个字典)，在局部变量字典找到y(第二个字典)。&lt;br /&gt;&lt;br /&gt;这种策略的问题是给实例变量赋值时就完蛋了。Python赋值时并不在多个字典中查找变量名，而是简单的对搜索顺序中的一个字典进行添加或修改变量，原来情况下这通常是局部变量。结果就是变量总是缺省创建在局部(local scope)范围。(当然，这儿也要说明的是，对每个函数中的每个变量可以用全局声明“global declaration”方式来重载顺序，使全局在最前。)&lt;br /&gt;&lt;br /&gt;不改变赋值方法的简单策略之前，把实例字典置于搜索顺序第一项使得在方法中无法给局部变量赋值。例如，如下一个方法&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;def spam(y):&lt;br /&gt;    x = 1&lt;br /&gt;    y = 2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;对x和y的赋值语句将会改写x的值，创建一个新的y并遮蔽局部变量y。交换实例变量和局部变量在搜索中的顺序，也只是将问题转进到另外一个方面而已，又无法给实例变量赋值了。&lt;br /&gt;&lt;br /&gt;如果修改赋值的语义，对已存在实例变量名的赋值时修改实例变量，对不存在实例变量的情况时生成局部变量，也不是一个正确策略，因为这样会带来一个自举问题：实例变量如何被初始化呢。一个可能的解决方案是对实例变量进行清晰的声明，就像全局变量那样，但是我实在不愿意增加增加这样的特性，因为已经在完全不需要变量声明的路上走的太远了。而且，对表示全局变量的额外处理只是一个特殊情况，这种处理也表明在代码中使用全局变量时应谨慎。然而对实例变量的额外处理则几乎在类里面随处可见。另一个思路是实例变量有变量名上的区别。例如，以特殊符号开头(Ruby用@开头)，或者采用前缀后缀等特殊的命名规范。这些都不能让我满意(直到现在我也没有改变过看法)。&lt;br /&gt;&lt;br /&gt;最后，我决定放弃采用隐含方式表示实例变量的想法。C++这样的语言允许你用this-&gt;foo来明确表示foo是实例变量(当存在另一个局部变量foo时)。因此，我决定用明确声明方式作为指定实例变量的唯一方式。另外，与其用一个特定关键字来表示当前对象(“this”)，我更愿意用方法的第一个参数“this”(或者其它等价变量名)。实例变量就可以总是通过这个参数的属性来引用了。&lt;br /&gt;有了清晰引用，就不用为方法设计特殊语法了，你也不用担心变量名查找时的会变得很复杂。相反，只需要函数的第一个参数对应实例(通常用“self”)，就可以成为一个方法了。如下代码：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;def spam(self,y):&lt;br /&gt;    print self.x, y&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;我在Modula-3中学过类似做法，之前Modula-3中已经提供了import和异常处理的语法。Modula-3没有类，但是它允许你创建记录类型(record type)时包含完整类型函数指针成员并就近初始化，并且增加了语法糖，当x是当前记录类型的一个变量，m是一个该类型的函数指针，用函数 f初始化时，调用x.m(args)和f(x, args)是等价的。这正好可以应用到典型的对象和方法实现，使得实例变量等价于第一个参数的属性。&lt;br /&gt;&lt;br /&gt;Python类语法的剩余细节也遵从这个规则或者其他实现引入的约束。出于简化的目的，我假定类语句由一系列方法定义组成，方法定义的语法和函数定义相同除了依照惯例要求第一个参数名为“self”。另外，与其给特殊的类方法(例如构造函数和析构函数)设计新的语法，我决定这个特征可由用户通过实现有特定命名约定的方法来完成，例如__init__，__del__等。这个命名规则从C语言中借鉴而来，C语言中由下划线开头的标识符保留给编译器使用，并通常有特殊用途(例如，C预编译器的__FILE__宏)。&lt;br /&gt;&lt;br /&gt;这样，我设想的类定义代码就是下面这个样子了：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;class A:&lt;br /&gt;     def __init__(self,x):&lt;br /&gt;         self.x = x&lt;br /&gt;     def spam(self,y):&lt;br /&gt;        print self.x, y&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;如同往常，我希望能尽量多的重复利用早期已有代码。以前一个函数定义就是一条可执行语句，简单的在当前命名空间设定一个变量，变量值就是函数对象(变量名就是函数名)。因此，与其设计完全不同的新方法来处理类，对我来说不如简单的把类的内容(class body)当做在一个新的命名空间运行的一系列语句。这个命名空间的字典将会被用以初始化类字典并创建一个类对象。实质就是把类内容用一个特殊方法当做匿名函数，并将执行后的局部变量组成的字典当做结果返回。这个字典传递给一个辅助函数(helper function)来生成类对象。最终，这个类对象存为相应命名空间下的一个变量。用户在知晓任何有效的Python语句都可以出现在类中后常感到惊奇。其实这个特点确实只是我想保持语法尽量简单的同时又不愿人工干涉来约束潜在可能的自然结果了。&lt;br /&gt;&lt;br /&gt;最后一点细节是关于类实例化(实例创建)的语法。许多语言，例如C++和Java，采用特定的运算符“new”来生成新的类实例。C++中这么做或许讲得过去，毕竟类名在其解析器中有特殊地位，在Python中情况就不同了。我分析后很快得出结论，既然Python的解析器不在意调用的对象是何种类型，让类对象本身可以被调用是恰当的，是“最简”方案，也是不需引入新语法的好点子。这儿我可能有所超前--现在，厂函数(factory function)是创建是通常实例创建的优先方式，我所做的正是简单的把每个类的实例创建丢给它自己的厂。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;特殊方法&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;如上节中已经简单提到的那样，我的目标之一是保持类的实现简单化。大多数面向对象编程中都有专为类设计的特殊的运算符和方法。例如，C++中，定义构造函数和析构函数有特殊的语法，与一般普通的函数和方法不同。&lt;br /&gt;&lt;br /&gt;我显然不愿意为对象的特殊操作引入新的语法。相反，我解决这个问题的方法是简单的将特殊操作映射到一套已预定义好的“特殊方法(special method)”名，例如__init__和__del__。通过定义这些名称的方法，用户就可以提供对象的构建函数和析构函数所需代码了。&lt;br /&gt;&lt;br /&gt;我还将这个设计应用到允许用户自定义类重定义Python运算符行为上来。前面已经提到，Python用C语言实现，利用函数指针表来实现各种内置对象能力(例如“get attribute”、“and”和“call”)。为了允许用户自定义类也拥有这些能力，我将这些函数指针映射到特别方法名上，如__getattr__、__add__和__call__。在实现C语言新建Python对象时已经存在一个从这些名字到function pointer表之间的直接对应。&lt;br /&gt;&lt;br /&gt;__________&lt;br /&gt;(*) 后来，new-style class需要控制对__dict__的改动；你仍然可以动态修改类，但是必须通过属性赋值方式，而不是直接操作__dict__了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-5461713738785144354?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/5461713738785144354/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=5461713738785144354' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5461713738785144354'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/5461713738785144354'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/adding-support-for-user-defined-classes.html' title='增加对用户自定义类的支持'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-3080096592369205548</id><published>2009-04-28T04:09:00.000+08:00</published><updated>2009-04-28T04:18:49.340+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>Python选择了动态类型</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/02/pythons-use-of-dynamic-typing.html"&gt;http://python-history.blogspot.com/2009/02/pythons-use-of-dynamic-typing.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;&lt;a href="http://homepages.cwi.nl/~steven/abc/"&gt;ABC&lt;/a&gt;和Python的重要区别之一在于类型系统的通用风格。ABC是静态类型语言，ABC的编译器会分析程序中类型的一致性。如果存在不一致情况，程序就会被拒绝运行。和现在大多数静态类型语言不同的是，ABC使用类型推断(这一点和&lt;a href="http://www.haskell.org/"&gt;Haskell&lt;/a&gt;一样)而不是常在C语言中看到的那样明确声明变量类型。相反，Python采用动态类型。Python编译器对程序中的类型一无所知，统统放行，所有的类型检查在运行时完成。&lt;br /&gt;&lt;br /&gt;虽然表面上看起来是对ABC背离很远，实际上并没有想象的那么夸张。和其它静态类型语言不同的是，ABC不(真的不？这个记忆可老有历史了:-)完全依赖仅靠静态类型检查以保证程序不会崩溃，还有一个运行时库在程序运行时对所有的操作类型进行再次检查。这个是作为编译器类型检查的安全性检查的一部分，在语言原型实现阶段没有完全实现。这个运行时库对于调试也有用，因为进行明确的运行时类型检查有助于输出更有针对性的出错信息(这是对实现团队来说的)，而不是解释器在运行时不检查参数类型是否正确就盲目运行而导致内核崩溃那样。&lt;br /&gt;&lt;br /&gt;然而，ABC在静态类型检查之外还采用运行时类型检查的最关键原因在于ABC是交互式的。在一次交互过程中，用户输入ABC程序语句和变量定义后立刻被执行。交互模式中一次完整过程可能将一个变量定义为数值类型，删除变量，然后重新定义变量(也就是创建另外一个同名变量)为字符串类型。在单个语句中某变量名从数值类型变为字符串类型会产生静态类型错误，然而在交互模式下不同语句之间也要求这种类型检查就有些不妥当了，否则不小心创建了一个数值类型的变量x，就会被禁止创建变量名为x的其他类型！因此作为折中，ABC对全局变量使用动态类型检查，对局部变量使用静态类型检查。为了简化实现，动态类型检查对局部变量也同样适用。&lt;br /&gt;&lt;br /&gt;于是，从ABC的类型检查实现方法到Python的方法只剩下一步之遥了--Python简单的把编译时类型检查完全去掉。这完全符合Python的“偷工减料”原则，只要这种实现上的简化不影响最终的安全性，所有的类型检查都会在运行时进行所以各种类型错误会被捕获而不是导致Python解释器失效。&lt;br /&gt;&lt;br /&gt;然而，一旦决定采用动态类型，就没有回头路了。ABC仔细设计了built-in(内置)运算以便从运算形式上推测参数类型。例如，从表达式“x^y”中，编译器可以得知变量x和y是字符串。Python中就无法采用这样的推理规则了。例如表达式“x+y”可能是字符串连接，也可能是数字相加，或者用户自定义类的重载操作。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-3080096592369205548?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/3080096592369205548/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=3080096592369205548' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/3080096592369205548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/3080096592369205548'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/pythons-use-of-dynamic-typing.html' title='Python选择了动态类型'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-1686360817103544893</id><published>2009-04-27T16:56:00.000+08:00</published><updated>2009-04-27T17:36:22.878+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>初创时期的语言设计与开发</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/02/early-language-design-and-development.html"&gt;http://python-history.blogspot.com/2009/02/early-language-design-and-development.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;从ABC到Python &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;Python最初就受到&lt;a href="http://homepages.cwi.nl/~steven/abc/"&gt;ABC&lt;/a&gt;的影响且影响最深，ABC是Lambert Meertens、Leo Geurts和CWI其他人在1980年代初设计的编程语言。ABC的目的是成为一门教学语言、BASIC语言的替代者和个人计算机上的编程语言环境。ABC设计时先进行编程工作的任务分析，然后在包括严格用户测试的情况下再重复往返数遍。我个人在ABC开发组中的角色主要是语言及其集成编程环境实现。&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Python中采用缩进的思想直接来自ABC，但是这个想法并不是ABC首创，缩进方式早已为Donald Knuth倡导并成为一种广泛的优良编程风格。(&lt;a href="http://en.wikipedia.org/wiki/Occam_programming_language"&gt;occam&lt;/a&gt;语言中也应用了缩进。)当然，ABC的作者确实发明了用冒号“：”来引导随后缩进块。在早期不使用冒号时的用户测试中，发现对于初次学习编程的新手来说，缩进的含义不够明确。添加冒号能明确缩进的含义：冒号提醒随后的程序块将要增加缩进，也将前后程序恰当的连接起来。&lt;br /&gt;&lt;br /&gt;Python的主要数据类型也是在ABC的基础上修改而来。ABC的list实际上是bag或者说multiset，它利用修改过的B-tree实现，总是保持顺序。ABC的table则是总能保持key顺序的关联数组。我发现没有任何一种已有的数据类型适合表示从文件中逐行顺序读取内容，而我认为这是一种常见程序应用情况。(在ABC中勉强可以用行号为key的table来表示相应内容，但涉及行增删时处理困难。)于是我把list类型改为一种可有效处理增删的灵活数组，给用户完全控制list中元素顺序的能力。并提供了sort方法以备list需要排序时使用。&lt;br /&gt;&lt;br /&gt;我还将保持key顺序的table改为hash表实现。我选择hash表的原因是因为我觉得它比ABC的B-tree速度更快也更容易实现。后者在理论上可以证明对于相当多的操作在时间和空间上是渐进优化的，然而实际情况是由于B-tree算法本身的复杂而难以正确实现。同样原因，对于规模较小的table，其性能也不出色。&lt;br /&gt;&lt;br /&gt;我照搬了ABC的不可变tuple类型--Python中tuple的打包与解包操作直接从ABC中借来。由于tuple内部由数组实现，我决定给tuple加上数组常有的index(索引)和slice(切片)操作。&lt;br /&gt;&lt;br /&gt;在给tuple增加数组操作接口时我发现需要解决tuple的边界情况，即tuple含有元素数目为0或者1的情况。我从ABC中引入的规则之一便是，对任一数据类型进行打印或转换为字符串时，其输出应当恰是语言语法分析器可有效处理的输入。所以，我需要有包含元素长度为0或者1的tuple的标记方法。同时我也不想失去单元素tuple和普通用括号包含表达式之间的区分能力，于是我采用了有些丑但却实用的方法，就是在括号中的表达式后附加一个多余的逗号，就变为单元素的tuple，用“()”来表示空tuple。需要说明的是，对于Python语法而言，tuple的括号并不是必须的，除了表示空元素这一情况时--我觉得用“空”表示空tuple太容易掩盖相应的书写错误了。&lt;br /&gt;&lt;br /&gt;Python的string和ABC中的不可变string语义十分相近，但是有一点标记上的区别，Python采用从0起始的索引。现在已经有了三种可以索引的类型，list、tuple和string，我决定将其归纳为sequence作为他们的通用概念。以使对任意sequence类型的核心操作形式相同，包括获取长度(len(s))，索引(s[i])，切片(s[i:j])，和遍历(for i in s)等。&lt;br /&gt;&lt;br /&gt;数值类型是我背离ABC设计思路最远的部分之一。ABC在运行时有两种类型的数值类型：可表示任意精度有理数的精确数和增大表示范围的二进制浮点数所表示的近似数。我没有采用前者那种有理数表示方式。(轶事：有次我想用ABC来计算自己要交的税。看起来很正常的程序，计算几个简单数字却费了很长时间还没算出来。又仔细看了下才发现正在处理几千位数字精度的算数运行，全然不顾最终输出结果只要精巧到荷兰盾的元和分即可。) 对于Python，我因此选择了更传统的方式，采用机器整数和机器二进制浮点数来表示。Python的实现中，这两种数据类型简单对应了C数据类型中的long和double。&lt;br /&gt;&lt;br /&gt;考虑到对无上界精确数的需求也很有实际意义，我增加了一个大数类型，称为long。我当时已经有了一个大数类型，是我几年前为了改进ABC实现时的半成品(ABC最初的相应实现，也是我对ABC做的最早贡献之一，是用十进制作为内部表示的)。因此，将代码拿来给Python用对我来说是再合适不过的事情了。&lt;br /&gt;&lt;br /&gt;虽然我为Python添加了大数类型，这里一定要明确说明的是我并不希望所有的整数运算都使用大数类型。根据我和CWI的同事对Python程序的profiling结果，我知道整数运算占据了大多数程序整个运行时间的相当比例。显然，整数的最常用情况是对内存可容纳的sequence类型进行索引操作。因此，我预测机器整数对各种常见情况是实用的，只有在做“严肃的数学”或者用分来计算美国国债时才使用大数类型。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;数值类型的问题&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;对数值类型的实现，特别是整数类型，是我犯了严重设计错误之处，也让我在如何设计Python方面获得了经验教训。&lt;br /&gt;&lt;br /&gt;既然Python有两种整数类型，我需要在程序中区分两种类型的方法。我的解决方式是当用户需要long类型时，自行对数字添加L后缀(例如1234L)。用户对不必要的实现细节无需操心是ABC的设计哲学，这里是Python违反这一思想的地方之一。&lt;br /&gt;&lt;br /&gt;悲哀的是，这还只是一个更大严重问题的冰山一角。一个相当夸张的错误是在特定情况下，integer和long两种整数实现会有语义上的细微不同！因为int类型是由机器整数表示，向上溢出时结果只是简单的截断为低32位或其它某个C中long类型对应的精度。此外，int类型通常情况下是有符号数，在位操作、位移操作、和8进制/16进制互相转换时则当做无符号数。而相对应的，long类型则总是有符号数。因此，某些操作会因为参数是由int还是long类型表达而产生不同的结果。例如，在32位运算中，1&lt;&lt;31(1左移31位)是一个32位的大负数，而1&lt;&lt;32结果为0。然而1L&lt;&lt;31(long类型的1左移31位)产生一个long类型整数，值为2**31，1L&lt;&lt;32的结果为2**32。&lt;br /&gt;&lt;br /&gt;为了解决这个问题，我做了一些简单的修补。对以前简单截断结果的操作做出变更，我将大多数算术运算结果超过存储范围时改为抛出溢出异常(raise an OverflowError exception)。(唯一的例外是上文提到的“位运算”操作，我认为用户期望这儿的结果和C中对应运算保持一致。)如果没有这个检查，Python用户注定在书写代码时依赖一个以2**32为模的有符号二进制运算(正如C中那样)，修正这个错误对社区的转换来说着实是一件苦事。&lt;br /&gt;&lt;br /&gt;虽然包含溢出检查看起来只是实现上一个细微末节，然而调试时的痛苦经历让我认识到这是一个有用的特征。作为我早期Python编程经验之一，我尝试实现了计算“Meertens数”的简单数学算法，这个消遣数学算法是由Richard Bird为纪念ABC首席发明人在CWI满25年时发明的。最前面几个Meertens比较小，但是算法转化为代码时，我当时还不知道中间计算结果远大于32位。这占用我大量时间和精力才找到问题根源，于是我立刻决定通过检查所有整数的运算来解决问题，只要结果不能用C语言中long表示就抛出异常。溢出检查的额外耗费由于我在实现运算结果需要生成新的对象产生较大耗费而显得影响有限。&lt;br /&gt;&lt;br /&gt;悲哀的是，我还要继续道歉，抛出异常仍然不是正确的解决方案！当时我受C语言的“T数值类型上运算返回结果也是T数值类型”这一规则约束。这条规则也是导致我在整数语义上另一个重大错误的原因：截断整数除法的结果，这个我在后面的博文中会谈到。放个马后炮，我应该让溢出的int整数操作结果升级为long类型。这也是今天Python采用的方式，可惜这个转换用了太长时间。&lt;br /&gt;&lt;br /&gt;尽管在数值设计方面遇到这些问题，这个经历还是产生了一个十分有益的结果。我决定Python中应当不含有未定义的结果--相反，当计算结果不正确时，总是抛出异常。这样Python程序员就不会因为运算中内部的悄悄转换而遭遇失败。这是一个重要语言设计原则，无论对语言本身还是标准库来说都是如此。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-1686360817103544893?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/1686360817103544893/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=1686360817103544893' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1686360817103544893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1686360817103544893'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/early-language-design-and-development.html' title='初创时期的语言设计与开发'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-1741451402695355439</id><published>2009-04-27T01:00:00.000+08:00</published><updated>2009-04-27T01:27:02.328+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>微软1996年发布的软件就含有Python代码</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/01/microsoft-ships-python-code-in-1996.html"&gt;http://python-history.blogspot.com/2009/01/microsoft-ships-python-code-in-1996.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Greg Stein&lt;br /&gt;&lt;br /&gt;衷心感谢Guido给我这个机会，能在这里和大家分析我的Python经历！&lt;br /&gt;&lt;br /&gt;我自己接触Python的经历先放一边，有机会另开新贴，要说的其结果就是1991年我和其他几个人合伙成立了一个新公司。我们设计了一个大的客户端/服务器端系统来处理B2C电子商务。当时用的旧X.25网络之上定制的TCP协议，陈旧的技术了。&lt;br /&gt;&lt;br /&gt;到了1995年，我们认识到，和最初设想的相反，很多消费者都是Internet用户，我们需要一个基于Internet的系统，以使我们的客户(那些货物供应商贩)能推销产品给Internet上的消费者。我当时任务就是找思路，我采用Python作为原型开发工具。&lt;br /&gt;我们在移植到完全基于浏览器的解决方案时碰到了问题。我们的原有客户端已不再适用，我们需要帮助消费者建立新的消费体验，而且要实现相应的服务端。当时通过浏览器进行交互就意味着给Apacher和Netscape HTTP服务器写CGI脚本。我利用CGI来连接现存的服务器后台，处理订单、更新购物篮、获取商品信息等。这些CGI脚本的处理结果都是纯粹的Html网页，(1995年还没有AJAX啦！)。&lt;br /&gt;这个方法不太理想，因为每次请求都会产生一个新的CGI进程。响应性能十分受限。到了1995年12月，去华盛顿特区参加Python研讨会时，我接触到一些可以在服务进程中持续运行的Apacher和Netscape模块(由Digital Creations实现，这个公司另一个广为人知的名字是Zope)。这些模块通过名为ILU的RPC系统与后台长期运行进程进行通讯。利用这个系统CGI频繁生成新进程的开销得以避免，网店购物经历也变得有趣起来！我们着手将原型系统转换为生产用代码。我们越用越越顺手，更多人参与到项目中来。接下来几个月的开发进展&lt;strong&gt;神速&lt;/strong&gt;(感谢Python！)。&lt;br /&gt;&lt;br /&gt;1996年1月，微软找上门来。微软内部关于电子商务系统的开发正举步维艰。他们需要熟悉这个行当的明白人(那个时候我们已经在电子商务领域耕耘了好几年了)。春天谈判进行的过程中，我们继续进行软件开发，收购最终在1996年6月完成。&lt;br /&gt;我们带着自己的一小摞Python代码来到微软，要处理的便是让产品在Windows NT平台上运行。我们加入的团队有丰富的Windows经验，构建IIS插件通过命名管道和后台服务之间的通讯。从七月份开始进入火速开发，1996年10月，我们发布了微软商店服务软件1.0版。&lt;br /&gt;于是，如果你仔细观察内部，就能看到，有些隐藏起来的东西，例如一个Python解释器，一些模块的动态链接库，一些.pyc文件。微软显然不愿对这件事情大张旗鼓，不过熟悉的人就会找到的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-1741451402695355439?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/1741451402695355439/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=1741451402695355439' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1741451402695355439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1741451402695355439'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/microsoft-ships-python-code-in-1996.html' title='微软1996年发布的软件就含有Python代码'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-7580890676797324029</id><published>2009-04-26T21:12:00.001+08:00</published><updated>2011-07-12T12:47:46.800+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>个人历史 第二部分 CNRI及其之后</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/01/personal-history-part-2-cnri-and-beyond.html"&gt;http://python-history.blogspot.com/2009/01/personal-history-part-2-cnri-and-beyond.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum &lt;br /&gt;&lt;br /&gt;在Python研讨会(详情参见前帖)上我得到去CNRI从事移动代理方面的工作机会，CNRI全称是美国全国研究创新联合会，是位于弗吉尼亚州瑞斯顿的一个非盈利研究实验室。我于1995年4月正式加入。CNRI主管Bob Kahn第一个告诉我Python和Lisp除了在表面的(语法形式上)区别很大之外是如此相似。在CNRI Python通过DARPA对移动代理研究的支持而得到间接资助。虽然DARPA支持了应用Python的项目，对Python语言本身开发的直接支持并不多。&lt;br /&gt;&lt;br /&gt;在CNRI，我领导并参与招聘了一个纯粹使用Python实现移动代理的开发小组。最初成员包括Roger Masse和Barry Warsaw，他们是在NIST召开的Python研讨会上对这门语言着魔的。除此之外我们还招聘了Python社区的Ken Manheimer和Fred Drake。Jeremy Hylton从MIT毕业后本来从事文本信息检索工作，也加入到我们组。开发组最初由Ted Strollo管理，后来是Al Vezza。&lt;br /&gt;&lt;br /&gt;开发组辅助我创建和维护Python社区的新配套实施，如Python.org网站、CVS服务器、Python各专业兴趣组(SIG)邮件列表。在CNRI Python发布了从1.3到1.6版本。其中的1.52版本在很多年里是最流行和稳定的版本。&lt;br /&gt;&lt;br /&gt;GNU mailman也诞生于此地：我们最初利用的是一个名为Majordomo的Perl工具，但是Ken Manheimer感到难以维护，也想找寻一个基于Python的实现方案。他找到John Viega利用Python写的部分代码，并接手了维护。Ken离开CNRI去Digital Creations之后，Barry Warsaw接手了维护，并且说服自由软件基金会采用mailman作为它们的官方邮件列表工具。为此Barry以GPL协议(GNU通用公共许可证)发布mailman软件。&lt;br /&gt;&lt;br /&gt;Python研讨会继续进行，最初是一年两次，后来由于规模变大，筹办事务繁重而改为一年一次。由最先想主办的机构来组织，NIST组织了第一届，USGS组织了第二届和第三届，LLNL组织了第四届，并且从此改为一年一次。最终CNRI把持了主办权，并随后(联合WWW以及IETF会议)作为一个商业活动的副产品，称作Fortec。参会者迅速飞涨到数百人。当我离开CNRI一段时间后Fortec逐渐衰落。国际Python会议成为O'Reilly开源大会(OSCON)的一部分，与此同时Python软件基金会(有关PSF详情参见下文)开始了一个面向草根大众的PyCon的新会议。&lt;br /&gt;&lt;br /&gt;在CNRI时，我们还创办了第一个(松散的)Python组织。在Mike McLay和Paul Everitt的努力下，成立了“Python基金会”这个基金会还在规划阶段便随风而逝了。Bob Kahn 建议成立“PSA：Python软件部门”，这不是一个独立的法人，而是作为CNRI(非盈利)法人之下的一个群体活动组。PSA成功的把一大群Python用户集合在一起，不过PSA的效力也因缺乏独立法人身份而受限。&lt;br /&gt;&lt;br /&gt;CNRI还是用DARPA的资金资助了JPython的开发(后来缩写为Jython)，这是一个用Java实现并为Java所用的Python实现。Jim Hugunin在MIT读研究生期间创建了该项目。他说服了CNRI雇用自己继续完成Jython(也可能是CNRI主动说服Jim加入进来 -- 当时我正在渡假。)。不到两年后Jim离开了CNRI，去了施乐帕洛阿尔托研究中心的AspectJ项目，Barry Warsaw接手了Jython并继续开发。(很久以后，Jim又开发了IronPython，这是在微软.NET平台上的Python实现。Jim还是Numeric Python第一个版本的作者。)&lt;br /&gt;&lt;br /&gt;其他CNRI的项目也开始使用Python。有几个新的Python核心开发人员便从中产生，特别有Andrew Kuchling、Neil Schemenauer和Greg Ward，他们当时为微机电系统交换项目工作。(Andrew早在加入CNRI之前就开始为Python语言做出贡献；他第一个主要项目是Python密码学工具包，这个第三方库使得Python用户得以使用许多基本的密码学算法。)&lt;br /&gt;&lt;br /&gt;看到Python日益取得的影响，CNRI尝试建立一种更加直接资助Python的模型，而不是像以前通过DARPA的研究基金那样的间接方式。我们基于X协会模式建立了Python协会，最低入会费为2万美元。然而除了HP公司的一个研究组，我们并没有得到过多关注，最终因为缺乏收入来源而停止运作。另一次尝试则是通过建立CP4E(人人可编程)计划来得到资助，这个计划得到了一些DARPA资金。然而不足以维持整个团队运作，而且看起来那几年就是通过一些同学关系网得到花费资金。这并不是我所希望的，于是我开始找寻其它可能。&lt;br /&gt;&lt;br /&gt;最终到了2000年早期，互联网泡沫时代的到来了(至尽仍未消失殆尽)。让我和CNRI其他三个成员(Barry Warsaw，Jeremy Hylton和Fred Drake)跳槽到BeOpen.com，这是加利福尼亚一家招聘开源开发人员的新创公司。Tim Peters，Python社区的关键一员也在这时加入我们。&lt;br /&gt;&lt;br /&gt;预计转移到BeOpen.com之后的需要面临一个Python将来的所有权问题。CNRI坚持更改协议并且要求我们采用新协议发布Python1.6版本。最初我在CWI时用的旧就协议是一个MIT协议版本，而在CNRI之前发布的Python版本修改甚微，主要是增加了个条CNRI的免责条款。1.6版本的协议则是由CNRI律师起草的冗长公文了。&lt;br /&gt;&lt;br /&gt;我们和FSF(自由软件基金会)的Richard Stallman和Eben Moglen就新协议问题进行了多次讨论。他们担心新协议有可能和GPL不兼容进而威胁GNU mailman的合法性。而现在GNU mailman已经是FSF离不开的重要工具了。 在Eric Raymond的帮助下，CNRI Python协议的更动之处除了行文不易于理解之外让FSF和CNRI双方都满意。我唯一能从中想到的好处(再次感谢Eric Raymond的帮助)是Python被FSF亲口认可为开源许可协议。后来又对协议做了细微改动以反映两个Python版权的继承者，BeOpen.com，然后是Python软件基金会。 当然CNRI律师的大作依然有效。&lt;br /&gt;&lt;br /&gt;正如那时候许多初创公司一样，BeOpen.com的商业计划也在惨烈中收场。留下了大量债务，一些对部分公司管理人员所扮演角色的沉沉疑惑，已经一些包括我的团队在内的心灰意冷程序员。&lt;br /&gt;我的团队，现在叫PythonLabs了，碰到了好年头，相当抢手，整体被Digital Creations招聘为一个部门。这是最早应用Python开发的公司之一(Ken Manheimer比我们还要早几年。)Digital Creations很快更名为Zope公司，这是由于他发布了自己的主要产品，开源web内容管理系统Zope。Zope的创办人Paul Everitt和Rob Page，以及CTO Jim Fulton参加了1994年在NIST召开的最早的那届Python研讨会。&lt;br /&gt;&lt;br /&gt;历史差点改写：除了Digital Creations，我们当时还考虑了VA Linux和ActiveState伸出的橄榄枝。VA Linux当时是股票市场的后起之秀，但是最终它的股价(使得Eric Raymond一度成为纸上的大富翁。)还是戏剧性的崩溃了。现在来看ActiveState如果不是在加拿大的话或许是个不错的选择，尽管创办人Dick Hardt的个性有争议。&lt;br /&gt;&lt;br /&gt;2001我们创建了Python软件基金会，这是一个非盈利组织，最初的成员主要来自当时Python开发的主力贡献人员。Eric Raymond是创办人之一。我下次再多写点这个事情。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-7580890676797324029?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/7580890676797324029/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=7580890676797324029' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/7580890676797324029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/7580890676797324029'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/personal-history-part-2-cnri-and-beyond.html' title='个人历史 第二部分 CNRI及其之后'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-4010713609123681073</id><published>2009-04-25T22:06:00.000+08:00</published><updated>2009-04-26T21:31:04.270+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>个人历史 第一部分 在CWI的日子</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/01/personal-history-part-1-cwi.html"&gt;http://python-history.blogspot.com/2009/01/personal-history-part-1-cwi.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;Python最早诞生在阿姆斯特丹一个叫&lt;a href="http://www.cwi.nl/"&gt;CWI&lt;/a&gt;的研究机构，CWI是一个荷兰机构名称的缩略语，翻译过来意思就是数学和计算机科学中心。CWI是个有意思的地方，由荷兰教育部提供资金，也接受其他研究基金资助，负责管理计算机科学和数学学科在学术方面的研究。无论何时，在CWI都能看到大量的博士生在闲逛，也能看到还记得单位原来名称“数学中心”的行内老前辈。最令CWI名声在外的事情当属这儿发明的编程语言 &lt;a href="http://en.wikipedia.org/wiki/ALGOL_68"&gt;Algol 68&lt;/a&gt;了。&lt;br /&gt;&lt;br /&gt;我在CWI的工作开始于1982年下半年，当时刚从大学毕业，在&lt;a href="http://en.wikipedia.org/wiki/Lambert_Meertens"&gt;Lambert Meertens &lt;/a&gt;和 &lt;a href="http://en.wikipedia.org/wiki/Steven_Pemberton"&gt;Steven Pemberton&lt;/a&gt;负责的&lt;a href="http://en.wikipedia.org/wiki/ABC_%28programming_language%29"&gt;ABC&lt;/a&gt;组做程序员。四五年后，ABC由于反响不太理想而项目中指终止，我去了由&lt;a href="http://www.huygens.org/sape/"&gt;Sape Mullender&lt;/a&gt;负责的CWI &lt;a href="http://en.wikipedia.org/wiki/Amoeba_distributed_operating_system"&gt;Amoeba&lt;/a&gt;组。Amoeba组做的是CWI和&lt;a href="http://en.wikipedia.org/wiki/Vrije_Universiteit"&gt;阿姆斯特丹自由大学&lt;/a&gt;联合开发的基于微内核的分布式系统， 由&lt;a href="http://en.wikipedia.org/wiki/Andrew_S._Tanenbaum"&gt;Andrew Tanenbaum&lt;/a&gt;负责。1991年Sape离开CWI，去&lt;a href="http://en.wikipedia.org/wiki/University_of_Twente"&gt;Twente大学&lt;/a&gt;做教授。我去了新成立的由&lt;a href="http://homepages.cwi.nl/~dcab/"&gt;Dick Bulterman&lt;/a&gt;负责的多媒体组。&lt;br /&gt;&lt;br /&gt;Python是我在CWI工作时的直接成果。正如我后面要提到的那样，ABC给了我开发Python的关键启发，Amoeba则是开发Python的直接诱因，而多媒体组则是Python成长的摇篮。然而至少据我所知，CWI没有正式资助过Python开发。Python做过Amoeba和多媒体两个组的重要工具而得以成长，CWI是这一过程的见证者。&lt;br /&gt;&lt;br /&gt;我最初设计Python的动机是感觉Amoeba项目缺少一门高级语言。我发现用C开发系统工具过于耗时。而使用Bourne shell 也有一些不妥之处。其中最重要一点就是作为新设计思路下的微内核分布式系统，Amoeba的基本操作与Bourne shell所适用的传统操作系统的基本操作相去甚远(前者改进明显)。因此，需要一门语言来“消除C和shell之间的隔阂”。Python有很长一段时间用把这个当做卖点。&lt;br /&gt;&lt;br /&gt;看到这儿，你或许会问“为什么不改进一门已有的语言呢？”在我看来，当时并没有太多合适的语言可选。我对Perl 3比较熟悉，但是Perl和Unix的结合比起Bourne shell来还紧密。我也不喜欢Perl的语法，我对语法风格的偏好受以前所学语言影响很深，如&lt;a href="http://en.wikipedia.org/wiki/ALGOL"&gt;Algol 60&lt;/a&gt;、Pascal和Algol 68，还有最后学习也同样重要的ABC，我曾为之付出四年的时光。所以，我决定设计一门自己的语言，尽量从ABC中借鉴一切我喜欢的特性，同时修正我认为ABC存在的问题。&lt;br /&gt;&lt;br /&gt;我首先想修改的就是名字！碰巧，ABC团队在为自己所开发开发语言选择名字的时候遇到了一些麻烦。最初选定的名字&lt;em&gt;B&lt;/em&gt;未获通过，是因为已经有一门更早更为人所知的语言用了B这个名字。另外&lt;em&gt;B&lt;/em&gt;也只是作为暂定名(有个笑话说&lt;em&gt;B&lt;/em&gt;是包含了语言名字的变量名，所以用斜体)。团队公开征集新名字，可惜参赛方案无一满意，内部提案最终中选。这个名字想表达的意思是说这门语言使得编程像学字母ABC一样简单，但是这些说法从未能让我满意。&lt;br /&gt;&lt;br /&gt;因此，与其在起名问题无休无止的耗下去，我决定不再纠缠。我就选了首先想到的事物，也就是&lt;a href="http://en.wikipedia.org/wiki/Monty_Python%27s_Flying_Circus"&gt;Monty Python’s Flying Circus&lt;/a&gt;，我最喜欢的戏剧团之一。对这个实质上的“&lt;a href="http://en.wikipedia.org/wiki/Skunkworks_project"&gt;小私活&lt;/a&gt;”来说，这个称呼有些风马牛不相及。“Python”易记、干脆，符合当时采用名人对编程语言命名的传统，如Pascal，Ada，和Eiffel。Monty Python马戏团虽不在科技方面见长，去也为相当多极客喜爱。这个命名也符合CWI Amoeba组用电视剧命名程序的传统。&lt;br /&gt;&lt;br /&gt;很长一段时间，我都拒绝把该语言和蛇联系起来的企图。最终，当O’Reilly准备在他们出版的第一本Python书籍《Programming Python》封面上放一条蛇的时候，我做了让步。用动物做封面是O’Reilly的传统，既然非要用一个动物，我想是一条蛇也好。&lt;br /&gt;&lt;br /&gt;名字定了之后，我在1989年12月份开始动手实现Python。在1990年的头几个月就有了一个可工作版本。我没有当时的记录，不过我清楚的记得我为Python实现所写的第一部分代码是一个简单的LL(1)剖析器产生器，我称之为“pgen。”。这个剖析器产生器仍是Python源代码的一部分，而且可能是所有Python源代码中改动最少的部分。这个Python的最早版本在1990年有几个CWI的用户，主要但不全是Amoeba组的。除我之外的关键开发人员是我的同事程序员&lt;a href="http://homepages.cwi.nl/~sjoerd/"&gt;Sjoerd Mullender&lt;/a&gt;(Sape的弟弟)和&lt;a href="http://homepages.cwi.nl/~jack/"&gt;Jack Jansen&lt;/a&gt;(他在我离开CWI多年之后仍是负责Macintosh平台Python移植的领头开发人员之一)。&lt;br /&gt;&lt;br /&gt;1991年2月20号，我第一次在&lt;a href="http://www.faqs.org/faqs/alt-sources-intro/"&gt;alt.sources&lt;/a&gt;新闻组向外界发布了Python(21个uuencoded打包文件，要先合并在一起然后&lt;a href="http://en.wikipedia.org/wiki/Uuencode"&gt;uudecoded&lt;/a&gt;解包为一个压缩的tar文件。)。这就是0.9.0版，发布采用的协议基本上照抄当时一个X11项目采用的MIT协议，只是改单位名称为“Stichting Mathematisch Centrum”，这是CWI的上级单位，以作为法律实体。就这样，如同我写过的所有代码那样，Python是开源软件，这要比&lt;a href="http://en.wikipedia.org/wiki/Eric_S._Raymond"&gt;Eric Raymond&lt;/a&gt;和&lt;a href="http://en.wikipedia.org/wiki/Bruce_Perens"&gt;Bruce Perens&lt;/a&gt;在1997年提出“开源软件”这个术语还早了。&lt;br /&gt;&lt;br /&gt;立刻就收到许多反馈，在这种鼓励下我在接下来的几年一直持续的发布新版本。我开始使用&lt;a href="http://en.wikipedia.org/wiki/Concurrent_Versions_System"&gt;CVS&lt;/a&gt;来跟踪代码变更和便于同Sjoerd、Jack交换代码。(恰巧，CVS最初是由&lt;a href="http://en.wikipedia.org/wiki/Dick_Grune"&gt;Dick Grune&lt;/a&gt;设计的一套shell脚本组成，他是ABC组的一个早期成员。)我写了个一个FAQ，然后正如在有web之前时代FAQ的处理惯例那样周期性的张贴到一些新闻组，建立了一个邮件列表。&lt;a href="http://groups.google.com/group/comp.lang.python/topics"&gt;comp.lang.python&lt;/a&gt;新闻组成立于1993年3月，此事我有鼓励但未亲自参与建立。新闻组和邮件列表通过一个双向网关连接起来。该双向网关至今仍工作，不过具体实现已是mailman的一个特性。mailman是开源邮件列表管理软件的首选，由Python语言实现。&lt;br /&gt;&lt;br /&gt;1994年夏天，新闻组因为一个“&lt;a href="http://www.python.org/search/hypermail/python-1994q2/1040.html"&gt;如果Guido被公车撞了怎么办？&lt;/a&gt;”的线索而人声鼎沸。这个线索关注的是日益成长壮大的Python社区对我个人贡献的依赖关系问题。讨论在Michael McLay邀请我到&lt;a href="http://www.nist.gov/"&gt;NIST&lt;/a&gt;做两个月访问学者时达到顶点。 NIST是美国国家标准技术研究所，前身为国家标准局。位于马里兰州的盖瑟斯堡。Michael 有些NIST的“客人”对使用Python做一些和标准有关的项目感兴趣，也有预算资助我留下来，目的是帮助他们提高Python使用水平，也可以说是改进Python以符合他们的需求。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.python.org/workshops/1994-11/attendees.pics.html"&gt;第一届Python研讨会&lt;/a&gt;于我呆在NIST的1994年11月召开，这要感谢NIST程序员&lt;a href="http://en.wikipedia.org/wiki/Ken_Manheimer"&gt;Ken Manheimer&lt;/a&gt;提供的重要帮助与支持。大约有20个参会者，约半数人仍活跃在Python社区，有些人已经成为主要开源项目的领军人物(如&lt;a href="http://www.zope.org/"&gt;Zope&lt;/a&gt;项目的&lt;a href="http://www.zope.com/about_us/management/james_fulton.html"&gt;Jim Fulton&lt;/a&gt;，&lt;a href="http://en.wikipedia.org/wiki/GNU_Mailman"&gt;GNU mailman&lt;/a&gt;项目的&lt;a href="http://barry.warsaw.us/"&gt;Barry Warsaw&lt;/a&gt;)。在NIST的支持下，我还在计算机系统协会(Usenix)的小语言会议上做主题发言，约有400人参会。会议在圣达菲召开，由&lt;a href="http://en.wikipedia.org/wiki/Tom_Christiansen"&gt;Tom Christiansen&lt;/a&gt;组织，他是一个思想开明的Perl拥护者，在他的引荐下我见到了Perl的发明人&lt;a href="http://en.wikipedia.org/wiki/Larry_Wall"&gt;Larry Wall&lt;/a&gt;和Tcl/TK的作者&lt;a href="http://home.pacbell.net/ouster/"&gt;John Ousterhout&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/3792639039530184077-4010713609123681073?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/4010713609123681073/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=4010713609123681073' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/4010713609123681073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/4010713609123681073'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/personal-history-part-1-cwi.html' title='个人历史 第一部分 在CWI的日子'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-4929408938100606352</id><published>2009-04-25T09:40:00.000+08:00</published><updated>2009-04-25T10:32:41.692+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>Python 时间表</title><content type='html'>&lt;p&gt;&lt;span&gt;英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/01/brief-timeline-of-python.html "&gt;http://python-history.blogspot.com/2009/01/brief-timeline-of-python.html &lt;/a&gt; &lt;/span&gt;&lt;/p&gt;&lt;span&gt;&lt;p&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Python开发过程也正是其它动态(开源)编程语言如Tcl、Perl和(晚的多的)Ruby活跃开发逐渐流行的时期。为了从远景对Python进行观察，窥其全貌，如下时间表列出了Python各个版本的发布日期。由于我没有持续记录，早期版本的发布日期并不精确。&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;p&gt;&lt;strong&gt;发布日期               版本&lt;/strong&gt; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;December, 1989         开始着手实现&lt;/p&gt;&lt;br /&gt;&lt;p&gt;1990                   CWI内部发布&lt;/p&gt;&lt;br /&gt;&lt;p&gt;February 20, 1991      0.9.0 (发布到alt.sources)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;February, 1991         0.9.1&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Autumn, 1991           0.9.2&lt;/p&gt;&lt;br /&gt;&lt;p&gt;December 24, 1991      0.9.4&lt;/p&gt;&lt;br /&gt;&lt;p&gt;January 2, 1992        0.9.5 (仅限Macintosh平台)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;April 6, 1992          0.9.6&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Unknown, 1992          0.9.7beta&lt;/p&gt;&lt;br /&gt;&lt;p&gt;January 9, 1993        0.9.8&lt;/p&gt;&lt;br /&gt;&lt;p&gt;July 29, 1993          0.9.9&lt;/p&gt;&lt;br /&gt;&lt;p&gt;January 26, 1994       1.0.0&lt;/p&gt;&lt;br /&gt;&lt;p&gt;February 15, 1994      1.0.2&lt;/p&gt;&lt;br /&gt;&lt;p&gt;May 4, 1994            1.0.3&lt;/p&gt;&lt;br /&gt;&lt;p&gt;July 14, 1994          1.0.4&lt;/p&gt;&lt;br /&gt;&lt;p&gt;October 11, 1994       1.1&lt;/p&gt;&lt;br /&gt;&lt;p&gt;November 10, 1994      1.1.1&lt;/p&gt;&lt;br /&gt;&lt;p&gt;April 13, 1995         1.2&lt;/p&gt;&lt;br /&gt;&lt;p&gt;October 13, 1995       1.3&lt;/p&gt;&lt;br /&gt;&lt;p&gt;October 25, 1996       1.4&lt;/p&gt;&lt;br /&gt;&lt;p&gt;January 3, 1998        1.5&lt;/p&gt;&lt;br /&gt;&lt;p&gt;October 31, 1998       1.5.1&lt;/p&gt;&lt;br /&gt;&lt;p&gt;April 13, 1999         1.5.2&lt;/p&gt;&lt;br /&gt;&lt;p&gt;September 5, 2000      &lt;a href="http://www.python.org/download/releases/1.6/"&gt;1.6&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;October 16, 2000       &lt;a href="http://www.python.org/download/releases/2.0/"&gt;2.0&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;April 17, 2001         &lt;a href="http://www.python.org/download/releases/2.1/"&gt;2.1&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;December 21, 2001      &lt;a href="http://www.python.org/download/releases/2.2/"&gt;2.2&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;July 29, 2003          &lt;a href="http://www.python.org/download/releases/2.3/"&gt;2.3&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;November 30, 2004      &lt;a href="http://www.python.org/download/releases/2.4/"&gt;2.4&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;September 16, 2006     &lt;a href="http://www.python.org/download/releases/2.5/"&gt;2.5&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;October 1, 2008        &lt;a href="http://www.python.org/download/releases/2.6/"&gt;2.6&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;December 3, 2008       &lt;a href="http://www.python.org/download/releases/3.0/"&gt;3.0&lt;/a&gt;&lt;/p&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;我给那些在python.org现在还有的版本添加了对应链接。这里要提及的是许多版本发布之后还会有随后的若干个小版本，例如2.0.1；限于篇幅我没有将这些小版本也包含进来。最初阶段的源代码任何可以从如下地址访问： &lt;a href="http://www.python.org/ftp/python/src/"&gt;http://www.python.org/ftp/python/src/&lt;/a&gt; 。一些早期版本的二进制文件和其它文物也可以到该链接的上一层进行找寻。&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-4929408938100606352?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/4929408938100606352/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=4929408938100606352' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/4929408938100606352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/4929408938100606352'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/brief-timeline-of-python-python.html' title='Python 时间表'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-1162531273659148693</id><published>2009-04-24T13:34:00.000+08:00</published><updated>2009-04-25T09:24:36.229+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>Python设计哲学</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/01/pythons-design-philosophy.html"&gt;http://python-history.blogspot.com/2009/01/pythons-design-philosophy.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;随后的博文重心落在Python历史细节上。然后，在开始具体内容之前，我想在这里详细说明一下Python设计与实现过程中指导我做出决策的哲学方针。&lt;br /&gt;&lt;br /&gt;首先，Python最初只是一个人的“私活”，没有正式资金支持，我希望能尽快做出成品，以便向管理层要求对该项目的支持(这方面我做的相当成功)。基于这一点，采取了如下一些节约时间的原则：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;只要合适，尽可能从其它语言借用已有思路。&lt;/li&gt;&lt;li&gt;事情应当简约而不简陋(爱因斯坦)。&lt;/li&gt;&lt;li&gt;只做一件事，做好一件事(UNIX哲学)。&lt;/li&gt;&lt;li&gt;对性能不需要太多顾虑，有在遇到性能瓶颈是进行优化的方案即可。&lt;/li&gt;&lt;li&gt;不对抗大环境，顺势而为。&lt;/li&gt;&lt;li&gt;不强求完美，因为通常“足够好”已经“足够好”了。&lt;/li&gt;&lt;li&gt;(因此)有些细碎之处可以先放在一边，尤其是那些放在以后正确处理的部分。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;还有一些原则则不是从节约时间的角度来考虑的，有时还会因此耗费相当时间:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Python实现应当不依赖具体平台，可以允许部分函数不是在所有平台实现，但是核心部分应当在所有平台都正常工作。&lt;/li&gt;&lt;li&gt;不劳烦用户处理那些机器可处理的部分(我并没有一直遵守这一原则，因此损失惨重，其中一些教训将在后文提到)。&lt;/li&gt;&lt;li&gt;支持并且鼓励用户写平台无关代码，同时不禁止利用平台特性。(这一点和Java的设计原则尖锐对立。)&lt;/li&gt;&lt;li&gt;一个大规模复杂系统应当有多层次的可扩展性。这对自己动手进行扩展的新老用户都有利。&lt;/li&gt;&lt;li&gt;出错不应当是致命的。也就是说，只要虚拟机还能工作，用户代码就有从出错处恢复的能力。&lt;/li&gt;&lt;li&gt;同时，也不应简单忽略出错之处。(这和上一条一起，导致了在具体实现时广泛采用异常。)&lt;/li&gt;&lt;li&gt;用户所写Python代码中的bug不应使Python解释器产生未定义行为；永远不会因为用户代码中的错误导致Python核心错误。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;最后，我还有些关于编程语言设计的好思路，这些主要是从ABC开发组借鉴而来。正是在ABC开发组我第一次有了编程语言设计与实现的实际经验。这些思路可归结为优美、简洁、良好可读性等主观想法，难以用言语具体表达。&lt;/p&gt;&lt;p&gt;虽然在后边我还会提到ABC对Python的影响，我想在这儿强调特别和可读性有关的一点：慎用标点符号，只采用书面英语和高中代数中的常用标点符号。当特定用法在编程语言中已经长期存在成为传统时，可以考虑破例。例如“x*y”表示乘法，“a[i]”表示数组下标，“x.foo”表示选择对象属性。但是Python不用“$”表示变量，也不用“!”表示运算以避免副作用。&lt;/p&gt;&lt;p&gt;Tim Peters，是Python的长期用户，并最终成为最高产与卓越的核心开发人员。他对我的设计语言进行理解并表达为“Python之禅”。我把全文贴出来：&lt;br /&gt;(这一段的翻译译者ZoomQuiet，来源：&lt;a href="http://wiki.woodpecker.org.cn/moin/PythonZenZoomq"&gt;http://wiki.woodpecker.org.cn/moin/PythonZenZoomq&lt;/a&gt;)&lt;/p&gt;&lt;ul&gt;&lt;li&gt;美丽好过丑陋,&lt;/li&gt;&lt;li&gt;浅显好过隐晦,&lt;/li&gt;&lt;li&gt;简单好过复合,&lt;/li&gt;&lt;li&gt;复合好过复杂,&lt;/li&gt;&lt;li&gt;扁平好过嵌套,&lt;/li&gt;&lt;li&gt;稀疏好过密集,&lt;/li&gt;&lt;li&gt;可读性最重要,&lt;/li&gt;&lt;li&gt;即使祭出实用性为理由,特例也不可违背这些规则.&lt;/li&gt;&lt;li&gt;不应默认包容所有错误,得由人明确的让它闭嘴!&lt;/li&gt;&lt;li&gt;面对太多的可能,不要尝试猜测;应该有一个(而且是唯一)直白的解决方法;&lt;/li&gt;&lt;li&gt;当然,找到这个方法不是件容易的事~谁叫你不是荷兰人呢?&lt;/li&gt;&lt;li&gt;但是！现在就做永远比不做要好;&lt;/li&gt;&lt;li&gt;若实现方案很难解释,那么它就不是一个好方案;反之也成立!&lt;/li&gt;&lt;li&gt;名称空间是个绝妙想法. --现在就来共同体验和增进这些吧!&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;虽然我在ABC的工作经验对Python影响深远，ABC开发组有一些设计原则和Python有根本不同。Python尽量避免了下面这些设计思路：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;ABC开发组努力追求完美，例如采用了树的结构，这对于大的收集(collection)是渐进优化的(但是对小的收集效果并不理想)。&lt;/li&gt;&lt;li&gt;ABC开发组希望将用户和“笨重脏乱的计算机世界”尽量隔离开。不仅不设定数字上限、字符串长度、收集包含元素数量(仅有可用内存来进行限制)，而且让用户不需要直接接触文件、磁盘、“存盘”等概念。ABC本身成为用户唯一需要了解的工具，基于这一思路，ABC开发组创建了一个ABC所特有的集成编辑环境(确实在使用ABC时存在不使用集成编辑环境的可能，但是这样做困难重重，多是求之不得之后的一种懊悔，而且只能间接实现。)&lt;/li&gt;&lt;li&gt;ABC开发组假定用户没有任何计算机知识(或者用户愿意忘记以前所学的计算机知识)。因此，他们设计了另外一套“新手友好”的计算机术语。例如，程序被改称“怎么办”，变量则称作“定位件”。&lt;/li&gt;&lt;li&gt;ABC开发组在设计ABC语言时对其未来发展的规划并不明确，也没有考虑用户如何参与对语言的设计。ABC是一个封闭的系统，被设计为尽量“完美无缺”。不鼓励用户查看ABC的具体实现。虽然在项目后期也有考虑对高级用户开放部分实现，但终未能实现。&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;从各方面来说，我在创建Python语言时采用的设计原则可能是Python语言获得巨大成功的最重要原因之一。不强求完美，而是让早期的用户群发现Python对他们的需求“足够好”。随着用户数量的增加，他们所提出的改进建议逐渐融入语言本身。我们可以在后面的介绍中看到，许多建议对语言有相当变化，需要对核心部分进行显著改动。时至今日，Python仍在继续进化过程之中。&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-1162531273659148693?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/1162531273659148693/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=1162531273659148693' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1162531273659148693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1162531273659148693'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/python.html' title='Python设计哲学'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-2834769857174218142</id><published>2009-04-24T09:09:00.000+08:00</published><updated>2009-04-24T13:39:57.565+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Python History'/><title type='text'>介绍与概述</title><content type='html'>英文原文链接：&lt;a href="http://python-history.blogspot.com/2009/01/introduction-and-overview.html"&gt;http://python-history.blogspot.com/2009/01/introduction-and-overview.html&lt;/a&gt;&lt;br /&gt;原文作者：Guido van Rossum&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;介绍&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Python, 如同Perl、Tcl、PHP以及新进的Ruby语言那样，是最流行的动态编程语言之一。虽然常被称作“脚本”语言，Python是一门功能齐全的通用编程语言，就像Lisp和Smalltalk以及其他通用编程一样。发展到今日Python的应用已经无所不在，从随写随丢的简单脚本到24x7不间断大规模网络服务应用随处可见其身影。Python的应用场所包括GUI和数据库编程、网络客户端和服务器端编程 、程序测试。科学家在世界上运行最快的超级计算机上编写程序用到了Python，Python还是小朋友初次学习编程时的好帮手。&lt;br /&gt;&lt;br /&gt;在这个Blog中，我将讨论重点放在Python的发展历史上，特别是如下方面：Python是如何开发的，设计时所受到的主要影响，所犯的错误和从中吸取的教训，以及Python语言未来的发展方向。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;感谢:&lt;/strong&gt; 我要感谢 &lt;a href="http://www.dabeaz.com/"&gt;Dave Beazley&lt;/a&gt; ,为这个Blog提供的许多优美语句。(有关这个Blog起因的更多信息，参考我另外Blog的&lt;a href="http://neopythonic.blogspot.com/2009/01/history-of-python-introduction.html"&gt;一篇博文&lt;/a&gt;。)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Python鸟瞰&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;人们初次浏览Python程序时，往往对Python代码样式感到亲切，至少是初看之下，和其他传统编程语言C或者Pascal风格类似。这并非偶然，Python从C语言借用了大量语法，例如Python的许多关键字if, else, while, for和C一致，Python标识符遵守和C同样的的命名规则，大部分运算符号也和C中的含义相同。当然，Python显然不等同与C语言，一个主要的不同之处是Python来界定一组语句时不使用括号，而是缩进。例如，对于如下的C语句：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:c"&gt;&lt;br /&gt;if (a &lt; b) {&lt;br /&gt;    max = b;&lt;br /&gt;} else {&lt;br /&gt;    max = a;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Python省略了两边的括号，并且省略了语句结尾的分号。书写为如下形式：&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;if a &lt; b:&lt;br /&gt;    max = b&lt;br /&gt;else:&lt;br /&gt;    max = a&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Python与C为代表的编程语言另外一个主要区别在于Python的动态类型。在C语言中，变量必须被清晰的声明并指定类型，例如int类型或double类型。该信息在静态编译时可用于类型检查，并分配存储变量所需内存。在Python中，变量只是引用对象的名字，变量在赋值前不需提前声明，甚至在程序运行中变量类型还可以发生变化。如同其他动态语言那样，所有的类型检查是在运行时由解释器完成的，而非一个单独的编译步骤。&lt;br /&gt;&lt;br /&gt;Python基本内置数据类型包括布尔类型、数值型(机器字整数、任意精度整数，实数和复数)、字符串(8bit以及Unicode类型)。这些基本类型是不可变的，也就是说这些类型的对象所包含的值在创建后不能被改变。组合内置数据类型有tuple(不可变数组)、list(可变数组)和dictionary(hash表)。&lt;br /&gt;&lt;br /&gt;在程序结构方面，Python支持包(由模块和/或包组成)、模块(由相关代码组成的单个源代码文件)、类、方法和函数等多个级别。对于程序流控制，则有 if/else, while, 和一种对任意可迭代对象适用的高级for语句，对于出错处理，Python采用了(不可恢复的)异常机制。raise语句抛出异常，try/except/finally 语句处理异常。在遇到错误时，内置操作就抛出异常。&lt;br /&gt;&lt;br /&gt;在Python中所有可以被命名的对象都可以被称作“一类公民”(“first class”)。这意味着函数、类、方法、模块以及其它可命名对象在运行时可被随意赋值给其它对象、被查看或者被放入各种数据结构中(例如list或者dictionary)。提到对象，还要说的是，Python全面支持了面向对象编程，包括用户自定义类、继承、运行时方法动态绑定等。&lt;br /&gt;&lt;br /&gt;Python有丰富的标准库，这也是Python流行的主要原因之一。标准库超过了100多个模块且继续改进丰富中。这些模块包括了正则表达式匹配、标准数学函数、线程、操作系统接口、网络编程、标准互联网协议(HTTP、FTP、SMTP等)、email模块，XML处理、HTML解析以及一个GUI模块(Tcl/Tk)。&lt;br /&gt;&lt;br /&gt;另外，还有极其丰富的第三方模块和包，其中大部分是开源的。有web开发框架(数目之多数不胜数)，许多GUI开发工具箱、高效的数值计算库(流行的Fortran包也有Python封装)，Oracle、MySQL等多种数据库的Python接口，SWIG是将各种C++库封装为Python模块的工具……还有许多优秀模块，不胜枚举。&lt;br /&gt;&lt;br /&gt;Python的一个主要优势在于有些复杂的任务可以用很少几行代码轻松完成(这也是动态语言的共同优点)。以下为一个示例，这个简单的Python脚本抓取一个网页，分析内容，得到其中URL链接，并打印前10条。&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;# -*- coding: UTF-8 -*-&lt;br /&gt;# 扫描网页，获得其中的超链接&lt;br /&gt;&lt;br /&gt;import re&lt;br /&gt;import urllib&lt;br /&gt;&lt;br /&gt;regex = re.compile(r'href="([^"]+)"')&lt;br /&gt;&lt;br /&gt;def matcher(url, max=10):&lt;br /&gt;    "打印从当前URL获取内容中所包括的前面几个URL"&lt;br /&gt;    data = urllib.urlopen(url).read()&lt;br /&gt;    hits = regex.findall(data)&lt;br /&gt;    for hit in hits[:max]:&lt;br /&gt;        print urllib.basejoin(url, hit)&lt;br /&gt;&lt;br /&gt;matcher("http://python.org")&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;这个程序很容易改进为Web爬虫，而且，Scott Hassan 确实告诉过我Google的第一个Web爬虫就是由他用Python写成的。现在Google有数以百万行计的代码用于管理运行的各个方面，从自动构建到广告管理。(声明：作者目前为Google员工。)&lt;br /&gt;&lt;br /&gt;更近距离的继续观察，Python的实现是由字节码编译器和解释器组合而成的。模块被加载时，编译器缺省被调用，有几条Python语句还要求在运行时可以使用编译器。虽然Python的最主要实现是用C语言完成的，还存着其它几种正在流行的Python实现。Jython 是一个运行在JVM上可以和Java无缝连接的版本。IronPython是微软.NET平台上可以和其它.NET语言集成在一起的实现。PyPy 是一个由Python实现的优化Python编译器/解释器(PyPy是欧盟资助项目，目前仍处在研究阶段)。还有Stackless Python,这是一个C实现的变种，特点在于函数/方法调用时减少了对C堆栈的依赖，以实现协程, continuations,和微线程。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-2834769857174218142?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/2834769857174218142/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=2834769857174218142' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/2834769857174218142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/2834769857174218142'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2009/04/blog-post.html' title='介绍与概述'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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-3792639039530184077.post-1841681869293135281</id><published>2007-11-08T14:17:00.001+08:00</published><updated>2010-07-06T11:55:43.545+08:00</updated><title type='text'>Loss</title><content type='html'>Loss        by alena # fanfiction.net&lt;br /&gt;&lt;br /&gt;    When I was a child,&lt;br /&gt;loss was a white feather,&lt;br /&gt;weightless, soft as snow:&lt;br /&gt;me on the beach,&lt;br /&gt;and mother beyond.&lt;br /&gt;&lt;br /&gt;    When night came,&lt;br /&gt;it became a silver beam&lt;br /&gt;from a distant star:&lt;br /&gt;father in the sky,&lt;br /&gt;and me earth-bound.&lt;br /&gt;&lt;br /&gt;    Years later,&lt;br /&gt;loss was just a bend&lt;br /&gt;in the gently singing sea:&lt;br /&gt;me on this side,&lt;br /&gt;and Celebrían beyond.&lt;br /&gt;&lt;br /&gt;    And then,&lt;br /&gt;loss came with a kiss, and a flick&lt;br /&gt;of Fate's slender blade:&lt;br /&gt;me in Arda,&lt;br /&gt;and my Evenstar beyond.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3792639039530184077-1841681869293135281?l=python3.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://python3.blogspot.com/feeds/1841681869293135281/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3792639039530184077&amp;postID=1841681869293135281' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1841681869293135281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3792639039530184077/posts/default/1841681869293135281'/><link rel='alternate' type='text/html' href='http://python3.blogspot.com/2007/11/loss.html' title='Loss'/><author><name>python3</name><uri>http://www.blogger.com/profile/15269284531019553385</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></feed>
