Smalltalk(例如Pharo)与Python相比如何?

7
我看到了一些关于Smalltalk和Ruby以及Ruby和Python之间的比较,但是没有关于Python和Smalltalk之间的比较。我特别想知道它们在实现、语法、可扩展性和哲学方面的根本区别。
例如,Python似乎没有元类(Metaclasses)。Smalltalk没有生成器(generators)的概念。虽然它们都被称为动态类型语言,但我认为Python不执行动态方法分派。这是正确的吗?

2
我特别想知道实现、语法、可扩展性和哲学方面的根本差异是什么。那基本上就是全部了。所以回答这个问题的唯一方法就是教你两种语言。 :-) - Lennart Regebro
5个回答

9
例如,Python似乎没有元类。
实际上,Python是有元类的,只是它不会为每个类隐式地生成一个新的元类:它使用父类相同的元类,或者默认使用type。 Python的设计哲学(即“Python之禅”)可以通过在交互式解释器的提示符下执行import this来查看;这里适用的点是第二点,“显式优于隐式”。
在Python 2.X中,您可以使用以下语法指定自定义元类:
class sic:
  __metaclass__ = mymeta
  ...

在Python 3.X中,更为优雅的方式是使用命名参数语法:
class sify(metaclass=mymeta):
  ...

Smalltalk没有生成器的概念。

Python的生成器是一等公民(通常是独立的)函数,而Smalltalk没有“独立”的函数概念——它有类内的方法。但是它当然有迭代器——作为类存在:

iterator := aCollection iterator.
[iterator hasNext] whileTrue: [iterator next doSomething]. 

由于Smalltalk拥有一流的"代码块"(Ruby从中借鉴了这一点),因此您可以通过向适当的方法发送代码块来实现迭代,就像其他"控制结构"一样,并且如果您希望,可以直接使用集合进行操作(例如select:):

aCollection select: [:item | item doSomething].

在Smalltalk(和Ruby)中,您将代码块发送到迭代;而Python则相反,迭代会向周围的“调用”代码发送值。看起来非常不同,但最终并没有“深层次”的区别。

一级代码块意味着Smalltalk不需要也没有“控制结构”语句和关键字,例如ifwhile:可以通过将代码块作为适当方法的参数(例如布尔值的ifTrue:方法)来完成它们。(Ruby选择在一级代码块之外拥有关键字/语句,我会说,Python [[明确]]和Smalltalk [[隐式]]都像C一样尝试“提供执行操作的单一方法”,而Ruby更多地是Perl-ish学派的“有很多种方法可以做到这一点”)。

虽然两者都被认为是动态类型,但我认为Python不执行动态方法分派。这正确吗?

不,完全不正确- Python 极度执行动态方法分派,到了极致。例如考虑:

for i in range(10):
  myobject.bah()

按照Python语义,这将在myobject中进行10次查找以获取方法bah。这是为了防止先前执行的方法导致myobject在内部完全重构,以至于其当前的bah方法与先前的方法完全不同(对于程序员来说,依赖如此激烈的动态性可能是一件相当疯狂的事情,但Python支持它)。这就是使得:
themethod = myobject.bah
for i in range(10):
  themethod()

Python代码中的一种常见手动优化——在循环之前进行一次动态查找,而不是在循环内部进行10次查找,每个循环一次(这是“常量提升”的情况,因为编译器受到Python极端规则的限制,不能自行执行“常量折叠”操作——除非它能够证明是无害的,在实践中这样的证明过于困难,所以Python实现通常不会费心去做)。

Python使用统一的命名空间:方法是对象的属性,就像任何其他属性一样,只是它们是可调用的。这就是为什么提取方法而不调用它(称为“绑定方法”),将引用设置为变量(或将其存储在列表或其他容器中,从函数返回它,等等)就像上面的常量提升示例一样,是一个简单明了的操作。

Smalltalk和Ruby有独立的方法和其他属性命名空间(在Smalltalk中,非方法属性在对象自己的方法外部不可见),因此“提取方法”和“调用结果对象”需要更多的内省仪式(但在某些情况下,特别是在调度的常见情况下,可能使得调度略微简单——特别是,“仅提及”一个无参数方法隐式调用它,而在Python中,就像在C中一样,调用是通过追加括号显式执行的,而“仅提及”则使其可用于任何类型的显式操作,包括调用;-)。


7

Python确实有元类。

Smalltalk具有一些不寻常的特点:

  • 其语法相当简单,只有大约6个关键字。除了调用方法(在Smalltalk中发送消息),其他所有内容(包括定义新类)都可以完成。这使您可以在语言内创建某些DSL。
  • 在Smalltalk中,您不需要存储源文件,而是有一个大型的内存镜像,并且可以随时修改它。您还可以修改大多数Smalltalk本身(并可能破坏它;)

2
Smalltalk没有生成器的概念。
虽然如此,但是在大多数 Smalltalk 方言中,它们可以从语言内部实现。GNU Smalltalk 自带生成器作为其流库stream library的一部分。

2
我一直在阅读《程序员的职业生涯》,这是一本充满了顶尖程序员采访的好书。其中之一是Smalltalk的发明者,他详细谈到了他的语言以及它与Python的关系(他也非常喜欢Python)。他唯一对Python不满意的地方就是它的代码运行速度较慢...他真的希望能够将Smalltalk JIT编译器作为Python的后端,但不幸的是,由于他所工作的公司拥有该软件,这是不可能的。

总之...也许不是逐点比较,但这本书真的很值得一读。


1
根据维基百科关于动态方法调度的页面:

Smalltalk实现

Smalltalk使用基于类型的消息分发器。每个实例都有一个单一的类型,其定义包含方法。当实例接收到消息时,分发器会在类型的消息到方法映射中查找相应的方法,然后调用该方法。[...]

许多其他动态类型的语言,包括Python、Ruby、Objective-C和Groovy使用类似的方法。

强调部分已添加,并省略了一个段落。因此,至少在这方面两种语言是相似的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接