对于不能以任何其他方式使用的元类,可以做些什么?
Alex Martelli告诉我们,如果没有元类,有些任务无法实现Python metaclasses vs class decorators 我想知道哪些是?
答案 0 :(得分:18)
如果您想要具有“特殊自定义行为”的类对象(而不是类对象的实例),则元类是必不可少的,因为对象的行为取决于上的特殊方法对象的类型,类对象的类型恰好是元类的同义词。
例如,如果你想要一个类对象X,使得“print X”发出“时间现在是8:46 am”(上午8:46,或者更一般地说,是当前时间),这必须意味着{{ 1}}(AKA X的元类)有一个特殊的自定义type(x)
方法 - 并且类似地(使用各种适用的特殊方法)如果你想给__str__
等X和Y这样的表达式赋予意义都是类对象,或X + Y
(其中X,同样是一个类对象),等等。
现在大多数其他自定义任务(在Python 2.6或更高版本中)更容易使用类装饰器实现,类装饰器可以在X[23]
语句结束后立即更改类对象。还有一些情况下这是不可行的,因为如果它们要产生任何影响(例如,设置或改变class
),必须尽早进行更改。
在Python 3中,元类获得了一些额外的用处:元类现在可以选择性地指定在执行__slots__
语句的主体期间要填充的映射对象(默认情况下,它是正常的{{1 }})。这允许保留和使用类主体中名称绑定的 order (当正常class
失去顺序时),当类必须具有“字段”时,这有时很好某些特定的顺序(例如,将1:1映射到C dict
,CSV文件或数据库表中的行等) - 在Python 2中。*必须冗余地指定(通常使用额外的类属性,它是一个序列,因此保留了顺序),Python 3元类的这个特性允许删除冗余。
答案 1 :(得分:10)
为您的编程增加额外的灵活性:
但根据这个Metaclass programming in Python你可能不需要它们(还)
元素比99%的用户应该担心的更深刻。如果你想知道你是否需要它们,你就不会(实际需要它们的人肯定知道他们需要它们,并且不需要解释原因)。
- Python大师Tim Peters
答案 2 :(得分:8)
我使用某些频率的元类,它们是工具箱中非常强大的工具。有时你的问题解决方案可以更优雅,更少的代码,而不是没有。
我发现自己最经常使用元类的方法是在类创建过程中对类属性进行后处理。例如,在适当的位置设置对象的name
属性(比如Django ORM可能如何工作):
class AutonamingType(type):
def __init__(cls, name, bases, attrs):
for k,v in attrs.iteritems():
if getattr(v, '__autoname__', False):
v.name = k
class Autonamer(object):
__metaclass__ = AutonamingType
如果您将此作为工具,并且您正在使用必须知道其name
的类do_something()
:
class Foo(object):
__autoname__ = True
def __init__(self, name=None):
self.name = name
def do_something(self):
if self.name is None:
raise ValueError('name is None')
# now, do something
它可以使你的代码的其余部分区别开来:
class Bar(object):
myfoo1 = Foo('myfoo1')
myfoo2 = Foo('myfoo2')
myfoo3 = Foo('myfoo3')
和此:
class Baaz(Autonamer):
myfoo1 = Foo()
myfoo2 = Foo()
myfoo3 = Foo()
因此减少了重复(以及变量名和指定名称可能不同步的可能性)。
答案 3 :(得分:4)
如果您正在寻找使用元类机制的示例,您可以阅读django.forms的源代码。
表单定义的声明式样式是通过元类实现的。
答案 4 :(得分:1)
它们很少需要,但在你想要为对象的基本行为添加行为的地方有用 - 比较面向方面编程,或者像Hibernate这样在持久性框架中完成的工具。
例如,您可能需要一个持久化或记录每个新对象的类。
答案 5 :(得分:1)
可能没有什么可以专门用于元类,但对于某些人(包括我的),这是一个你可以使用的有趣工具。小心不要滥用,因为它可能很棘手。
例如,我在最近的一个项目中使用过元编程。这是一个OpenOffice计算表,它使用一些pyUNO宏生成一些包含信息的文件。有一张表格向用户显示要填写的信息,其他表格可用于描述元素的类型及其属性。然后,用户可以选择元素的数量和每个元素的类型,并生成文件。 宏将按照每个工作表上的配置通过元编程创建一个类。然后,用户可以实例化每个类并生成对象。
可以在没有元编程的情况下完成,但对我来说似乎很自然地使用元编程功能来实现它。
答案 6 :(得分:1)
查看Django源代码 - 例如,在那里使用元类来生成模型。
http://code.djangoproject.com/wiki/DynamicModels
在内部,Django使用元类 根据你的类创建模型 在您的源代码中提供。没有 进入太多细节,那 意味着而不是你的课程 作为实际的模型,Django 收到你班级的描述, 它用于在其中创建模型 的地方。
答案 7 :(得分:0)
第一位评论员指出,使用元类here是一块宝石'这有助于他追踪(很多)“天”发生的意外错误。