动态创建 class 而不实例化它 - 没有 metaclasses?
Create a class dynamically without instantiating it - no metaclasses?
以 WTForms 表单定义 classes 为例:
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 似乎允许用户定义一个非常简单的 class 自定义表单结构(如上所述),然后它又被用来构建一个新的 field class 是 not 在生成 class 时实例化。
我已经阅读了很多关于 class 工厂和 metaclasses 的教程,普遍的共识是避免使用 metaclasses 并使用 class 装饰器代替。问题是教程要么开始导入额外的库,例如:import six
,将不同 Python 版本的解释混合在一起,使用过于复杂的示例,要么建议根本不要使用 metaclasses。
请有人提供一个非常简单的解释(针对 Python 3)如何使用简单的 class 定义(如上面的 WTForms 示例)以及元 classes自定义 class 的全新构造,而无需在构造时实际实例化 class。
编辑: 很抱歉发现很难解释我的最终目标是什么,但由于我已经完成了教程,所以不清楚 class 装饰器, metaclasses, 魔术方法 (call, new, init) 或组合这些是我实现我想象的东西所需要的,或者如果我想象的是错误的做事方式。不幸的是,在无法理解实现目标所需的机制的情况下,似乎无法判断我的目标是否错误。我已经意识到 metaclasses 是要走的路,只需要指向正确的方向即可完成一个非常简单的 metaclass 示例 Python 3.x 方式。
您可以动态创建 classes - 没有自定义元classes,也没有装饰器,在程序员看来只是简单的函数调用。
只需使用三个参数调用 Python 的内置函数 type
:
class 的名称、一个带有其基的元组和一个带有命名空间的映射对象(即包含您通常在 class 主体上定义的属性和方法的字典)。
def __init__(self):
...
namespace = {
'__init__': init,
'name': 'default name'
}
MyClass = type("MyClass", (object,), namespace)
你失去了一些功能,这些功能只有在编译器在构建 class 主体中声明的函数期间做了一些特殊的事情时才有可能 - 主要是使用无参数 super
和名称修饰的能力以 __
开头的属性,仅此而已。
也就是说,应该注意这与 "no metaclasses" 无关。 "type" 本身就是一个 metaclass - 所有对象的默认 Python metaclass - 并且正在调用一个创建 class 的 metaclass .没有其他方法可以创建 class。 "class decorator" 只是一种方法,可以在创建 class 对象后对其进行更改。
任何生成新的动态 class 的函数或方法都将在其中调用 type
或其他元class。同样,"metaclass" 本身不会创建动态的 classes - 它需要在 class 主体声明中使用,或者使用(至少)相同的参数调用用于调用 type
.
至于 "class decorators" 而不是 metaclasses 的建议,我不确定是不是真的(除此之外 "class decorator" 无法创建 classes 本身是动态的):它们的主要缺点是没有普通的方法让装饰的 classes 的子classes 自动将父级的 class 装饰器应用于自己,而 metaclasses 是继承的。
在 Python 3.6 中,你有 __init_subclass__
协议,是的,它可以避免 metaclass 的许多传统用途(但仍然不会 "create classes dynamically" - 调用 type
就是这样做的)。
以 WTForms 表单定义 classes 为例:
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 似乎允许用户定义一个非常简单的 class 自定义表单结构(如上所述),然后它又被用来构建一个新的 field class 是 not 在生成 class 时实例化。
我已经阅读了很多关于 class 工厂和 metaclasses 的教程,普遍的共识是避免使用 metaclasses 并使用 class 装饰器代替。问题是教程要么开始导入额外的库,例如:import six
,将不同 Python 版本的解释混合在一起,使用过于复杂的示例,要么建议根本不要使用 metaclasses。
请有人提供一个非常简单的解释(针对 Python 3)如何使用简单的 class 定义(如上面的 WTForms 示例)以及元 classes自定义 class 的全新构造,而无需在构造时实际实例化 class。
编辑: 很抱歉发现很难解释我的最终目标是什么,但由于我已经完成了教程,所以不清楚 class 装饰器, metaclasses, 魔术方法 (call, new, init) 或组合这些是我实现我想象的东西所需要的,或者如果我想象的是错误的做事方式。不幸的是,在无法理解实现目标所需的机制的情况下,似乎无法判断我的目标是否错误。我已经意识到 metaclasses 是要走的路,只需要指向正确的方向即可完成一个非常简单的 metaclass 示例 Python 3.x 方式。
您可以动态创建 classes - 没有自定义元classes,也没有装饰器,在程序员看来只是简单的函数调用。
只需使用三个参数调用 Python 的内置函数 type
:
class 的名称、一个带有其基的元组和一个带有命名空间的映射对象(即包含您通常在 class 主体上定义的属性和方法的字典)。
def __init__(self):
...
namespace = {
'__init__': init,
'name': 'default name'
}
MyClass = type("MyClass", (object,), namespace)
你失去了一些功能,这些功能只有在编译器在构建 class 主体中声明的函数期间做了一些特殊的事情时才有可能 - 主要是使用无参数 super
和名称修饰的能力以 __
开头的属性,仅此而已。
也就是说,应该注意这与 "no metaclasses" 无关。 "type" 本身就是一个 metaclass - 所有对象的默认 Python metaclass - 并且正在调用一个创建 class 的 metaclass .没有其他方法可以创建 class。 "class decorator" 只是一种方法,可以在创建 class 对象后对其进行更改。
任何生成新的动态 class 的函数或方法都将在其中调用 type
或其他元class。同样,"metaclass" 本身不会创建动态的 classes - 它需要在 class 主体声明中使用,或者使用(至少)相同的参数调用用于调用 type
.
至于 "class decorators" 而不是 metaclasses 的建议,我不确定是不是真的(除此之外 "class decorator" 无法创建 classes 本身是动态的):它们的主要缺点是没有普通的方法让装饰的 classes 的子classes 自动将父级的 class 装饰器应用于自己,而 metaclasses 是继承的。
在 Python 3.6 中,你有 __init_subclass__
协议,是的,它可以避免 metaclass 的许多传统用途(但仍然不会 "create classes dynamically" - 调用 type
就是这样做的)。