Python 和 Smalltalk - 元编程能力比较
我最近一直在学习Python,对其卓越的运行时元编程能力感到惊讶。之前我在阅读 Smalltalk 时遇到了“运行时元编程”这个术语,据我所知,Smalltalk 拥有最好的运行时元编程功能。 Python 与 Smalltalk 元编程相比有多好?两种语言所采用的方法之间有哪些显着差异?
I have of late been learning Python, and am amazed by its superb runtime metaprogramming capabilities. Previously I came across the term 'runtime metaprogramming' was when I was reading about Smalltalk, which as far as I know boasts of best runtime metaprogramming capabilities. How well does Python stack up against Smalltalk w.r.t. metaprogramming? What are the notable differences between the approaches taken by two languages?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
![扫码二维码加入Web技术交流群](/public/img/jiaqun_03.jpg)
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Python 实际上在这方面表现得相当好。 Smalltalk 通常不会明确区分程序和元程序,但 Python 更加明确 - 例如,装饰器的特殊语法或元编程挂钩的 __foo__() 命名约定。这是一件好事。
另一方面,这有点像苹果与橘子的比较。 Smalltalk 是一种比 Python 更小、更紧凑的语言,因此使用元程序操作的材料更少。例如,考虑
__getattr__()
。这是一个让 Python 对象提供属性访问的自定义实现的钩子。 Smalltalk 没有这样的东西。但! Smalltalk 强制对对象的内部状态进行更紧密的封装,并且没有与 Python 中使用的object.attribute
语法等效的语法。因此读取对象的状态需要通过一个方法...这正是__getattr__()
提供的。因此,对于很多在 Python 中使用 __getattr__() 的情况,您只需在 Smalltalk 中编写一个普通方法 - 不需要元编程。到处都是这样:Python 的 __getitem__() 和朋友使得编写模仿列表或字典的类成为可能。 Smalltalk 不需要它,因为 Array 和 Dictionary 只是常规的 Smalltalk 类,并且没有使用它们的特殊语法。 Python
__eq__()
等启用运算符重载。 Smalltalk 没有运算符,因此您无需执行任何特殊操作即可实现+
。 Python 的 contextlib 提供了一些漂亮的工具来实现您自己的上下文管理器。 Smalltalk 没有with
构造,但它确实有非常轻量级的 lambda 语法,它可以让您以简单的方式做同样的事情。Smalltalk 的元编程工具往往相当低级。例如,您可以创建自己的 CompiledMethod 实例,并将它们粘贴到类的方法字典中。您还可以编写自己的编译器并指定使用它来编译特定类的所有方法。这使得各种各样的事情成为可能——我见过一些项目尝试替代语法、用于分析的仪器字节码、陷阱读取和写入实例变量以实现透明持久性等等。
Smalltalk 的元编程工具很强大,但它们的组织不如 Python 那样整齐,并且使用得不那么频繁。
Python actually holds up fairly well here. Smalltalk usually doesn't make explicit distinction between program and metaprogramm, but Python is more explicit - eg, the special syntax for decorators or the
__foo__()
naming convention for metaprogramming hooks. This is a good thing.On the other hand, it's a bit of an apples-to-oranges comparison. Smalltalk is a smaller, tighter language than Python, and so there's just less material to manipulate with metaprograms. For example, consider
__getattr__()
. This is a hook that lets Python objects provide a custom implementation of attribute access. Smalltalk doesn't have anything like this. But! Smalltalk enforces tighter encapsulation of an object's internal state, and there's no equivalent of theobject.attribute
syntax that's used in Python. So reading an object's state requires going through a method... which is exactly what__getattr__()
provides. So for a lot of cases where you'd use__getattr__()
in Python, you'd just write a normal method in Smalltalk - no metaprogramming needed.And it's like that all over the place: Python's
__getitem__()
and friends make it possible to write classes that mimic lists or dictionaries. Smalltalk doesn't need that because Array and Dictionary are just regular Smalltalk classes and there's no special syntax for using them. Python__eq__()
and so on enable operator overloading. Smalltalk doesn't have operators, so you can implement+
without doing anything special. Python's contextlib provides some nifty tools for implementing your own context managers. Smalltalk doesn't have awith
construct, but it does have really lightweight syntax for lambdas, which lets you do the same sort of thing in a straightforward way.Smalltalk's metaprogramming facilities tend to be pretty low-level. You can, for example, create your own
CompiledMethod
instances, and stick them into a class's method dictionary. You can also write your own compiler and specify that all the methods of a particular class be compiled with it. That enables all sorts of things - I've seen projects that experiment with alternate syntaxes, instrument bytecode for profiling, trap reads and writes to instance variables for transparent persistence, and so on.Smalltalk's metaprogramming facilities are powerful, but they're not as neatly organized as Python's, and don't get used as often.
应提问者的要求发布为答案。
Smalltalk 的重要思想之一是正交性。坦率地说,Python 在这方面受到了影响。并非一切都适用于一切。示例:
eval
仅适用于表达式字符串,exec
仅适用于语句字符串。myclass = type('x', (object,), {'__init__':partial(foo, value)})
生成一个无法实例化的类,同时传递一个等效的lambda
表达式代替partial
可以正常工作。 (虽然这可能只是一个错误而不是一个功能。)也许 PyPy 没有这些问题,我不确定。但我确实非常喜欢Python,并且发现在实际应用程序中使用元类、柯里化和偶尔的描述符非常方便。
Posted as an answer at questioner's request.
One of the big ideas of Smalltalk is orthogonality. Frankly Python suffers in this respect. Not everything works on everything. Examples:
inspect.getargspec()
does not work on built-in functions or the results of calls tofunctools.partial
(in the C interpreter anyway).eval
only works for expression strings, andexec
only works for statement strings.myclass = type('x', (object,), {'__init__': partial(foo, value)})
produces a class that can't be instantiated, whereas passing an equivalentlambda
expression instead of apartial
works fine. (Though this may just be a bug not a feature.)Maybe PyPy doesn't have these problems, I'm not sure. But I do love Python very much and find it very convenient to use metaclasses, currying and the occasional descriptor in real applications.