【问题标题】:Python and Smalltalk - Metaprogramming capabilities comparisonPython 和 Smalltalk - 元编程能力比较
【发布时间】:2011-07-27 22:52:16
【问题描述】:

我最近一直在学习 Python,并对其卓越的运行时元编程能力感到惊讶。以前,我在阅读有关 Smalltalk 的文章时遇到了“运行时元编程”一词,据我所知,它拥有最好的运行时元编程功能。 Python 与 Smalltalk w.r.t 的对比效果如何?元编程?两种语言采用的方法之间有哪些显着差异?

【问题讨论】:

  • 在python中,类型和可调用对象是第一类,组合它们,甚至在运行时创建它们是合理的。任何比这更神奇的东西通常被认为是 un"pythonic"。我们不喜欢在 python 中创建 DSL,我们只是使用 python。
  • @TokenMacGuy:感谢您的回复!我的问题不是关于元编程是否是 Pythonic,或者是否应该这样做。这是一个关于两种语言元编程能力比较研究的简单学术问题。
  • Smalltalk 的一大理念是正交性。坦率地说,Python 在这方面受到了影响。并非一切都适用于一切。示例:inspect.getargspec() 不适用于内置函数(无论如何在 C 解释器中)。 eval 仅适用于表达式字符串,而 exec 仅适用于语句字符串。无法腌制 Lambda 表达式。也许PyPy没有这些问题,我不确定。但我确实非常喜欢 Python,并且发现在实际应用程序中使用元类、柯里化和偶尔使用的描述符非常方便。
  • 感谢@wberry 的回复。您可以将其发布为答案。

标签: python oop programming-languages metaprogramming smalltalk


【解决方案1】:

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 的那么整齐,而且使用频率也不高。

【讨论】:

    【解决方案2】:

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

    Smalltalk 的一大理念是正交性。坦率地说,Python 在这方面受到了影响。并非一切都适用于一切。例子:

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

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

    【讨论】:

    • 在 PyPy 中确实消除了 C 和 Python 函数之间的许多差异(您无法通过行为真正区分它们)。酸洗限制保留(只是因为酸洗太疯狂了)
    • @fijal: 酸洗有什么疯狂的?
    • Pickling 依赖于按名称引用所有函数和类的全局状态。请参阅 NamedTuple crazy sys._getframe hacks 以解决它的示例。您不能在全局命名空间中按名称引用 lambda,因此您不能腌制它们(这就是它的设计方式,它在 PyPy 中的工作方式相同)
    • 所以酸洗并不是真正的疯狂,它更像是一个谎言?如果你在同名指代不同事物的虚拟机中解压,解压可以(取决于)仍然“工作”,但你得到的对象与你放入的对象不同?
    猜你喜欢
    • 2014-08-08
    • 1970-01-01
    • 1970-01-01
    • 2018-06-17
    • 1970-01-01
    • 2017-10-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-28
    相关资源
    最近更新 更多