2011-07-27 30 views
10

我最近一直在学习Python,并且对它出色的运行时元编程功能感到惊叹。之前我遇到过'运行时元编程'这个词,当时我正在阅读有关Smalltalk的内容,据我所知,它拥有最佳的运行时元编程功能。 Python与Smalltalk w.r.t堆积得如何?元编程?两种语言采取的方法之间有什么显着差异?Python和Smalltalk - 元编程能力比较

+0

在Python中,类型和可调用都是一流的,而且它的合理组合他们,甚至在运行时创建它们。任何比这更神奇的东西通常被认为是un *“pythonic”*。我们不喜欢在python中创建DSL,我们只是使用python。 – SingleNegationElimination

+0

@TokenMacGuy:谢谢你的回应!我的问题不在于元编程是否是Pythonic,或者是否应该这样做。这是关于两种语言的元编程能力比较研究的普通学术问题。 – missingfaktor

+3

Smalltalk的一个重要思想是正交性。坦率地说Python在这方面受到了影响。并非所有的东西都可以运作例子:inspect.getargspec()在内置函数上不起作用(无论如何都在C解释器中)。 eval仅适用于表达式字符串,而exec仅适用于语句字符串。 Lambda表达式不能被腌制。也许PyPy没有这些问题,我不确定。但是我非常喜欢Python,并且发现在实际应用中使用元类,currying和偶尔的描述符非常方便。 – wberry

回答

12

Python在这里实际上保持得相当好。 Smalltalk通常不会明确区分程序和元编程,但Python更加明确 - 例如,装饰器的特殊语法或元编程钩子的命名约定。这是一件好事。

另一方面,这是一个苹果对桔子的比较。 Smalltalk是一种比Python更小,更紧密的语言,所以用元程序操作的材料更少。例如,考虑__getattr__()。这是一个让Python对象提供属性访问的自定义实现的钩子。 Smalltalk没有这样的东西。但! Smalltalk强制对一个对象的内部状态进行更严格的封装,并且没有相当于Python中使用的语法。因此,读取对象的状态需要通过一种方法......这正是__getattr__()提供的。因此,在Python中使用__getattr__()的很多情况下,您只需在Smalltalk中编写一个常规方法 - 不需要元编程。

它就像遍布整个地方:Python的__getitem__()和朋友可以编写模仿列表或字典的类。 Smalltalk并不需要这样做,因为Array和Dictionary只是普通的Smalltalk类,并没有特别的语法来使用它们。 Python __eq__()等使运算符重载。 Smalltalk没有运营商,所以你可以实现+而不做任何特殊的事情。 Python的contextlib提供了一些用于实现自己的上下文管理器的漂亮工具。 Smalltalk没有with构造,但它对lambda表达式确实有非常轻量级的语法,它可以让你以直接的方式完成同样的事情。

Smalltalk的元程序设施往往是相当低级的。例如,您可以创建自己的CompiledMethod实例,并将其粘贴到类的方法字典中。您也可以编写自己的编译器,并指定使用它编译特定类的所有方法。这使得各种各样的东西 - 我见过的项目尝试了替代语法,用于分析的工具字节码,用于透明持久性的实例变量的陷阱读取和写入,等等。

Smalltalk的元编程功能非常强大,但它们并不像Python那样整洁,而且不经常使用。

10

作为回答提问者的要求发布。

Smalltalk的一个重要思想是正交性。坦率地说Python在这方面受到了影响。并非所有的东西都可以运作例子:

  • inspect.getargspec()没有(反正在C解释器)工作在内置功能或调用的结果functools.partial
  • eval仅适用于表达式字符串,而exec仅适用于语句字符串。
  • Lambda表达式不能被腌制。
  • myclass = type('x', (object,), {'__init__': partial(foo, value)})产生不能被实例化的一类,而传递一个等效lambda表达,而不是一个partial工作正常。 (虽然这可能只是一个bug而不是功能)

也许PyPy没有这些问题,我不确定。但是我非常喜欢Python,并且发现在实际应用中使用元类,currying和偶尔的描述符非常方便。

+1

PyPy中的C和Python函数之间的许多差异确实被删除了(您无法通过行为真正区分它们)。酸洗限制逗留(只是因为酸洗是疯狂) – fijal

+0

@fijal:有什么疯狂的约酸洗? – missingfaktor

+1

酸洗依赖于全局状态通过名称引用所有的函数和类。有关示例,请参阅NamedTuple疯狂的sys._getframe hacks来解决它。你不能在全局命名空间中引用lambda的名称,因此你不能腌制它们(这是它的设计原理,它在PyPy中的工作方式相同) – fijal