Mik*_*e A 14 python design-patterns factory metaprogramming metaclass
我最近在python中发现了元类.
基本上python中的元类是一个创建类的类.有许多有用的理由可以解释为什么要这样做 - 例如任何类的初始化.在工厂上注册类,复杂的属性验证,改变继承的工作方式等等.所有这些不仅可能而且简单.
但在python中,元类也是普通类.所以,我开始想知道抽象是否可以有效地走高,而且在我看来它可以和那样:
我在网上找到了一些关于这个的东西,但大多数都不是很有用.一个问题是不同的语言稍微不同地定义了元类.
有没有其他人在python /其他地方使用过像这样的元类,或者看到过在野外使用过的,还是想过它?其他语言有哪些类似物?例如,在C++中,模板递归有多深?
我非常想进一步研究它.
回答你的问题:没有.
随意进一步研究.
但请注意,您已将设计模式(仅仅是想法)与代码(这是一种实现)混为一谈.
好的代码通常反映了许多互锁的设计模式.没有简单的方法来形式化这个.你能做的最好的是一张漂亮的图片,精心编写的文档字符串以及反映各种设计模式的方法名称.
另请注意,元类是一个类.那是一个循环.没有更高级别的抽象.那时,这只是意图.元元类的概念并不重要 - 它是元类的元类,这在技术上是可能的愚蠢.然而,这只是一个班级.
编辑
"创建元类的类真的太傻了吗?它们的实用程序突然耗尽了吗?"
创建类的类很好.这就是它.目标类是元类或抽象超类或具体类的事实并不重要.元类会上课.他们可能制作其他元类,这很奇怪,但它们仍然只是制作类的元类.
实用程序"突然"耗尽,因为在创建另一个元类的元类中没有您需要(或甚至可以写)的实际内容.并不是说它"突然"变得愚蠢.这就是那里没什么用处.
随着我的种子,随意研究它.例如,实际上编写一个构建另一个元类的元类.玩得开心.那里可能有一些有用的东西.
OO的要点是编写模拟现实世界实体的类定义.因此,元类有时很方便定义几个相关类的交叉方面.(这是一种做面向方面编程的方法.)这就是所有元类都可以做到的; 它是一个容纳一些函数的地方,比如__new__()
,它们不是类本身的适当部分.
在2007年的编程语言历史会议期间,Simon Peyton Jones评论说Haskell允许使用类型类进行元编程,但它真正的乌龟一直在下降.你可以在Haskell中使用meta-meta-meta-meta等程序,但他从来没有听说过任何人使用超过3级的间接.
Guy Steele在Lisp和Scheme中指出了它的相同之处.你可以使用反引号和evals进行元编程(你可以把它想象为一个Python lambda,有点),但是他从未见过超过3个反引号.
据推测,他们已经看到了比你或我曾经拥有的代码更多的代码,所以毫不夸张地说没有人超过3级元.
如果你考虑一下,大多数人都不会使用元编程,而且很难将两个层次包围起来.我猜这三个几乎是不可能的,那个最后一个尝试四个的人最终得到了一个避难所.
自从我第一次理解 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)
Smalltalk 中的类系统是一个值得研究的有趣系统。在 Smalltalk 中,一切都是对象,每个对象都有一个类。这并不意味着层次结构会无穷无尽。如果我没记错的话,大概是这样的:
5 -> 整数 -> 整数类 -> 元类 -> 元类 -> 元类 -> ... (循环)
其中“->”表示“是……的实例”。