<p>Stallman的观点是,与Lisps相比,没有实现显式的“reader”会使Python的REPL看起来很糟糕,因为它从REPL进程中删除了一个关键步骤。Reader是将文本输入流转换为内存的组件,可以想象一个内置于语言中的XML解析器,用于数据的源代码<em>和</em>。这不仅对编写宏(理论上在Python中可以使用<code>ast</code>模块)有用,而且对调试和内省也很有用。</p>
<p>假设您对<code>incf</code>特殊表单的实现方式感兴趣。你可以这样测试:</p>
<pre><code>[4]> (macroexpand '(incf a))
(SETQ A (+ A 1)) ;
</code></pre>
<p>但是<code>incf</code>可以做的远不止增加符号值。当要求增加哈希表条目时,它到底做了什么?让我们看看:</p>
<pre><code>[2]> (macroexpand '(incf (gethash htable key)))
(LET* ((#:G3069 HTABLE) (#:G3070 KEY) (#:G3071 (+ (GETHASH #:G3069 #:G3070) 1)))
(SYSTEM::PUTHASH #:G3069 #:G3070 #:G3071)) ;
</code></pre>
<p>这里我们了解到<code>incf</code>调用系统特定的<code>puthash</code>函数,这是这个常见Lisp系统的实现细节。请注意“printer”是如何利用“reader”已知的特性的,例如使用<code>#:</code>语法引入匿名符号,以及在扩展表达式的范围内引用相同的符号。在Python中模拟这种检查将更加冗长,而且不易访问。</p>
<p>除了在REPL中的明显使用之外,有经验的Lispers在代码中使用<code>print</code>和<code>read</code>作为一个简单且易于使用的序列化工具,与XML或json类似。虽然Python具有<code>str</code>函数,相当于Lisp的<code>print</code>,但它缺少<code>read</code>的等价物,最接近的等价物是<code>eval</code>。<code>eval</code>当然把<em>两个不同的概念,解析和求值结合在一起,这导致了<a href="https://stackoverflow.com/questions/988228/converting-a-string-to-dictionary">problems like this</a>和<a href="http://code.activestate.com/recipes/364469-safe-eval/" rel="noreferrer">solutions like this</a>这是Python论坛上经常出现的话题。这在Lisp中并不是一个问题,因为读取器和求值器是完全分离的。</p>
<p>最后,reader工具的高级特性使程序员能够以甚至宏都无法提供的方式扩展语言。这种使困难成为可能的完美例子是Mark Kantrowitz的<a href="http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/syntax/infix/infix.cl" rel="noreferrer">the ^{<cd14>} package</a>,他作为reader宏实现了一个功能齐全的中缀语法。</p>