我最近在python中发现了元类。
基本上python中的元类是一个创建类的类。有许多有用的理由可以解释为什么要这样做 - 例如任何类的初始化。在工厂注册类,复杂的属性验证,改变继承的工作方式等等。所有这一切不仅可能而且简单。
但是在python中,元类也是普通类。所以,我开始想知道抽象是否可以有效地走高,在我看来它可以和那个:
我在网上找到了一些这方面的内容,但大多数都不是很有用。一个问题是不同的语言对元类的定义略有不同。
有没有其他人在python /其他地方使用过像这样的元类,或者看过这个在野外使用过,还是想过它?其他语言有哪些类似物?例如。在C ++中,模板递归有多深?
我非常想进一步研究它。
答案 0 :(得分:18)
这让我想起了一些人似乎在做出“模式的通用实现”的永恒追求。就像一个可以创建任何对象(including another factory)的工厂,或者一个通用的依赖注入框架,它比管理实际上做的代码要复杂得多。
当我管理Zend Framework项目时,我不得不处理那些意图抽象的人,直到注视肚脐。我拒绝了一堆建议来创建没有做任何事情的组件,它们只是GoF模式的神奇实现,就好像模式本身就是一个目标,而不是达到目标的手段。
抽象的回报有所减少。一些抽象很棒,但最终你需要编写一些有用的代码。
答案 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