`
Lich_Ray
  • 浏览: 164087 次
  • 性别: Icon_minigender_1
  • 来自: 南京
文章分类
社区版块
存档分类
最新评论

尝试用Python实现消息传递编程风格

阅读更多
引用
本文站在一个难以名状的角度上研究了 Python 语言中消息发送的编程风格。原文是使用 JavaScript 描述的。文章作者 lichray 只把文章的上篇改成了 Python,因为下篇对于 Python 来说是没有意义的。lichray 是个 ECMAScript 的狂热追随者,mozilla.org 邮件列表里的无名潜水员。
文章中使用了 Python 解释器,行开头有 ">>>" 表示那是输入,输入下一行没有这个标记的表示解释器回馈消息。省略了多余的回馈。
PS: 文章用处不大。


[size=9]一. 对象和消息
考虑一下我们平常怎么说话的。我们叫某某人做某事,用下面的句式:
forest run!
其中"!"是语气的标志,对于编程语言来说是没有意义的,全部换成".":
forrest run.
不知道如果我告诉大家上面这句话就是 Smalltalk 语言中一个合法语句大家会怎么想。好了,不谈这个。这样我们就得到了一种语法,"宾"谓结构:
ObjectVerb::
	Object Verb.

如果让它支持多个 Verb,比如
forrest run, jump, stop.
可以扩展成这样:
ObjectVerb::
	Object VerbList.
VerbList::
	Verb
	Verb , VerbList

很明显,对于 Python 来说,上面的 BNF 不可能和任何一个产生式匹配。问题出在哪儿?我们要帮 Python 指定,谁是 Object,谁是 Verb。鉴于 Object 只有一个,Verb 有多个,我们可以用括号来区分它们,然后把最后那个句号去掉:
ObjectVerb::
	Object ( VerbList )

这样上面的那句话就变成了下面的形式:
forrest (run, jump, stop)
很像函数调用,是吧?不过还有一个问题,现在这些 Verb(s) 对于 Python 来说是“裸词”(Perl 语),我们可以避开再去定义这些标识符,用字符串代替;最后再说明一下 Object 是什么:
forrest ('run', 'jump', 'stop')
那么现在我们第一个“模仿”自然语言的程序版本出现了,加上下面针对 Python 的文法:
Object::
	Identifier
Verb::
	StringLiteral


二. 实现消息传递
有了文法,一切都好办。看得出来,我们下面的工作是定义能创建一个新 Object 的函数,函数中有一些动作,产生的新 Object 是一个能处理这些消息的函数。创建 Forrest Gump 的函数还可以创建 Tom,Mike 等等;他们都是 People:
def People ():
	def run ():
		print("I'm running!")
	
	def jump ():
		print("I'm jumping!")
	
	def stop ():
		print("I can't stop!")
		
	def _dispatch_ (verb):
		if verb == 'run': run()
		elif verb == 'jump': jump()
		elif verb == 'stop': stop()

	return _dispatch_


当然,我们可以用 lambda 和 eval() 替换显式的 _dispatch_ 函数。需要注意是,使用 eval() 要先保存上层执行环境:
def People ():
	def run ():
		print("I'm running!")
	
	def jump ():
		print("I'm jumping!")
	
	def stop ():
		print("I can't stop!")
		
	local = locals()
	return (lambda verb: eval(verb, globals() ,local)())


Ok。现在我们来试一试这个智商低于 85 的 Forrest Gump 怎么样:
>>> forrest = People()
>>> forrest('run')
I'm running!
>>> forrest('jump')
I'm jumping!
>>> forrest('stop')
I can't stop!
事情就是这样。我们成功地创造了对象,还让他做动作、说话。
不过,这个实现并不是我们上文中最后一个文法所指出的。它不支持连续发送指令。改一改。要加入顺序执行指令的办法:
def People ():
	def run ():
		print("I'm running!")
	
	def jump ():
		print("I'm jumping!")
	
	def stop ():
		print("I can't stop!")
	
	local = locals()
	return lambda *verblist: map((lambda verb: (eval(verb, globals(), local))()), verblist)


这下似乎比较像样了:
>>> forrest = People()
>>> forrest('jump','run','jump','stop')
I'm jumping!
I'm running!
I'm jumping!
I can't stop!

三. 利用消息传递处理状态
什么是状态?我们在进行面向对象编程时,把状态表示为对象的一组数据,我们称之为“属性(property)”。在我们的消息传递编程风格中,可以直接把这些数据堆到产生对象的那个函数中去。下面给 Forrest 加入一个状态,Forrest 口袋里的钱。先得声明原先有多少钱:
forrest = People(1000)
然后,我们希望可以执行这样的代码,让 forrest 支出 200 美元:
forrest('pay', 200)
但很明显,我们无法分清 200 是 Verb 还是 'pay' 所要求的数据。我们只得简化文法,只允许一次发送一个消息,以保全我们的脑细胞:
forrest('pay')(200)
也就是说,我们需要让 forrest('pay') 这一表达式返回一个能改变状态的函数,而不仅仅是调用函数来显示一句话。也就是说,如果我们想让 Forrest 急得跳起来,我们先得跳起来:
forrest('jump')()
新时代的 Forrest 实现如下(省略了一点多余的代码):
def People (money):
	local = locals()
	def pay (dollars):
		local['money'] = local['money'] - dollars
	
	def restMoney ():
		return local['money']
	
	def run ():
		print("I'm running!")
	
	local = locals()
	return lambda verb: eval(verb, globals(), local)


试一下。先支出 200 美元,然后看看他还剩多少钱:
>>> forrest=People(1000)
>>> forrest('restMoney')()
1000
>>> forrest('pay')(200)
>>> forrest('restMoney')()
800
当然,我们的 Forrest 还可以赚钱。下面这个版本比较彻底地说明了消息传递编程风格的一切。可以直接修改钱之后,我们可以不需要在创建 Object 的时候就说明原有多少钱;当然,使用注释中的版本更自然:
def People ():
	# def People (money):
	money = 0  # money = money or 0
	local = locals()
	def setMoney (dollars):
		local['money'] = dollars
	
	def addMoney (dollars):
		local['money'] = local['money'] + dollars
	
	def pay (dollars):
		local['money'] = local['money'] - dollars
	
	def restMoney ():
		return local['money']
	
	local = locals()
	return lambda verb: eval(verb, globals(), local)


试一下吧:
>>> forrest = People()
>>> forrest('addMoney')(1000)
>>> forrest('restMoney')()
1000
>>> forrest('pay')(200)
>>> forrest('restMoney')()
800

四. 小结
消息传递的编程风格指的是,把函数 A 的执行上下文当作对象的数据环境,在此定义对象的动词(函数),然后从此上下文中返回一个可以接受、处理消息的函数(常为匿名)。用函数 A 产生消息处理器作为对象,向此对象传递参数作为消息,以此执行函数 A 环境中定义的动作,这些动作还可能改变所在上下文中用一组数据定义的对象状态。
[/size]
分享到:
评论
13 楼 charon 2007-06-11  
Lich_Ray 写道
你的那个例子不是一回事吗。都说了文章是直接从别的语言转过来的,我很多Python的特性都没有用。

PS: LS牛X吹大了吧。真不巧,我就猜到你会说Lua和JavaScript的不是。告诉你Lua和JavaScript的面向对象机制非同小可,你不信?行啊。Walk & See.


切. 不需要walk and see了,人家javascript自己都已经开始从基于原型的OO向基于class的OO转变了.
http://developer.mozilla.org/presentations/xtech2006/javascript/
对象级别上基于原型的语言,和以class为基础的OO语言,在处理上有很多麻烦的地方,特别像javascript/lua这样的,所以javascript2才会引入一大票package、interface、class、implement、extend这类东西.
兄弟你说的强大的面对对象机制说的不会是这个传说中的javascript2吧.
对于现实意义中的javascipt,在面向对象这个问题中,最简单的一个测试,去实现一下继承和重载,并且在子类重新定义的函数中调用父类的同名被重载函数(一个非常常见的场景), 这个时候,你会发现肠子都钩出来才行.当然了,用一些第三方包可以较为简捷的处理这个,但那样做,和汇编语言的面向对象化没啥区别.
至于lua,相信前面给的那两个链接,仔细读过的人,至少在这个问题上,都会有点感受吧. lua在语言层面为面向对象准备了良好的基础,但是仅仅在这个基础上不自己裹一层就想直接裸着开干OO,累得不是一点两点.
了解一个语言,不是知道了语法要素,写过几个类似于hello world的东西就算大拿了.
12 楼 厌倦发呆 2007-06-11  
大家先别忙着吵,谁先定义一下啥叫“面向对象机制”,以及评价“面向对象机制”好不好的标准如何?
JS是基于原型的语言,因此很灵活,不过像mixin之类的功能,其实要自己动手来搞,不知道算不算支持弱呢?汗。但是JS继承了很多lisp的理念,用function可以模拟所谓的OO中相当多的东西,这个算不算支持好呢?

PS:本来想多插两句,写了几句发现无处着力亚
11 楼 Lich_Ray 2007-06-11  
你的那个例子不是一回事吗。都说了文章是直接从别的语言转过来的,我很多Python的特性都没有用。

PS: LS牛X吹大了吧。真不巧,我就猜到你会说Lua和JavaScript的不是。告诉你Lua和JavaScript的面向对象机制非同小可,你不信?行啊。Walk & See.
10 楼 charon 2007-06-10  
Lich_Ray 写道
我见过的语言中数它最差
Smalltalk Ruby JavaScript Lua E Scala Groovy Self
其中 E 的面向对象机制已经到了“高山仰止,境行行止”的地步。
http://www.erights.org
Python 的面向对象机制超过哪个了

牛X吹大了吧
你认为最差只不过因为这些语言中,你最不了解python。
从你的那个列表里面,至少javascript和lua的在面向对象这个层面是弱于python的。
别的偶不懂,就不说了。
9 楼 charon 2007-06-10  
Lich_Ray 写道
""而对付那个lambda返回值中eval的参数,直接调用locals().""
这样的话会找不到内层名字空间,我试过了。

hehe. 这个是我的疏忽。忘了在交互环境下测试一下。在这个lambda里面执行locals(),找到的是该匿名函数的locals,而不是那个外层函数的。在你这个例子中,通常会采用的是如下的方式:
lambda verb(local=locals()): eval(verb, globals(), local)  

8 楼 Lich_Ray 2007-06-10  
我见过的语言中数它最差
Smalltalk Ruby JavaScript Lua E Scala Groovy Self
其中 E 的面向对象机制已经到了“高山仰止,境行行止”的地步。
http://www.erights.org
Python 的面向对象机制超过哪个了?
此外一些比较“硬”的语言,其机制我不喜欢,不提了。
7 楼 liping 2007-06-10  
Lich_Ray 写道


呼呼~~你们说 Python 面向对象机制强悍,我还说 Python 函数式编程机制失败呢——都说了原文是用 JavaScript,写的而且仅仅是 show 着玩儿的,说明一下问题而已。下次不用 Python,但是我用的那些语言 JavaEye 上看得懂的人有多少?

PS: 别以为 Python 面向对象机制有多强悍。实话说,我见过的语言中数它最差(本来反对 OOP 的语言除外)。



综上所述猜测:牛的有点大!
6 楼 gigix 2007-06-10  
Lich_Ray 写道
呼呼~~你们说 Python 面向对象机制强悍,我还说 Python 函数式编程机制失败呢——都说了原文是用 JavaScript,写的而且仅仅是 show 着玩儿的,说明一下问题而已。下次不用 Python,但是我用的那些语言 JavaEye 上看得懂的人有多少

我记得以前TrustNo1讲解FP用的就是Python示例
红色这句彪悍
5 楼 Lich_Ray 2007-06-10  
""而对付那个lambda返回值中eval的参数,直接调用locals().""
这样的话会找不到内层名字空间,我试过了。

呼呼~~你们说 Python 面向对象机制强悍,我还说 Python 函数式编程机制失败呢——都说了原文是用 JavaScript,写的而且仅仅是 show 着玩儿的,说明一下问题而已。下次不用 Python,但是我用的那些语言 JavaEye 上看得懂的人有多少?

PS: 别以为 Python 面向对象机制有多强悍。实话说,我见过的语言中数它最差(本来反对 OOP 的语言除外)。
4 楼 charon 2007-06-09  
LZ虽然写了很多,但是偶赞同gigix的看法(虽然gigix的那行代码貌似有点问题)。
从python的attribute查找机制来看,楼主的做法是自己把这个查找机制作了一个非常非常非常简陋而且低效的实现。
http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html.

而且,LZ的代码风格有些问题。在python中,对locals()得回的东西进行update的结果是未定义的和微妙的.这一点和对globals()的操作不同。
http://mail.python.org/pipermail/python-list/2005-October/343950.html
虽然在这个例子里面不会有问题。但是最直接了当的解决办法是对付money只需要
local = { 'money':0 }

而对付那个lambda返回值中eval的参数,直接调用locals().

不明白楼主为啥要用python来做这个事情。个人觉得用汇编之类的会比较说明问题,只有对这类本身没有提供这样一个抽象层次的语言而言,这个做法才有意义(就这个角度而言,javascript是基于对象的,而python是面向对象的)。而对于python这类对象机制既为强悍的语言,再用函数方式来模仿消息传递,实在有点多余。

3 楼 Lich_Ray 2007-06-09  
""Smalltalk里面“调用方法”就叫“传递消息”""
没错啊,我写这篇文章就是想说明“消息”是什么。

PS: 在Python3000中可以用 nonlocal 关键字指定引用上级名字空间中的变量,这样在最后两个例子中就可以不始终用 local['name']了。
2 楼 gigix 2007-06-09  
这个,俗话叫脱了裤子放屁
forest.run.jump.stop

不是一样么?还不用自己做消息分发
说起这个消息,貌似很时髦似的
Smalltalk里面“调用方法”就叫“传递消息”
1 楼 Lich_Ray 2007-06-09  
弄错了,最后两个函数写了各两句 local = locals()。只要保留各自的第二个就行了。

相关推荐

    python二级课后题编程答案

    10. **函数式编程**:使用map()、filter()、reduce()等函数,以及lambda表达式和列表推导式实现函数式编程风格。 每个编程题目都会围绕以上一个或多个知识点进行设计,通过解答这些题目,学生可以巩固理论知识,...

    Python-CNNsRNNsGANs等实现

    在IT领域,特别是机器学习和深度学习中,Python语言凭借其强大的库支持和易读性,成为了首选的编程工具。本资源"Python-CNNsRNNsGANs等实现"聚焦于三种重要的深度学习模型:卷积神经网络(Convolutional Neural ...

    python撩妹

    Python是一种强大的编程语言,不仅在科学计算、数据分析、人工智能等领域有着广泛应用,还能用来做一些创意十足、有趣的事情...所以,不妨尝试用Python来“撩妹”,让编程成为连接感情的桥梁,展现出科技的温情与魅力。

    27篇精选python文章

    这意味着可以将类的实例作为参数传递给其他函数,或用于函数式编程风格。 ### Python学习路径 对于没有编程经验的学习者,建议从基础语法开始,逐步掌握数据结构、控制流、函数和模块等内容,然后再深入到面向对象...

    蓝桥杯青少年创意编程Python组赛前集训教程包,蓝桥杯青少年创意编程python初级考察内容,Python源码.zip

    蓝桥杯提供的源码可以帮助学生了解其他选手的解题思路和编程风格,从而提升自己的编程水平。 综上所述,这个集训教程包涵盖了Python编程的多个方面,包括基础语法、数据结构、控制流、文件操作、函数式编程、面向...

    python bug清除手册-代码书写规范与基本使用.pdf

    根据PEP 8(Python Enhancement Proposal 8)—— Python官方的代码风格指南,建议在赋值操作符`=`的两边各添加一个空格来提高代码的可读性。例如: ```python a = 0 b = input('输入你的问题') ``` 这种写法虽然...

    Python3.6零基础入门与实战-code.rar

    【Python3.6零基础入门与实战】 Python 3.6是Python编程语言的一个重要版本,以其简洁明了的语法和强大的功能深受程序员...记得动手实践,因为编程学习最好的老师就是亲自动手尝试。祝你在Python的世界里探索愉快!

    从零开始的python教程自学方法

    它支持面向对象、函数式和过程式编程风格。Python的标准库非常丰富,提供了大量内置函数和模块,用于各种任务。 二、安装Python环境 首先,你需要下载并安装Python解释器。访问Python官方网站...

    Python 自学20个专题总结

    良好的编程习惯包括避免多余空格,正确判断`None`,合理使用`lambda`表达式,减少受保护代码,保持逻辑完整性,使用意义明确的方法,采用EAFP(尝试-错误-处理)或LBYL(看-再开火)防御编程风格,考虑异常处理,...

    完整图文版教程 优质的Python基础入门教程 讲解清晰 PPT课件 11、Python函数总结 (共36页).rar

    Python支持函数式编程风格,如高阶函数(函数作为参数传递)、map()、filter()、reduce()等,以及列表推导式、生成器等特性。 13. **上下文管理器**: 通过定义`__enter__`和`__exit__`方法,可以创建上下文管理...

    Python-CNNRNN以及深入学习新酷技术的实现

    Python作为目前最流行的编程语言之一,为这些复杂的算法提供了便利的实现框架,如TensorFlow、Keras和PyTorch。 **CNN(卷积神经网络)**是一种专门用于处理具有网格结构数据的神经网络,如图像和声音。CNN的核心...

    google-python-exercises.zip_google_gray1oq_solutions

    **Python编程基础与Google实践教程** 本压缩包“google-python-exercises.zip_google_gray1oq_solutions”包含了一份由Google提供的Python入门教程,旨在帮助初学者掌握Python编程的基础知识。这个教程不仅涵盖了...

    爱心代码合集(html、C语言、Python)

    《爱心代码合集:HTML、C语言与Python的浪漫编程》 爱心,这个象征着温暖与关怀的符号,被巧妙地融入到了编程的世界中。在本"爱心代码合集"中,...这是一次技术与情感的完美碰撞,用代码传递温暖,用编程表达爱意。

    合肥师范学院Python期末考试.docx

    选项B使用了C/C++风格的三目运算符,Python不支持。选项C是Python的条件表达式写法,是正确的。选项D使用了`true`,Python中应使用`True`。 11. **编码解码**:Python的`str`对象可以使用`encode()`方法编码成字节...

    Python库 | ReactiPy-0.0.93.tar.gz

    3. **声明式编程**:ReactiPy鼓励声明式编程风格,开发者只需要描述UI应有的状态,而库会自动处理如何更新UI以反映这些变化。 4. **状态管理**:ReactiPy可能提供了类似于React的state和props机制,用于管理组件的...

    合肥师范学院Python期末考试.pdf

    这些知识点涵盖了Python的基础语法,包括变量命名、数据类型、字符串操作、文件操作、循环结构、函数使用、面向对象编程、错误处理和版本兼容性等方面。掌握这些知识点对于学习和理解Python编程至关重要。

    深入Python函数编程的一些特性

    Python是一种高度支持函数式编程风格的动态类型语言,它允许开发者利用函数作为一等公民,即函数可以作为变量赋值、作为参数传递以及作为返回值。在Python中,函数编程提供了一种强大的抽象层次,使得代码更加模块化...

    python如何写try语句

    Python中的`try`语句是异常处理的关键构造,它允许你在程序中捕获和处理可能出现的错误或异常,从而提高程序的健壮性。...在实际编程中,确保理解每种风格的用途,并根据需要选择合适的异常处理策略。

Global site tag (gtag.js) - Google Analytics