怎样用python写代码

《Effective Python:编写高质量Python代码的59个有效方法》([美]布雷特·斯拉特金)【摘要 书评 试读】- 京东图书
京 东 价:
[定价:¥]
PLUS会员专享价
您购买此商品可享受专属价
增值业务:
重  量:
搭配赠品:
服务支持:
加载中,请稍候...
加载中,请稍候...
加载中,请稍候...
Effective Python:编写高质量Python代码的59个有效方法
商品介绍加载中...
扫一扫,精彩好书免费看
??????“Slatkin所写的这本书,其每个条目(item)都是一项独立的教程,并包含它自己的源代码。这种编排方式,使我们可以随意跳读:大家可以按照学习的需要来浏览这些item。本书涉及的话题十分广泛,作者针对这些话题,给出了相当精练而又符合主流观点的建议,我把这本书推*给中级Python程序员。”——&Brandon&Rhodes,Dropbox的软件工程师、年PyCon会议主席?“当初我刚从Java转向Python时,要是能先看到这本书的话,那就能节省好几个月的时间。这本书使我意识到:以前反复编写的那些代码,都不是很符合Python的编程风格。这本书包含了Python语言的绝大部分必备知识,使我们无需通过数月乃至数年的艰难探索,即可逐个了解它们。本书的内容非常丰富,从PEP8的重要性和Python语言的主要编程习惯开始,然后谈到如何设计函数、方法和类,如何高效地使用标准库,以及如何设计高质量的API,*后,又讲了测试及性能问题。新手和老手都可以通过这本优秀教程来领略Python编程的真谛。”???——Mike&Bayer,SQLAlchemy的创?立者????“这本书会清楚地告诉你如何改善Python代码的风格及函数的质量,它会令你的Python技能更上一层楼。”?????——Leah&Culver,Dropbox的开发者代?言人(developer&advocate)?????&“这是一本*好的书,对其他编程语言较有经验的开发者,可以通过本书迅速学习Python,并了解更符合Python风格的基础语言结构。本书内容清晰、简明,而且易于理解,只需阅读某个条目或某一章,即可单独研究某个话题。书中讲解了大量纯Python的语言结构,使读者不会把它们与Python生态圈中的其他复杂事物相混淆。经验更多的开发者可以通过书中提供的一些深度范例来了解自己尚未遇到的语言特性,以及原来不常使用的语言功能。作者肯定是一位非常熟悉Python的人,他用自己丰富的经验来给读者指出各种经常出现的bug以及经常出错的写法。另外,本书也恰当地说明了Python&2.X与Python&3.X之间的微妙区别,大家在各种版本的Python之间迁移时,可以把本书用作参考资料。”???——Katherine&Scott,Tempo&Automation的软件主管“这是一本对初级开发者和熟练开发者都适用的好书。代码范例及其讲解都写得非常细致、非常简洁、非常透彻。”?????——C.&Titus&Brown,加州大学戴维斯分校?副?教授????“这本参考书非常有用,它提供了很多高级的Python用法,并讲解了如何构建更清晰、更易维护的软件。把书中的建议付诸实践,就可以令自己的Python技能得到提升。”???????????????????????????????——Wes&McKinney,pandas程?序库的创立者《Python&for&Data&Analysis》的作者、Cloudera的软件工程师??????
京东商城向您保证所售商品均为正品行货,京东自营商品开具机打发票或电子发票。
凭质保证书及京东商城发票,可享受全国联保服务(奢侈品、钟表除外;奢侈品、钟表由京东联系保修,享受法定三包售后服务),与您亲临商场选购的商品享受相同的质量保证。京东商城还为您提供具有竞争力的商品价格和,请您放心购买!
注:因厂家会在没有任何提前通知的情况下更改产品包装、产地或者一些附件,本司不能确保客户收到的货物与商城图片、产地、附件说明完全一致。只能确保为原厂正货!并且保证与当时市场上同样主流新品一致。若本商城没有及时更新,请大家谅解!
权利声明:京东上的所有商品信息、客户评价、商品咨询、网友讨论等内容,是京东重要的经营资源,未经许可,禁止非法转载使用。
注:本站商品信息均来自于合作方,其真实性、准确性和合法性由信息拥有者(合作方)负责。本站不提供任何保证,并不承担任何法律责任。
印刷版次不同,印刷时间和版次以实物为准。
价格说明:
京东价:京东价为商品的销售价,是您最终决定是否购买商品的依据。
划线价:商品展示的划横线价格为参考价,该价格可能是品牌专柜标价、商品吊牌价或由品牌供应商提供的正品零售价(如厂商指导价、建议零售价等)或该商品在京东平台上曾经展示过的销售价;由于地区、时间的差异性和市场行情波动,品牌专柜标价、商品吊牌价等可能会与您购物时展示的不一致,该价格仅供您参考。
折扣:如无特殊说明,折扣指销售商在原价、或划线价(如品牌专柜标价、商品吊牌价、厂商指导价、厂商建议零售价)等某一价格基础上计算出的优惠比例或优惠金额;如有疑问,您可在购买前联系销售商进行咨询。
异常问题:商品促销信息以商品详情页“促销”栏中的信息为准;商品的具体售价以订单结算页价格为准;如您发现活动商品售价或促销信息有异常,建议购买前先联系销售商咨询。
加载中,请稍候...
加载中,请稍候...
加载中,请稍候...
加载中,请稍候...
加载中,请稍候...
加载中,请稍候...
加载中,请稍候...
浏览了该商品的用户还浏览了
加载中,请稍候...
七日畅销榜
新书热卖榜
iframe(src='//www.googletagmanager.com/ns.html?id=GTM-T947SH', height='0', width='0', style='display: visibility:')怎样打开用python编写的程序_百度知道
怎样打开用python编写的程序
我有更好的答案
提问者说的是dos命令下的打开方式:方法是Python 文件全路径名:当然也可以右键,选择Edit With IDLE;或者双击。
采纳率:64%
来自团队:
直接打开的话它就运行了。点击右键,第一个是打开,第二个是edit with IDLE,点第二个就能看到源代码
打开是这样的
你这文件保存的格式不对。你这个文件的类型是“文件”,python文件的类型是“python文件”新建python文件的方式有两种。1.打开记事本,写好源代码后,保存。保存时把文件格式设成“所有格式”,文件名后面加上“.py”。比如helloworld就保存成helloworld.py2.打开python的那个IDLE,就是那个白色的窗口,然后点击new window,在这个里面写源代码,然后直接保存就行。不用去修饰那个文件名或更改格式。然后再按我之前说的方法打开。附:如果你只是想看源代码的话,用记事本打开就行。但是这样运行不了程序。
本回答被提问者采纳
py为文件名结尾的文件运行方式,可以在python的ide里直接运行,也可以在shell里python 首先需要的是一个解释器,这个官网有的下python程序是以
为您推荐:
其他类似问题
您可能关注的内容
python的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。(如何(用Python)写一个(Lisp)解释器(上))6 months ago-;; Scheme
(if (& (val x) 0)
(fn (+ (aref A i) 1)
(quote (one two)))
Java有大量不同的语法约规(关键字、中置操作符、三种括号、操作符优先级、点、引号、逗号、分号等等),而Scheme的语法则简单很多:Scheme程序中只有表达式。表达式和声明之间并无区别。数字(例如 1)和符号(例如 A)被称之为原子表达式(atomic expression);他们无法被拆分成更小的表达式。这部分和Java类似,但在Scheme中,诸如 + 和 & 这种操作符也被认为是符号(symbol),处理方式与A或是fn这种符号别无二致。除此之外的一切都是列表表达式(list expression):以“(”为首,“)”为尾,中间包括着零个或更多表达式。列表的第一个元素决定了它的含义:若第一个元素是关键字,例如(if ...),那这个列表是一个特殊形式(special form);特殊形式的意义取决于关键字。若第一个元素并非关键字,例如(fn ...),那这个列表则是函数调用。Scheme之美在于她的简洁性:整个语言由5个关键字和8个语法形式构成。相较之下,Python有33个关键字和110个语法形式,Java有50个关键字和133个语法形式。Scheme中的大量括号初看起来可能显得古怪陌生,但括号为Scheme提供了简洁性和一致性。(有些人开玩笑说Lisp的意思是“大量又蠢又烦的括号(Lots of Irritating Silly Parentheses)”;我觉得应该是“Lisp拥有纯净的语法(Lisp Is Syntactically Pure)。”)在这篇文章中我们会涉及到Scheme中所有的关键点(除了一些琐碎的细节)。但罗马城不是一天建成的,我们需要分两步。首先,我们会定义一个相对简单的语言,再在它的基础上定义一个几近完整的Scheme语言。1号语言:Lispy计算器Lispy计算器是Scheme语言的一个子集,它只包含五种语法形式(两种原子,两个特殊形式,以及过程调用)。只要你习惯了Lisp前置运算符的古怪语法,你就能利用Lispy计算器干一般计算器的活。你还能干一般计算器干不了的活:使用"if"表达式进行条件判断以及定义新的变量。我们来举个例子,以下是一个计算圆面积的程序,圆的半径为10,计算公式为πr^2:(begin
(define r 10)
(* pi (* r r)))
下面这张表列举了所有可用的语法形式:在表中“语法”一列中,var必须为一个符号,number必须为一个整数或浮点数,其他斜体字可以是任何表达式。其中的“arg...”表示零个或更多个"arg"。在“真正”的Scheme中,begin是一个语法关键字,但在这个Scheme实现中,它只是一个普通的函数。语言解释器做些什么?一个计算机语言的解释器分为两部分:分析(parse):解释器的分析部分将程序以一串字符的形式读入,依照语法规则(syntactic rules)验证其正确性并将程序转换成一种内部表达形式。在一个简单的解释器中,内部表达形式是一个树形结构,人们一般将其称之为抽象语法树 (abstract syntax tree)。抽象语法树的结构和程序中层层嵌套的声明及表达式非常相近,几乎可以说是完美对应。在编译器之中往往存在多个内部表达形式,一开始先转换成抽象语法树,随后再转换成可以直接被计算器执行的指令序列。Lispy的语法分析器由parse函数实现。执行(execution):内部表达形式被按照语言的语法规则进行处理,以此来进行计算。Lispy的执行函数叫做eval (注意,这会覆盖Python的同名内置函数)。以下是对解释器工作流程的一个简单的演示:程序 ---& [parse] ---& 抽象语法树 ---& [eval] ---& 结果
下面这个例子则展示了我们希望eval和parse实现的功能:&& program = "(begin (define r 10) (* pi (* r r)))"
&&& parse(program)
['begin', ['define', 'r', 10], ['*', 'pi', ['*', 'r', 'r']]]
&&& eval(parse(program))
分析:parse, tokenize 以及 read_from_tokens依照传统,分析被分为两个部分:词法分析(lexical analysis):在这一部分中,输入的字符串被拆分为一系列的token。语法分析(syntactic analysis):将token汇编为抽象语法树。Lispy token们由括号,符号和数字组成。由许多用来进行词法分析的工具(例如Mike Lesk和Eric Schmidt写的lex),但我们只需要用到一个十分简单的工具:Python的str.split函数。tokenize函数接受一个字符串,并在括号周围加上空格;随后调用str.split来得到一个由token组成的列表:def tokenize(chars):
"将字符串转换成由token组成的列表。"
return chars.replace('(', ' ( ').replace(')', ' ) ').split()
&&& program = "(begin (define r 10) (* pi (* r r)))"
&&& tokenize(program)
['(', 'begin', '(', 'define', 'r', '10', ')', '(', '*', 'pi', '(', '*', 'r', 'r', ')', ')', ')']
我们的parse函数接收一个字符串作为输入,然后调用tokenize函数获得一个由token组成的列表,再调用read_from_tokens来将token列表汇编成抽象语法树。read_from_token函数会查看第一个token,如果是“)”,那就报出一个语法错误。如果是“(”,那我们就开始构建一个由子表达式组成的列表,直到匹配到对应的“)”。所有非括号的token必须是符号或者数字。我们会让Python来识别它们之间的区别:对任何一个非括号token,先尝试将之转为整数,若失败则尝试转为浮点数,若还是失败,则转为符号。下边是parser的代码:def parse(program):
"从字符串中读取Scheme表达式"
return read_from_tokens(tokenize(program))
def read_from_tokens(tokens):
"从一串token之中读取表达式"
if len(tokens) == 0:
raise SyntaxError('unexpected EOF while reading')
token = tokens.pop(0)
if '(' == token:
while tokens[0] != ')':
L.append(read_from_tokens(tokens))
tokens.pop(0) # pop off ')'
elif ')' == token:
raise SyntaxError('unexpected )')
return atom(token)
def atom(token):
"数字转为对应的Python数字,其余的转为符号"
try: return int(token)
except ValueError:
try: return float(token)
except ValueError:
return Symbol(token)
parse函数的工作方式如下:&&& program = "(begin (define r 10) (* pi (* r r)))"
&&& parse(program)
['begin', ['define', 'r', 10], ['*', 'pi', ['*', 'r', 'r']]]
我们还需要决定一下各种Scheme对象在Python中的表示方法:Symbol = str
# Scheme符号由Python str表示
# Scheme列表由Python list表示
Number = (int, float) # Scheme数字由Python的整数或浮点数表示
好了!定义eval的准备工作基本都做好了。但我们需要先了解更多的概念。环境(Environments)eval函数接受两个参数:一个我们想要求值的表达式x,还有一个环境env,x将在这个环境中被求值。环境指的是变量名和他们的值之间的映射。eval默认会使用全局环境(global environment)进行求值,全局环境包含着一系列的标准函数(比如sqrt, max和 * 这类操作符)。这一环境可以用用户定义的变量拓展,语法为 (define variable value)。我们可以用Python自带的字典来实现环境,字典中的键对为{变量: 值}的形式。import math
import operator as op
Env = dict
# 环境是{变量: 值}之间的映射
def standard_env():
"一个包含着一些Scheme标准过程的环境。"
env = Env()
env.update(vars(math)) # sin, cos, sqrt, pi, ...
env.update({
'+':op.add, '-':op.sub, '*':op.mul, '/':op.div,
'&':op.gt, '&':op.lt, '&=':op.ge, '&=':op.le, '=':op.eq,
lambda *x: x[-1],
lambda x: x[0],
lambda x: x[1:],
lambda x,y: [x] + y,
lambda *x: list(x),
lambda x: isinstance(x,list),
lambda x: x == [],
'number?': lambda x: isinstance(x, Number),
'procedure?': callable,
'symbol?': lambda x: isinstance(x, Symbol),
return env
global_env = standard_env()
求值:eval现在,我们已经做好了实现eval函数的准备。来让我们重新看一遍Lispy计算器的语法形式表以加深一下记忆:来和eval的代码对比一下,是不是觉得很像?def eval(x, env=global_env):
"对在某个环境下的表达式进行求值"
if isinstance(x, Symbol):
# 变量引用
return env[x]
elif not isinstance(x, List):
# 字面常量
elif x[0] == 'if':
(_, test, conseq, alt) = x
exp = (conseq if eval(test, env) else alt)
return eval(exp, env)
elif x[0] == 'define':
(_, var, exp) = x
env[var] = eval(exp, env)
# 过程调用
proc = eval(x[0], env)
args = [eval(arg, env) for arg in x[1:]]
return proc(*args)
搞定!来试试吧:&&& eval(parse("(define r 10)"))
&&& eval(parse("(* pi (* r r))"))
交互:来做一个REPL一直打“eval(parse(...))”的话即便是耐心再好的人也会嫌烦。Lisp最伟大的遗产之一就是引入了read-eval-print loop(读取-求值-输出 循环,缩写为REPL,译者注)。运用REPL,程序员们可以即时地读取、求值、输出,而不用麻烦地先编译再运行。我们先定义一个名为repl的函数以实现这个功能,然后再定义一个schemestr函数来输出Scheme对象的字符串表示。def repl(prompt='lis.py& '):
"REPL的懒人实现。"
while True:
val = eval(parse(raw_input(prompt)))
if val is not None:
print(schemestr(val))
def schemestr(exp):
"将一个Python对象转换回可以被Scheme读取的字符串。"
if isinstance(exp, List):
return '(' + ' '.join(map(schemestr, exp)) + ')'
return str(exp)
老样子,做完以后来试试:&&& repl()
lis.py& (define r 10)
lis.py& (* pi (* r r))
lis.py& (if (& (* 11 11) 120) (* 7 6) oops)
这一章中,我们实现了一个简单的Lisp计算器,在下半部分中,我们将在此基础上写一个更完整的Scheme解释器。(破乎什么时候才能支持Markdown,不能插表格也就算了,图的质量还压得那么差。)83收藏分享举报文章被以下专栏收录杂谈{&debug&:false,&apiRoot&:&&,&paySDK&:&https:\u002F\u002Fpay.zhihu.com\u002Fapi\u002Fjs&,&wechatConfigAPI&:&\u002Fapi\u002Fwechat\u002Fjssdkconfig&,&name&:&production&,&instance&:&column&,&tokens&:{&X-XSRF-TOKEN&:null,&X-UDID&:null,&Authorization&:&oauth c3cef7c66aa9e6a1e3160e20&}}{&database&:{&Post&:{&&:{&isPending&:false,&contributes&:[{&sourceColumn&:{&lastUpdated&:,&description&:&http:\u002F\u002Fzhuanlan.zhihu.com\u002Fmarisa\u002F&,&permission&:&COLUMN_PUBLIC&,&memberId&:7316099,&contributePermission&:&COLUMN_PUBLIC&,&translatedCommentPermission&:&all&,&canManage&:true,&intro&:&&,&urlToken&:&marisa&,&id&:9526,&imagePath&:&73fa95e05c4d73bd51b34eb72057ae95.jpeg&,&slug&:&marisa&,&applyReason&:&&,&name&:&雾雨魔法店&,&title&:&雾雨魔法店&,&url&:&https:\u002F\u002Fzhuanlan.zhihu.com\u002Fmarisa&,&commentPermission&:&COLUMN_ALL_CAN_COMMENT&,&canPost&:true,&created&:,&state&:&COLUMN_NORMAL&,&followers&:7678,&avatar&:{&id&:&73fa95e05c4d73bd51b34eb72057ae95&,&template&:&https:\u002F\u002Fpic1.zhimg.com\u002F{id}_{size}.jpg&},&activateAuthorRequested&:false,&following&:false,&imageUrl&:&https:\u002F\u002Fpic1.zhimg.com\u002F73fa95e05c4d73bd51b34eb72057ae95_l.jpg&,&articlesCount&:167},&state&:&accepted&,&targetPost&:{&titleImage&:&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-b613df87f6ac9ef472af5b_r.jpg&,&lastUpdated&:,&imagePath&:&v2-b613df87f6ac9ef472af5b.png&,&permission&:&ARTICLE_PUBLIC&,&topics&:[,872],&summary&:&\u003Ca href=\&https:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F\&\u003E下篇:(如何(用Python)写一个(Lisp)解释器(下))\u003C\u002Fa\u003E& 译自\u003Ca href=\&http:\u002F\u002Fnorvig.com\u002Flispy.html\&\u003EPeter Norvig的博客\u003C\u002Fa\u003E,有少量魔改这篇文章有两个目的:通用地介绍如何实现计算机语言的解释器。介绍如何利用Python实现Lisp方言Scheme的一个子集。\u003Cb\u003EScheme程序的语法和语义\u003C\u002Fb\u003E一门语言的语法(syntax…&,&copyPermission&:&ARTICLE_COPYABLE&,&translatedCommentPermission&:&all&,&likes&:0,&origAuthorId&:0,&publishedTime&:&T23:15:53+08:00&,&sourceUrl&:&&,&urlToken&:,&id&:3783701,&withContent&:false,&slug&:,&bigTitleImage&:false,&title&:&(如何(用Python)写一个(Lisp)解释器(上))&,&url&:&\u002Fp\u002F&,&commentPermission&:&ARTICLE_ALL_CAN_COMMENT&,&snapshotUrl&:&&,&created&:,&comments&:0,&columnId&:0,&content&:&&,&parentId&:0,&state&:&ARTICLE_PUBLISHED&,&imageUrl&:&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-b613df87f6ac9ef472af5b_r.jpg&,&author&:{&bio&:&eval\u002Fapply enthusiasm\u002Fdepression&,&isFollowing&:false,&hash&:&69ed26ac738de&,&uid&:016000,&isOrg&:false,&slug&:&li-yu-&,&isFollowed&:false,&description&:&'Tis magic, magic, that hath ravish'd me.&,&name&:&李愚&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fli-yu-&,&avatar&:{&id&:&v2-0daf67a030db4dffde36dda550a36d4a&,&template&:&https:\u002F\u002Fpic1.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&memberId&:,&excerptTitle&:&&,&voteType&:&ARTICLE_VOTE_CLEAR&},&id&:796607},{&sourceColumn&:{&lastUpdated&:,&description&:&&,&permission&:&COLUMN_PUBLIC&,&memberId&:,&contributePermission&:&COLUMN_PUBLIC&,&translatedCommentPermission&:&all&,&canManage&:true,&intro&:&杂谈&,&urlToken&:&c_&,&id&:61368,&imagePath&:&v2-5d0bfab414e31af177bf559ddb57e969.png&,&slug&:&c_&,&applyReason&:&0&,&name&:&愚人之庭院&,&title&:&愚人之庭院&,&url&:&https:\u002F\u002Fzhuanlan.zhihu.com\u002Fc_&,&commentPermission&:&COLUMN_ALL_CAN_COMMENT&,&canPost&:true,&created&:,&state&:&COLUMN_NORMAL&,&followers&:21,&avatar&:{&id&:&v2-5d0bfab414e31af177bf559ddb57e969&,&template&:&https:\u002F\u002Fpic3.zhimg.com\u002F{id}_{size}.jpg&},&activateAuthorRequested&:false,&following&:false,&imageUrl&:&https:\u002F\u002Fpic3.zhimg.com\u002Fv2-5d0bfab414e31af177bf559ddb57e969_l.jpg&,&articlesCount&:6},&state&:&accepted&,&targetPost&:{&titleImage&:&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-b613df87f6ac9ef472af5b_r.jpg&,&lastUpdated&:,&imagePath&:&v2-b613df87f6ac9ef472af5b.png&,&permission&:&ARTICLE_PUBLIC&,&topics&:[,872],&summary&:&\u003Ca href=\&https:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F\&\u003E下篇:(如何(用Python)写一个(Lisp)解释器(下))\u003C\u002Fa\u003E& 译自\u003Ca href=\&http:\u002F\u002Fnorvig.com\u002Flispy.html\&\u003EPeter Norvig的博客\u003C\u002Fa\u003E,有少量魔改这篇文章有两个目的:通用地介绍如何实现计算机语言的解释器。介绍如何利用Python实现Lisp方言Scheme的一个子集。\u003Cb\u003EScheme程序的语法和语义\u003C\u002Fb\u003E一门语言的语法(syntax…&,&copyPermission&:&ARTICLE_COPYABLE&,&translatedCommentPermission&:&all&,&likes&:0,&origAuthorId&:0,&publishedTime&:&T23:15:53+08:00&,&sourceUrl&:&&,&urlToken&:,&id&:3783701,&withContent&:false,&slug&:,&bigTitleImage&:false,&title&:&(如何(用Python)写一个(Lisp)解释器(上))&,&url&:&\u002Fp\u002F&,&commentPermission&:&ARTICLE_ALL_CAN_COMMENT&,&snapshotUrl&:&&,&created&:,&comments&:0,&columnId&:0,&content&:&&,&parentId&:0,&state&:&ARTICLE_PUBLISHED&,&imageUrl&:&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-b613df87f6ac9ef472af5b_r.jpg&,&author&:{&bio&:&eval\u002Fapply enthusiasm\u002Fdepression&,&isFollowing&:false,&hash&:&69ed26ac738de&,&uid&:016000,&isOrg&:false,&slug&:&li-yu-&,&isFollowed&:false,&description&:&'Tis magic, magic, that hath ravish'd me.&,&name&:&李愚&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fli-yu-&,&avatar&:{&id&:&v2-0daf67a030db4dffde36dda550a36d4a&,&template&:&https:\u002F\u002Fpic1.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&memberId&:,&excerptTitle&:&&,&voteType&:&ARTICLE_VOTE_CLEAR&},&id&:834506}],&title&:&(如何(用Python)写一个(Lisp)解释器(上))&,&author&:&li-yu-&,&content&:&\u003Cp\u003E\u003Ca href=\&https:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F\& class=\&internal\&\u003E下篇:(如何(用Python)写一个(Lisp)解释器(下))\u003C\u002Fa\u003E\u003C\u002Fp\u003E\u003Cp\u003E& 译自\u003Ca href=\&http:\u002F\u002Flink.zhihu.com\u002F?target=http%3A\u002F\u002Fnorvig.com\u002Flispy.html\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EPeter Norvig的博客\u003C\u002Fa\u003E,有少量魔改\u003C\u002Fp\u003E\u003Cp\u003E这篇文章有两个目的:\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003E通用地介绍如何实现计算机语言的解释器。\u003C\u002Fli\u003E\u003Cli\u003E介绍如何利用Python实现Lisp方言Scheme的一个子集。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Ch2\u003E\u003Cb\u003EScheme程序的语法和语义\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E一门语言的语法(syntax)指的是字母排列成正确表达式或声明的顺序;语义(semantics)则是这些表达式或声明的意义。例如在数学和许多编程语言之中,一加二的语法是“1 + 2”, 语义则是将加法运算符应用于数字1和2之上,得到结果3。我们将计算表达式的值称之为求值(evaluating);“1 + 2”求值得到结果3,我们将之记为“1 + 2” =& 3。\u003C\u002Fp\u003E\u003Cp\u003EScheme的语法与你熟悉的大部分语言不同。例如:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-java\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&c1\&\u003E\u002F\u002F Java\u003C\u002Fspan\u003E\n\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003Eval\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E()\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E \n
\u003Cspan class=\&n\&\u003Efn\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EA\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ei\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E+\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Enew\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EString\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E[]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\u003Cspan class=\&s\&\u003E\&one\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s\&\u003E\&two\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E});\u003C\u002Fspan\u003E \n\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E-\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-scheme\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&c1\&\u003E;; Scheme\u003C\u002Fspan\u003E\n\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&k\&\u003Eif \u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nb\&\u003E& \u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nf\&\u003Eval\u003C\u002Fspan\u003E \u003Cspan class=\&nv\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \n
\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nf\&\u003Efn\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nb\&\u003E+ \u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nf\&\u003Earef\u003C\u002Fspan\u003E \u003Cspan class=\&nv\&\u003EA\u003C\u002Fspan\u003E \u003Cspan class=\&nv\&\u003Ei\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \n
\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&k\&\u003Equote \u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nf\&\u003Eone\u003C\u002Fspan\u003E \u003Cspan class=\&nv\&\u003Etwo\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)))\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003EJava有大量不同的语法约规(关键字、中置操作符、三种括号、操作符优先级、点、引号、逗号、分号等等),而Scheme的语法则简单很多:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003EScheme程序中只有表达式。表达式和声明之间并无区别。\u003C\u002Fli\u003E\u003Cli\u003E数字(例如 1)和符号(例如 A)被称之为原子表达式(atomic expression);他们无法被拆分成更小的表达式。这部分和Java类似,但在Scheme中,诸如 + 和 & 这种操作符也被认为是符号(symbol),处理方式与A或是fn这种符号别无二致。\u003C\u002Fli\u003E\u003Cli\u003E除此之外的一切都是列表表达式(list expression):以“(”为首,“)”为尾,中间包括着零个或更多表达式。列表的第一个元素决定了它的含义:\u003C\u002Fli\u003E\u003Cul\u003E\u003Cli\u003E若第一个元素是关键字,例如(if ...),那这个列表是一个特殊形式(special form);特殊形式的意义取决于关键字。\u003C\u002Fli\u003E\u003Cli\u003E若第一个元素并非关键字,例如(fn ...),那这个列表则是函数调用。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003EScheme之美在于她的简洁性:整个语言由5个关键字和8个语法形式构成。相较之下,Python有33个关键字和110个语法形式,Java有50个关键字和133个语法形式。Scheme中的大量括号初看起来可能显得古怪陌生,但括号为Scheme提供了简洁性和一致性。(有些人开玩笑说Lisp的意思是“大量又蠢又烦的括号(Lots of Irritating Silly Parentheses)”;我觉得应该是“Lisp拥有纯净的语法(Lisp Is Syntactically Pure)。”)\u003C\u002Fp\u003E\u003Cp\u003E在这篇文章中我们会涉及到Scheme中所有的关键点(除了一些琐碎的细节)。但罗马城不是一天建成的,我们需要分两步。首先,我们会定义一个相对简单的语言,再在它的基础上定义一个几近完整的Scheme语言。\u003C\u002Fp\u003E\u003Ch2\u003E\u003Cb\u003E1号语言:Lispy计算器\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003ELispy计算器是Scheme语言的一个子集,它只包含五种语法形式(两种原子,两个特殊形式,以及过程调用)。只要你习惯了Lisp前置运算符的古怪语法,你就能利用Lispy计算器干一般计算器的活。你还能干一般计算器干不了的活:使用\&if\&表达式进行条件判断以及定义新的变量。我们来举个例子,以下是一个计算圆面积的程序,圆的半径为10,计算公式为πr^2:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-scheme\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nf\&\u003Ebegin\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&k\&\u003Edefine \u003C\u002Fspan\u003E\u003Cspan class=\&nv\&\u003Er\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E10\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nb\&\u003E* \u003C\u002Fspan\u003E\u003Cspan class=\&nv\&\u003Epi\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nb\&\u003E* \u003C\u002Fspan\u003E\u003Cspan class=\&nv\&\u003Er\u003C\u002Fspan\u003E \u003Cspan class=\&nv\&\u003Er\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)))\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E下面这张表列举了所有可用的语法形式:\u003C\u002Fp\u003E\u003Cp\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-dd978e5bb96fff4a144b3a27fef70c21_b.jpg\& data-rawwidth=\&725\& data-rawheight=\&567\& class=\&origin_image zh-lightbox-thumb\& width=\&725\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-dd978e5bb96fff4a144b3a27fef70c21_r.jpg\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='725'%20height='567'&&\u002Fsvg&\& data-rawwidth=\&725\& data-rawheight=\&567\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&725\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-dd978e5bb96fff4a144b3a27fef70c21_r.jpg\& data-actualsrc=\&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-dd978e5bb96fff4a144b3a27fef70c21_b.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E在表中“语法”一列中,\u003Ci\u003Evar\u003C\u002Fi\u003E必须为一个符号,\u003Ci\u003Enumber\u003C\u002Fi\u003E必须为一个整数或浮点数,其他斜体字可以是任何表达式。其中的“\u003Ci\u003Earg...\u003C\u002Fi\u003E”表示零个或更多个\&\u003Ci\u003Earg\u003C\u002Fi\u003E\&。在“真正”的Scheme中,begin是一个语法关键字,但在这个Scheme实现中,它只是一个普通的函数。\u003C\u002Fp\u003E\u003Ch2\u003E\u003Cb\u003E语言解释器做些什么?\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E一个计算机语言的解释器分为两部分:\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003E\u003Cb\u003E分析(parse)\u003C\u002Fb\u003E:解释器的分析部分将程序以一串字符的形式读入,依照语法规则(\u003Ci\u003Esyntactic rules\u003C\u002Fi\u003E)验证其正确性并将程序转换成一种内部表达形式。在一个简单的解释器中,内部表达形式是一个树形结构,人们一般将其称之为\u003Ci\u003E抽象语法树 (abstract syntax tree)\u003C\u002Fi\u003E。抽象语法树的结构和程序中层层嵌套的声明及表达式非常相近,几乎可以说是完美对应。在编译器之中往往存在多个内部表达形式,一开始先转换成抽象语法树,随后再转换成可以直接被计算器执行的指令序列。Lispy的语法分析器由parse函数实现。\u003C\u002Fli\u003E\u003Cli\u003E\u003Cb\u003E执行(execution)\u003C\u002Fb\u003E:内部表达形式被按照语言的语法规则进行处理,以此来进行计算。Lispy的执行函数叫做eval (注意,这会覆盖Python的同名内置函数)。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E以下是对解释器工作流程的一个简单的演示:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E程序 ---& [parse] ---& 抽象语法树 ---& [eval] ---& 结果\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E下面这个例子则展示了我们希望eval和parse实现的功能:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E&& program = \&(begin (define r 10) (* pi (* r r)))\&\n\n&&& parse(program)\n['begin', ['define', 'r', 10], ['*', 'pi', ['*', 'r', 'r']]]\n\n&&& eval(parse(program))\n314.3\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Ch2\u003E\u003Cb\u003E分析:parse, tokenize 以及 read_from_tokens\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E依照传统,分析被分为两个部分:\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003E词法分析(lexical analysis):在这一部分中,输入的字符串被拆分为一系列的token。\u003C\u002Fli\u003E\u003Cli\u003E语法分析(syntactic analysis):将token汇编为抽象语法树。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003ELispy token们由括号,符号和数字组成。由许多用来进行词法分析的工具(例如Mike Lesk和Eric Schmidt写的lex),但我们只需要用到一个十分简单的工具:Python的str.split函数。tokenize函数接受一个字符串,并在括号周围加上空格;随后调用str.split来得到一个由token组成的列表:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-python\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&k\&\u003Edef\u003C\u002Fspan\u003E \u003Cspan class=\&nf\&\u003Etokenize\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Echars\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E):\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&将字符串转换成由token组成的列表。\&\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Echars\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ereplace\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'('\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E' ( '\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ereplace\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E')'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E' ) '\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Esplit\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E()\u003C\u002Fspan\u003E\n\u003Cspan class=\&o\&\u003E&&&\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eprogram\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&s2\&\u003E\&(begin (define r 10) (* pi (* r r)))\&\u003C\u002Fspan\u003E\n\u003Cspan class=\&o\&\u003E&&&\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Etokenize\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eprogram\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'('\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'begin'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'('\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'define'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'r'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'10'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E')'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'('\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'*'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'pi'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'('\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'*'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'r'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'r'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E')'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E')'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E')'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E]\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E我们的parse函数接收一个字符串作为输入,然后调用tokenize函数获得一个由token组成的列表,再调用read_from_tokens来将token列表汇编成抽象语法树。read_from_token函数会查看第一个token,如果是“)”,那就报出一个语法错误。如果是“(”,那我们就开始构建一个由子表达式组成的列表,直到匹配到对应的“)”。所有非括号的token必须是符号或者数字。我们会让Python来识别它们之间的区别:对任何一个非括号token,先尝试将之转为整数,若失败则尝试转为浮点数,若还是失败,则转为符号。下边是parser的代码:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-python\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&k\&\u003Edef\u003C\u002Fspan\u003E \u003Cspan class=\&nf\&\u003Eparse\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eprogram\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E):\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&从字符串中读取Scheme表达式\&\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eread_from_tokens\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etokenize\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eprogram\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E))\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&k\&\u003Edef\u003C\u002Fspan\u003E \u003Cspan class=\&nf\&\u003Eread_from_tokens\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etokens\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E):\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&从一串token之中读取表达式\&\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Elen\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etokens\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eraise\u003C\u002Fspan\u003E \u003Cspan class=\&ne\&\u003ESyntaxError\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'unexpected EOF while reading'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Etoken\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Etokens\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Epop\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'('\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Etoken\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EL\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E[]\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ewhile\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Etokens\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!=\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E')'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EL\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eappend\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eread_from_tokens\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etokens\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E))\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Etokens\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Epop\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&c1\&\u003E# pop off ')'\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EL\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eelif\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E')'\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Etoken\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eraise\u003C\u002Fspan\u003E \u003Cspan class=\&ne\&\u003ESyntaxError\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'unexpected )'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eelse\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eatom\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etoken\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&k\&\u003Edef\u003C\u002Fspan\u003E \u003Cspan class=\&nf\&\u003Eatom\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etoken\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E):\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&数字转为对应的Python数字,其余的转为符号\&\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Etry\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eint\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etoken\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eexcept\u003C\u002Fspan\u003E \u003Cspan class=\&ne\&\u003EValueError\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Etry\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Efloat\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etoken\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eexcept\u003C\u002Fspan\u003E \u003Cspan class=\&ne\&\u003EValueError\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003ESymbol\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etoken\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003Eparse函数的工作方式如下:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E&&& program = \&(begin (define r 10) (* pi (* r r)))\&\n\n&&& parse(program)\n['begin', ['define', 'r', 10], ['*', 'pi', ['*', 'r', 'r']]]\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E我们还需要决定一下各种Scheme对象在Python中的表示方法:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-python\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003ESymbol\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Estr\u003C\u002Fspan\u003E
\u003Cspan class=\&c1\&\u003E# Scheme符号由Python str表示\u003C\u002Fspan\u003E\n\u003Cspan class=\&n\&\u003EList\u003C\u002Fspan\u003E
\u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Elist\u003C\u002Fspan\u003E
\u003Cspan class=\&c1\&\u003E# Scheme列表由Python list表示\u003C\u002Fspan\u003E\n\u003Cspan class=\&n\&\u003ENumber\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nb\&\u003Eint\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Efloat\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&c1\&\u003E# Scheme数字由Python的整数或浮点数表示\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E好了!定义eval的准备工作基本都做好了。但我们需要先了解更多的概念。\u003C\u002Fp\u003E\u003Ch2\u003E\u003Cb\u003E环境(Environments)\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003Eeval函数接受两个参数:一个我们想要求值的表达式x,还有一个环境env,x将在这个环境中被求值。\u003Ci\u003E环境\u003C\u002Fi\u003E指的是变量名和他们的值之间的映射。eval默认会使用全局环境(global environment)进行求值,全局环境包含着一系列的标准函数(比如sqrt, max和 * 这类操作符)。这一环境可以用用户定义的变量拓展,语法为 (\u003Ci\u003Edefine variable value\u003C\u002Fi\u003E)。我们可以用Python自带的字典来实现环境,字典中的键对为{变量: 值}的形式。\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-python\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kn\&\u003Eimport\u003C\u002Fspan\u003E \u003Cspan class=\&nn\&\u003Emath\u003C\u002Fspan\u003E\n\u003Cspan class=\&kn\&\u003Eimport\u003C\u002Fspan\u003E \u003Cspan class=\&nn\&\u003Eoperator\u003C\u002Fspan\u003E \u003Cspan class=\&kn\&\u003Eas\u003C\u002Fspan\u003E \u003Cspan class=\&nn\&\u003Eop\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&n\&\u003EEnv\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Edict\u003C\u002Fspan\u003E
\u003Cspan class=\&c1\&\u003E# 环境是{变量: 值}之间的映射\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&k\&\u003Edef\u003C\u002Fspan\u003E \u003Cspan class=\&nf\&\u003Estandard_env\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E():\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&一个包含着一些Scheme标准过程的环境。\&\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EEnv\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E()\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eupdate\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nb\&\u003Evars\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Emath\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E))\u003C\u002Fspan\u003E \u003Cspan class=\&c1\&\u003E# sin, cos, sqrt, pi, ...\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eupdate\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E({\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'+'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eadd\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'-'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Esub\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'*'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Emul\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'\u002F'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ediv\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \n
\u003Cspan class=\&s1\&\u003E'&'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Egt\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'&'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Elt\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'&='\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ege\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'&='\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ele\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'='\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eeq\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \n
\u003Cspan class=\&s1\&\u003E'abs'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&nb\&\u003Eabs\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'append'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eadd\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E
\u003Cspan class=\&s1\&\u003E'apply'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&nb\&\u003Eapply\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'begin'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&k\&\u003Elambda\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E*\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E-\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E],\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'car'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&k\&\u003Elambda\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E],\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'cdr'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&k\&\u003Elambda\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:],\u003C\u002Fspan\u003E \n
\u003Cspan class=\&s1\&\u003E'cons'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&k\&\u003Elambda\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ey\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E+\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ey\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'eq?'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eis_\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \n
\u003Cspan class=\&s1\&\u003E'equal?'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eeq\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \n
\u003Cspan class=\&s1\&\u003E'length'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&nb\&\u003Elen\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \n
\u003Cspan class=\&s1\&\u003E'list'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&k\&\u003Elambda\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E*\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Elist\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E),\u003C\u002Fspan\u003E \n
\u003Cspan class=\&s1\&\u003E'list?'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&k\&\u003Elambda\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eisinstance\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&nb\&\u003Elist\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E),\u003C\u002Fspan\u003E \n
\u003Cspan class=\&s1\&\u003E'map'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&nb\&\u003Emap\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'max'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&nb\&\u003Emax\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'min'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&nb\&\u003Emin\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'not'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&n\&\u003Eop\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Enot_\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'null?'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&k\&\u003Elambda\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E[],\u003C\u002Fspan\u003E \n
\u003Cspan class=\&s1\&\u003E'number?'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Elambda\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eisinstance\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003ENumber\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E),\u003C\u002Fspan\u003E
\u003Cspan class=\&s1\&\u003E'procedure?'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Ecallable\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'round'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&nb\&\u003Eround\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'symbol?'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Elambda\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eisinstance\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003ESymbol\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E),\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E})\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&n\&\u003Eglobal_env\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Estandard_env\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E()\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Ch2\u003E\u003Cb\u003E求值:eval\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E现在,我们已经做好了实现eval函数的准备。来让我们重新看一遍Lispy计算器的语法形式表以加深一下记忆:\u003C\u002Fp\u003E\u003Cp\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-dd978e5bb96fff4a144b3a27fef70c21_b.jpg\& data-rawwidth=\&725\& data-rawheight=\&567\& class=\&origin_image zh-lightbox-thumb\& width=\&725\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-dd978e5bb96fff4a144b3a27fef70c21_r.jpg\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='725'%20height='567'&&\u002Fsvg&\& data-rawwidth=\&725\& data-rawheight=\&567\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&725\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-dd978e5bb96fff4a144b3a27fef70c21_r.jpg\& data-actualsrc=\&https:\u002F\u002Fpic2.zhimg.com\u002Fv2-dd978e5bb96fff4a144b3a27fef70c21_b.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E来和eval的代码对比一下,是不是觉得很像?\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-python\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&k\&\u003Edef\u003C\u002Fspan\u003E \u003Cspan class=\&nf\&\u003Eeval\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eglobal_env\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E):\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&对在某个环境下的表达式进行求值\&\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eisinstance\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003ESymbol\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E):\u003C\u002Fspan\u003E
\u003Cspan class=\&c1\&\u003E# 变量引用\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E]\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eelif\u003C\u002Fspan\u003E \u003Cspan class=\&ow\&\u003Enot\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eisinstance\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EList\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E):\u003C\u002Fspan\u003E
\u003Cspan class=\&c1\&\u003E# 字面常量\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E
\u003Cspan class=\&k\&\u003Eelif\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'if'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&c1\&\u003E# 条件\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003E_\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Etest\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Econseq\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ealt\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eexp\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Econseq\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eeval\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etest\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Eelse\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ealt\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eeval\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eexp\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eelif\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'define'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&c1\&\u003E# 定义\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003E_\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Evar\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eexp\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Evar\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eeval\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eexp\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eenv\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eelse\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E
\u003Cspan class=\&c1\&\u003E# 过程调用\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eproc\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003Eeval\u003C\u0}

我要回帖

更多关于 python快速入门 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信