是否有人在Python /其他语言中使用元元类/元元元类?

时间:2009-01-24 20:10:48

标签: python metaprogramming design-patterns factory metaclass

我最近在python中发现了元类。

基本上python中的元类是一个创建类的类。有许多有用的理由可以解释为什么要这样做 - 例如任何类的初始化。在工厂注册类,复杂的属性验证,改变继承的工作方式等等。所有这一切不仅可能而且简单。

但是在python中,元类也是普通类。所以,我开始想知道抽象是否可以有效地走高,在我看来它可以和那个:

  • 元类对应于或实现模式中的角色(如GOF模式语言中)。
  • 元元类是模式本身(如果我们允许它创建表示抽象角色的类的元组,而不仅仅是单个类)
  • meta-meta-metaclass是模式工厂,它对应于GOF模式分组,例如创造性,结构性,行为性。一个工厂,你可以描述一个特定类型问题的案例,它会给你一组解决它的类。
  • 一个meta-meta-meta-metaclass(据我所知),是一个模式工厂,你可以描述你的问题类型的工厂,它会给你你是一个模型工厂要问。

我在网上找到了一些这方面的内容,但大多数都不是很有用。一个问题是不同的语言对元类的定义略有不同。

有没有其他人在python /其他地方使用过像这样的元类,或者看过这个在野外使用过,还是想过它?其他语言有哪些类似物?例如。在C ++中,模板递归有多深?

我非常想进一步研究它。

5 个答案:

答案 0 :(得分:18)

这让我想起了一些人似乎在做出“模式的通用实现”的永恒追求。就像一个可以创建任何对象(including another factory)的工厂,或者一个通用的依赖注入框架,它比管理实际上的代码要复杂得多。

当我管理Zend Framework项目时,我不得不处理那些意图抽象的人,直到注视肚脐。我拒绝了一堆建议来创建没有做任何事情的组件,它们只是GoF模式的神奇实现,就好像模式本身就是一个目标,而不是达到目标的手段。

抽象的回报有所减少。一些抽象很棒,但最终你需要编写一些有用的代码。

否则只是turtles all the way down

答案 1 :(得分:7)

回答你的问题:不。

随意进一步研究。

但请注意,您已将设计模式(仅仅是想法)与代码(这是一种实现)混为一谈。

良好的代码通常反映了许多互锁的设计模式。没有简单的方法来形式化这个。您可以做的最好的是精美的图片,精心编写的文档字符串以及反映各种设计模式的方法名称。

另请注意,元类是一个类。那是一个循环。没有更高级别的抽象。那时,这只是意图。元元类的概念并不重要 - 它是元类的元类,这在技术上是可能的愚蠢。然而,这只是一个课程。


修改

“创建元类的类真的如此愚蠢吗?它们的实用程序突然耗尽了吗?”

创建类的类很好。这就是它。目标类是元类或抽象超类或具体类的事实并不重要。元类会上课。他们可能制作其他元类,这很奇怪,但它们仍然只是制作类的元类。

实用程序“突然”耗尽,因为在创建另一个元类的元类中没有您需要(或甚至可以写)的实际内容。并不是说它“突然”变得愚蠢。这就是那里没什么用处。

当我播种时,随意研究它。例如,实际上编写一个构建另一个元类的元类。玩得开心。可能会有一些有用的东西。

OO的目的是编写模拟现实世界实体的类定义。因此,元类有时很方便定义几个相关类的交叉方面。 (这是一种做面向方面编程的方法。)这就是所有元类都可以做到的;它是一个容纳一些函数的地方,比如__new__(),它们不是类本身的适当部分。

答案 2 :(得分:7)

在2007年的编程语言历史会议期间,Simon Peyton Jones评论说Haskell允许使用Type Classes进行元编程,但它真的是乌龟一直在下来。你可以在Haskell中使用meta-meta-meta-meta等程序,但他从来没有听说过任何人使用超过3级的间接。

Guy Steele在Lisp和Scheme中指出了它的相同之处。你可以使用反引号和evals进行元编程(你可以把它想象为一个Python lambda,有点),但他从未见过使用过3个反引号。

据推测,他们看到的代码比你或我曾经有过的代码更多,所以毫不夸张地说没有人超过3级元素。

如果你考虑一下,大多数人都不会使用元编程,而且很难将两个层面包围起来。我猜这三个几乎是不可能的,最后一个尝试四个的人最后都进入了一个避难所。

答案 3 :(得分:4)

Smalltalk中的类系统是一个值得研究的有趣系统。在Smalltalk中,一切都是一个对象,每个对象都有一个类。这并不意味着层次结构变为无穷大。如果我没记错的话,那就像是:

5 - >整数 - >整数类 - >元类 - >元类 - >元类 - > ......(它循环)

其中' - >'表示“是”的实例。

答案 4 :(得分:2)

从我第一次理解Python中的元类时,我一直想知道"元元类可以做些什么?"。这是至少10年前 - 现在,就在几个月前,我很清楚Python类创建中有一种机制实际上涉及一个" meta-meta"类。因此,可以尝试设想一些用途。

重新概述Python中的对象实例化:每当用Python实例化一个对象时,通过"调用"它的类具有相同的语法,用于调用普通函数,类__new____init__。什么" orchestrates"在课堂上调用这些方法恰好是班级的元类' __call__方法。通常,当用Python编写元类时,可以自定义元类的__new____init__方法。

所以,事实证明,通过写一个" meta-meta"第一类可以自定义其__call__方法,从而控制传递哪些参数以及元类的__new____init__方法,以及是否要调用其他代码在那之后。最终结果是,metcalsses本身通常是硬编码的,即使在非常大的项目中,也只需要一些(如果有的话)。所以可以在" meta meta"调用通常直接在元类本身上完成。

而且,对于Python元类,还有其他不经常使用的方法 - 可以在元类中自定义__add__方法,以便它们定义的类是"可添加",并创建派生类将两个添加的类作为超类的类。这种机制对于元类也是完全有效的 - 因此,我们只需要一些实际的代码",遵循" meta-meta"允许一个人组成"元类"对于一个类,只需在类声明中添加它们:

class MM(type):
    def __add__(cls, other):
        metacls = cls.__class__
        return metacls(cls.__name__ + other.__name__, (cls, other), {})

class M1(type, metaclass=MM):
    def __new__(metacls, name, bases, namespace):
        namespace["M1"] = "here"
        print("At M1 creation")
        return super().__new__(metacls, name, bases, namespace)

class M2(type, metaclass=MM):
    def __new__(metacls, name, bases, namespace):
        namespace["M2"] = "there"
        print("At M2 creation")
        return super().__new__(metacls, name, bases, namespace)

我们可以看到在交互式控制台上工作:

In [22]: class Base(metaclass = M1 + M2): 
    ...:     pass
    ...: 
At M1 creation
At M2 creation

请注意,由于Python中的不同元类通常难以组合,因此通过允许将用户自定义元类与库或stdlib组合,实际上这可能非常有用,而不必显式声明作为前者的父母:

In [23]: import abc

In [24]: class Combined(metaclass=M1 + abc.ABCMeta):
    ...:     pass
    ...: 
At M1 creation