Python中的元类是什么?
元类是什么,我们将它们用于什么?
解决方案
注意,此答案适用于2008年编写的Python 2.x,3.x中的元类略有不同,请参见注释。
元类是使"类"工作的秘诀。新样式对象的默认元类称为"类型"。
class type(object) | type(object) -> the object's type | type(name, bases, dict) -> a new type
元类带有3个参数。 '名称','基础'和'dict'
这是秘密的开始。在此示例类定义中查找名称,基数和字典来自何处。
class ThisIsTheName(Bases, Are, Here): All_the_code_here def doesIs(create, a): dict
让我们定义一个元类,该元类将演示" class:"如何调用它。
def test_metaclass(name, bases, dict): print 'The Class Name is', name print 'The Class Bases are', bases print 'The dict has', len(dict), 'elems, the keys are', dict.keys() return "yellow" class TestName(object, None, int, 1): __metaclass__ = test_metaclass foo = 1 def baz(self, arr): pass print 'TestName = ', repr(TestName) # output => The Class Name is TestName The Class Bases are (<type 'object'>, None, <type 'int'>, 1) The dict has 4 elems, the keys are ['baz', '__module__', 'foo', '__metaclass__'] TestName = 'yellow'
现在,一个实际上意味着含义的示例将自动使列表中的变量"设置为"类,并设置为"无"。
def init_attributes(name, bases, dict): if 'attributes' in dict: for attr in dict['attributes']: dict[attr] = None return type(name, bases, dict) class Initialised(object): __metaclass__ = init_attributes attributes = ['foo', 'bar', 'baz'] print 'foo =>', Initialised.foo # output=> foo => None
请注意,通过使元类" init_attributes"获得" Initalized"所获得的魔术行为不会传递到Initalized的子类上。
这是一个更具体的示例,显示了如何子类化"类型"以使元类在创建类时执行操作。这很棘手:
class MetaSingleton(type): instance = None def __call__(cls, *args, **kw): if cls.instance is None: cls.instance = super(MetaSingleton, cls).__call__(*args, **kw) return cls.instance class Foo(object): __metaclass__ = MetaSingleton a = Foo() b = Foo() assert a is b
我认为ONLamp对元类编程的介绍写得很好,尽管已经有好几年历史了,但它对该主题却提供了非常好的介绍。
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html(存档于https://web.archive.org/web/20080206005253/http://www.onlamp。 com / pub / a / python / 2003/04/17 / metaclasses.html)
简而言之:类是创建实例的蓝图,元类是创建类的蓝图。很容易看出,在Python中,类也必须是一流的对象才能启用此行为。
我从来没有自己写过,但是我认为在Django框架中可以看到元类最好的用途之一。模型类使用元类方法来启用声明性样式,以编写新模型或者表单类。当元类创建类时,所有成员都可以自定义类本身。
- 创建一个新模型
- 元类实现了这一点
剩下要说的是:如果我们不知道什么是元类,则不需要它们的可能性为99%。
元类的一种用途是自动向实例添加新的属性和方法。
例如,如果我们查看Django模型,则其定义看起来有些混乱。似乎我们只是在定义类属性:
class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
但是,在运行时,Person对象充满了各种有用的方法。请参阅源代码以获取一些惊人的元类。
元类是类的类。就像类定义类的实例的行为一样,元类定义类的行为。类是元类的实例。
尽管在Python中我们可以对元类使用任意可调用对象(例如Jerub演示),但实际上更有用的方法是使其成为实际的类。 type是Python中常见的元类。如果我们想知道,是的,type
本身就是一个类,并且它是自己的类型。我们将无法纯粹在Python中重新创建类似" type"的内容,但是Python会有些作弊。要在Python中创建自己的元类,我们实际上只想将type子类化。
元类最常用作类工厂。就像我们通过调用类来创建类的实例一样,Python通过调用元类来创建一个新类(在执行" class"语句时)。因此,与常规的__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__