我最近看过Sandi Metz的Nothing is Something,在她的演讲中,她使用了向对象发送消息的想法,并讨论了如何在Ruby中完成这些操作。 4:10 - 7:30部分将是一个很好的切入点,她开始讨论这个话题(它是一个构建块,然后渗透到谈话的一半以上)。
现在,在某些背景下:我在使用Ruby编写程序方面没有很多经验,而且没有使用smalltalk的经验。我的OO体验有限,非常陈旧。我也在谷歌查询了send object message python
,我所看到的只是通过套接字和电子邮件发送消息,这与我的想法并不相同。
我不确定如何在Python中解释这个概念,或者如何实现它。任何想法? :)
旁注:她提到她的OO视图来源于smalltalk的经验,因此我将其添加为此问题的标记。
答案 0 :(得分:10)
Python使用略有不同的术语。它被称为"调用方法"。但它是一回事。 (C ++称之为"调用虚函数"。再次,相同的区别。)
就个人而言,我不喜欢这个术语,它过分关注实现细节,并且失去了"消息发送的大部分隐喻力量。术语
与Python存在其他差异,其中一些最重要的是:
OO的基本思想是消息传递:您向对象发送消息,对象响应。就像在现实生活中一样,你不知道对象对消息的作用。所有你能观察到的是答复。对象可能会处理消息本身,它可能会使用其他人的帮助,它可能会盲目地转发消息,而不会实际执行任何工作。
由于您无法知道对象对消息的作用,您可以观察到的是对象的响应,您对该对象的所有了解都是其协议(它理解的消息以及它如何响应它们。你不知道它的实现,你不知道它的代表性。这就是OO如何实现数据抽象,信息隐藏,数据隐藏,封装。
此外,由于每个对象独立决定如何响应消息,因此您将获得多态性。
一种响应消息的典型方式是执行与该消息对应的方法。但这是一种实施机制,这就是我不喜欢这个术语的原因。作为一个比喻,它没有我上面提到的任何内涵。
Alan Kay has said that OO is about three things, Messaging, Data Abstraction, and Polymorphism:
对我来说,OOP意味着只有消息传递,本地保留和保护以及隐藏状态进程,以及所有事物的极端后期绑定。
他后来澄清了the Big Thing is Messaging:
只是温和地提醒我,我在最后的OOPSLA上花了一些力气试图提醒大家Smalltalk不仅不是它的语法或类库,它甚至不是关于类。对不起,我很久以前就创造了这个术语"对象"对于这个主题,因为它让很多人专注于较少的想法。
最大的想法是"消息传递" - 这就是Smalltalk / Squeak的核心所在(这是我们的Xerox PARC阶段从未完成的事情)。日本人有一个小词 - 马 - 用于"它介于"之间。 - 也许最近的英语等价物是" interstitial"。制作出色的可扩展系统的关键在于设计其模块的通信方式,而不是其内部属性和行为应该是什么。想想互联网 - 生活,它(a)必须允许超出任何单一标准的许多不同类型的想法和实现,以及(b)允许这些想法之间的不同程度的安全互操作性。
事实上,正如我上面提到的,在我看来,另外两个只是消息的后果。
当Alan Kay提出术语"面向对象"时,他受到后来成为ARPANet然后互联网的激励:独立机器("对象")他们自己的私人记忆("实例变量")通过发送消息相互通信。
On Understanding Data Abstraction, Revisited以及William R. Cook Proposal for Simplified, Modern Definitions of "Object" and "Object Oriented"也提出了类似的观点。
动态调度操作是对象的基本特征。这意味着要调用的操作是对象本身的动态属性。无法静态识别操作,并且除了通过运行它之外,通常无法准确地执行响应给定请求的操作。这与第一类函数完全相同,它们总是动态调度。
Python的对象系统与其他语言略有不同。 Python最初是一种过程语言,稍后会添加对象系统,其目标是尽可能减少对语言的绝对更改。 Python中的主要数据结构是dict
s(映射/散列表),所有行为都在函数中。甚至在Python的OO功能之前,这种极简主义就表现出来,例如局部变量和全局变量实际上只是dict
中的键。因此,很自然地使对象和类与dict
s非常相似并重用该概念,对象本质上是dict
的值,而类是函数的dict
。没有单独的"方法"的概念,相反,你有把接收器作为第一个参数的函数。 (在大多数其他OO语言中,接收器是"隐藏"第0个参数,可使用特殊关键字,例如self
,this
或me
。< / p>
答案 1 :(得分:7)
基本上&#34;发送消息&#34;在大多数OO语言中称为调用方法。关键的区别在于,在动态语言中,您不知道对象是否知道方法。因此,如果您执行var.jump()
,则不知道var
是什么。也许它是一只兔子它可以跳跃,或者它可能是一块石头而且它不知道该怎么做(Rock类没有实现jump()
方法)。因此,从概念的角度来看,发送消息是要求某个对象做某事(也许它不知道你在问什么),而调用一个方法就是让你知道的那个对象做你想做的事。
在Smalltalk和Ruby中,使用其他消息发送消息非常容易,因此如果您使用1.send(:to_s)
,则与1.to_s
相同。 1.send(:to_s)
本身就是一条消息send
,使用参数1
发送给:to_s
。所以你也可以把它花在1.send(:send, :to_s)
上。
在Python中,元编程是一个真正的痛苦。因此,如果你想做同样的1.send(:to_s)
,你必须使用像getattr(1,&#34; to_s&#34;)()这样的东西。在这里,您获得了to_s
&#34;方法&#34;本身使用getattr
并使用()
调用它。 这也是糟糕的Python设计的一个很好的例子。你如何在Python中做1.send(:send, :to_s)
之类的事情?在Ruby send
中是代码对象的方法。所以你也可以通过自己发送它。在Python中,getattr是一个外部独立函数。
如果您真的想学习OO编程的概念,我建议您使用Smalltalk,因为我发现它具有最佳设计。 (它也不受C ++或其他东西的影响,因为在70年代他们不在身边)。有一本很好的书Pharo by Example教你在pharo编程。此外,还有一个work in progress version更新了新版本的环境。
答案 2 :(得分:2)
核心理念称为Message passing。
在python中,您通常使用标准符号发送消息:
obj.methodname(args)
如果方法名称是动态的,您可以这样做:
getattr(obj, methodname)(args)
示例:
>>> getattr(" 12", "strip")()
'12'
即使我们通常使用标准符号,但在幕后还有一个请求属性,您可以通过拦截该调用来观察:
class Test(object):
def __getattribute__(self, name):
print "requesting attr:", name
return object.__getattribute__(self, name)
def test(self):
print "Hello"
>>> Test().test()
requesting attr: test
Hello
答案 3 :(得分:1)
在20世纪70年代早期开始在Smalltalk中发送“发送消息”的内容,现在通常被称为“calling a method
”
发送消息正在向对象发出礼貌请求以进行响应。如果它理解收到的信息,它将礼貌地回应,并有一个回应的方法。即如果邮件位于protocol
的{{1}}。
协议是它具有响应方法的消息列表。如今,我们将协议称为接收者的receiver
。
Smalltalk的父亲Alan Kay认为,消息传递而不是继承是所谓的面向对象编程的重要方面。