Python 中的元类是什么?
什么是元类,我们用它们做什么?
-
元类是类的类。就像类定义类的实例的行为方式一样,元类定义类的行为方式。类是元类的一个实例。
虽然在 Python 中,您可以对元类使用任意可调用对象(如 Jerub 所示),但更有用的方法实际上是使其本身成为一个实际的类。
type
是 Python 中常用的元类。如果您想知道,是的,type
它本身就是一个类,它是它自己的类型。您将无法重新创建type
纯粹在 Python 中的东西,但 Python 会作弊。要在 Python 中创建自己的元类,你真的只想继承type
.元类最常用作类工厂。就像您通过调用类来创建类的实例一样,Python 通过调用元类来创建一个新类(当它执行“类”语句时)。结合普通
__init__
和__new__
方法,元类因此允许您在创建类时做“额外的事情”,例如使用某个注册表注册新类,甚至完全用其他东西替换该类。执行语句时
class
,Python 首先将class
语句体作为普通代码块执行。生成的命名空间(一个字典)保存了类的属性。元类是通过查看待定类的基类(继承元类)、待定类的__metaclass__
属性(如果有)或__metaclass__
全局变量来确定的。然后使用类的名称、基类和属性调用元类以实例化它。然而,元类实际上定义了一个类的 类型 ,而不仅仅是它的工厂,所以你可以用它们做更多的事情。例如,您可以在元类上定义普通方法。这些元类方法类似于类方法,因为它们可以在没有实例的类上调用,但它们也不像类方法,因为它们不能在类的实例上调用。是元类
type.__subclasses__()
上的方法的示例。type
您还可以定义普通的“魔术”方法,如和__add__
,以实现或更改类的行为方式。__iter__``__getattr__
演示:
def make_hook(f): """Decorator to turn 'foo' method into '__foo__'""" f.is_hook = 1 return f class MyType(type): def __new__(mcls, name, bases, attrs): if name.startswith('None'): return None # Go over attributes and see if they should be renamed. newattrs = {} for attrname, attrvalue in attrs.iteritems(): if getattr(attrvalue, 'is_hook', 0): newattrs['__%s__' % attrname] = attrvalue else: newattrs[attrname] = attrvalue return super(MyType, mcls).__new__(mcls, name, bases, newattrs) def __init__(self, name, bases, attrs): super(MyType, self).__init__(name, bases, attrs) # classregistry.register(self, self.interfaces) print "Would register class %s now." % self def __add__(self, other): class AutoClass(self, other): pass return AutoClass # Alternatively, to autogenerate the classname as well as the class: # return type(self.__name__ + other.__name__, (self, other), {}) def unregister(self): # classregistry.unregister(self) print "Would unregister class %s now." % self class MyObject: __metaclass__ = MyType class NoneSample(MyObject): pass # Will print "NoneType None" print type(NoneSample), repr(NoneSample) class Example(MyObject): def __init__(self, value): self.value = value @make_hook def add(self, other): return self.__class__(self.value + other.value) # Will unregister the class Example.unregister() inst = Example(10) # Will fail with an AttributeError #inst.unregister() print inst + inst class Sibling(MyObject): pass ExampleSibling = Example + Sibling # ExampleSibling is now a subclass of both Example and Sibling (with no # content of its own) although it will believe it's called 'AutoClass' print ExampleSibling print ExampleSibling.__mro__
-
在我编写的测试框架中,我想跟踪定义类的顺序,以便以后可以按此顺序实例化它们。我发现使用元类最容易做到这一点。
class MyMeta(type): counter = 0 def __init__(cls, name, bases, dic): type.__init__(cls, name, bases, dic) cls._order = MyMeta.counter MyMeta.counter += 1 class MyType(object): # Python 2 __metaclass__ = MyMeta class MyType(metaclass=MyMeta): # Python 3 pass
任何作为
MyType
then 子类的东西都会获得一个类属性,该属性_order
记录了定义类的顺序。
发表回复