1

以 WTForms 表单定义类为例:

class RegistrationForm(Form):
    username     = StringField('Username', [validators.Length(min=4, max=25)])
    email        = StringField('Email Address', [validators.Length(min=6, max=35)])
    accept_rules = BooleanField('I accept the site rules', [validators.InputRequired()])

并查看库的源代码,似乎 WTForms 允许用户定义一个非常简单的自定义表单结构类(如上),然后用于构造一个新的字段类,该类在类被实例化时不会被实例化生成。

我已经阅读了许多关于类工厂和元类的教程,普遍的共识是避免使用元类,而是使用类装饰器之类的东西。问题是教程要么开始导入额外的库,例如:import six混合不同 Python 版本的解释,使用过于复杂的示例,要么建议根本不要使用元类。

请有人提供一个非常简单的解释(对于 Python 3),说明如何使用简单的类定义(如上面的 WTForms 示例)以及元类来自定义类的全新构造,而无需在构造类时实际实例化类。

编辑:很抱歉很难解释我的最终目标是什么,但是当我浏览教程时,我不清楚类装饰器、元类、魔术方法(callnewinit)或这些方法的组合是什么需要实现我所想象的,或者我所想象的是否是错误的做事方式。不幸的是,如果不了解实现目标所需的机制,似乎无法判断我的目标是否错误。我已经意识到元类是要走的路,只需要为一个非常简单的元类示例指明正确的方向,以 Python 3.x 的方式完成。

4

1 回答 1

3

您可以动态创建类 - 没有自定义元类和装饰器,程序员看起来只是简单的函数调用。

只需使用三个参数调用 Python 的内置type函数:类的名称、带有其基的元组和带有名称空间的映射对象(即包含您通常在类主体上定义的属性和方法的字典)。

def __init__(self):
    ...

namespace = {
   '__init__': init,
   'name': 'default name'
}

MyClass = type("MyClass", (object,), namespace)

您失去了一些功能,这些功能只有在编译器在构建类体内声明的函数期间做了一些特殊的事情时才可能实现 - 主要是使用无参数super 和以 开头的属性的名称修饰的能力__,但仅此而已。

也就是说,应该注意这不是“没有元类”。“type”本身就是一个元类——所有对象的默认 Python 元类——并且正在调用一个创建类的元类。没有其他方法可以创建类。“类装饰器”只是一种可以在创建类对象后对其进行更改的方法。

任何产生新的动态类的函数或方法,都会在其中包含调用type或其他元类。同样,“元类”本身不会创建动态类——它需要在类主体声明中使用,或者使用(至少)与调用相同的参数进行调用type

至于“类装饰器”而不是元类的建议,我不确定是不是这样(事实上,“类装饰器”无法自行动态创建类):它们的主要缺点是没有普通的装饰类的子类自动将父类的装饰器应用到自己的方式,而元类是继承的。

在 Python 3.6__init_subclass__中,您拥有的协议可以避免元类的许多传统用途(但它仍然不会“动态创建类”——调用type会这样做)。

于 2017-05-31T08:22:33.657 回答