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

Mik*_*e A 14 python design-patterns factory metaprogramming metaclass

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

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

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

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

我在网上找到了一些关于这个的东西,但大多数都不是很有用.一个问题是不同的语言稍微不同地定义了元类.

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

我非常想进一步研究它.

Bil*_*win 18

这让我想起了一些人似乎在做出"模式的通用实现"的永恒追求.就像一个可以创建任何对象(包括另一个工厂)的工厂,或者一个通用的依赖注入框架,它比简单地编写实际执行某些操作的代码要复杂得多.

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

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

否则它只是乌龟一路下来.


S.L*_*ott 7

回答你的问题:没有.

随意进一步研究.

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

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

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


编辑

"创建元类的类真的太傻了吗?它们的实用程序突然耗尽了吗?"

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

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

随着我的种子,随意研究它.例如,实际上编写一个构建另一个元类的元类.玩得开心.那里可能有一些有用的东西.

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


Pau*_*gar 7

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

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

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

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


jsb*_*eno 6

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

回顾 Python 中的对象实例化:每当在 Python 中通过使用与调用普通函数相同的语法“调用”它的类来实例化一个对象时,类的__new____init__. 在类上“编排”这些方法的调用正是类的“元类”__call__方法。通常在 Python 中编写元类时,会自定义元类的__new____init__方法。

因此,事实证明,通过编写“元元”类,可以自定义其__call__方法,从而控制传递哪些参数以及传递给元类__new____init__方法的参数,以及是否要在这些参数之前或之后调用其他代码。最终结果是,metcalsses 本身通常是硬编码的,即使在非常大的项目中,也只需要几个,如果有的话。因此,可能在“元元”调用中完成的任何定制通常直接在元类本身上完成。

而它们,还有 Python 元类的其他一些不太常见的用途——可以__add__在元类中自定义一个方法,以便它们定义的类是“可添加的”,并创建一个派生类,将两个添加的类作为超类。该机制对于元类也完全有效 - 因此,因此,只要我们“有一些实际代码”,就可以遵循“元元”类的示例,该类允许人们通过将它们添加到类声明中来为类组合“元类” :

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)
Run Code Online (Sandbox Code Playgroud)

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

In [22]: class Base(metaclass = M1 + M2): 
    ...:     pass
    ...: 
At M1 creation
At M2 creation
Run Code Online (Sandbox Code Playgroud)

请注意,由于 Python 中的不同元类通常难以组合,这实际上是有用的,允许将用户创建的元类与库或 stdlib 的元类组合,而不必将此元类显式声明为前者的父类:

In [23]: import abc

In [24]: class Combined(metaclass=M1 + abc.ABCMeta):
    ...:     pass
    ...: 
At M1 creation
Run Code Online (Sandbox Code Playgroud)


Raf*_*ird 4

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

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

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