什么是"向对象发送消息的好例子"在Python内?

时间:2015-11-04 23:47:41

标签: python ruby oop smalltalk

我最近看过Sandi Metz的Nothing is Something,在她的演讲中,她使用了向对象发送消息的想法,并讨论了如何在Ruby中完成这些操作。 4:10 - 7:30部分将是一个很好的切入点,她开始讨论这个话题(它是一个构建块,然后渗透到谈话的一半以上)。

现在,在某些背景下:我在使用Ruby编写程序方面没有很多经验,而且没有使用smalltalk的经验。我的OO体验有限,非常陈旧。我也在谷歌查询了send object message python,我所看到的只是通过套接字和电子邮件发送消息,这与我的想法并不相同。

我不确定如何在Python中解释这个概念,或者如何实现它。任何想法? :)

旁注:她提到她的OO视图来源于smalltalk的经验,因此我将其添加为此问题的标记。

4 个答案:

答案 0 :(得分:10)

Python使用略有不同的术语。它被称为"调用方法"。但它是一回事。 (C ++称之为"调用虚函数"。再次,相同的区别。)

就个人而言,我不喜欢这个术语,它过分关注实现细节,并且失去了"消息发送的大部分隐喻力量。术语

与Python存在其他差异,其中一些最重要的是:

  • 面向对象的数据抽象是通过约定实现的,而不是内置语言特性(例如Smalltalk,Ruby)或设计模式(Scheme,ECMAScript)
  • 并非所有子程序都是方法

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。没有单独的&#34;方法&#34;的概念,相反,你有把接收器作为第一个参数的函数。 (在大多数其他OO语言中,接收器是&#34;隐藏&#34;第0个参数,可使用特殊关键字,例如selfthisme。< / 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教你在编程。此外,还有一个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认为,消息传递而不是继承是所谓的面向对象编程的重要方面。