通过元类,可以修改类的方法与实现,根据“_ init_”与“_ new_”方法钩子的不同,可以在类创建后与类创建前添加控制,在类创建前可提供默认实现,在类创建后可以提供方法检查、属性检查与覆盖实现。
在大部分的情况下,通过继承可以实现元类的大部分功能,所以在99%的情况下,元类基本都用不上,但是需要对类自身进行操作时,元类就排上了用场,下面是具体步骤。
1. 创建元类
元类必须要继承types,或者是其他元类,如下:
class MetaClass(type):
# 在类创建前调用
def __new__(cls, name, bases, attrs):
def sayHello(self):
print 'Hello, %s' %(self.username)
# 添加实例方法
cls.sayHello = sayHello
return super(MetaClass, cls).__new__(cls, name, bases, attrs)
# 在类创建后调用,这里的self指向带创建的类
def __init__(self, name, bases, attrs):
# 添加静态方法
def add(a, b):
return a + b
# 添加类方法
def adds(cls, a, b):
return a + b
self.add = staticmethod(add)
self.adds = classmethod(adds)
super(MetaClass, self).__init__(name, bases, attrs)
# 元类也可以继承
class DomainMeta(MetaClass):
pass
在上面的代理里,需要总结的有:
1. “_ new_”提供默认实现(优先级最低),记住一定要有返回值;
2. “_ init_”会覆盖类的定义(优先级最高);
3. 类方法与静态方法的区别在于参数数量,类方法第一个参数为类对象自身,而静态则没有第一个参数;
2. 使用元类
使用元类非常简单,只要在创建类时指定“_ metaclass_”属性即可,如下:
class Person(object):
__metaclass__ = DomainMeta
def __init__(self, username):
self.username = username
def sayHello(self):
print 'Hi, %s' %(self.username)
通过“_ metaclass_”属性,类获得了元类中定义的方法,包括静态方法、类方法以及实例方法,如下:
yiifaa = Person('yiifaa')
# 会被类中的定义方法覆盖
yiifaa.sayHello()
# 静态方法
print Person.add(2, 3)
# 类方法
print Person.adds(5, 5)
结论
与继承相比,元类会满足如下条件(继承刚好相反):
1. 类是它的实例。
# 输出True
print isinstance(Person, DomainMeta)
- 元类与类不存在继承关系。
# 输出False
print issubclass(Person, DomainMeta)
- 元类与类通过“_ class_”建立关系。
# 输出True
print Person.__class__ == DomainMeta
最后,type是所有类的祖先节点,包括元类。
# 输出True
print Person.__class__.__class__ == type
# 输出True
print isinstance(Person, type)