python的元类
本文示例代码在python3.7下
一.元类(metaclass)
1.python中一切皆对象.class也是一个对象.
class A:
pass
a = A()
print(type(a))
print(type(A))
输出
<class '__main__.A'> <class 'type'>
a是A类的实例,类A(是一个class)是type的实例(注意:类A是type的实例,是object的子类,所有新式类的根类都是object)
2.A类是如何创建的?
(1).解释器检查是否有类A的元类属性,如果有则按指定元类来创建
(2).如果没有则默认使用type元类来创建
(3).对于创建类,解释器调用元类,需要使用三个参数
name:这将是需要创建的类的名称。对于我们的情况,它将是字符串'A'。
bases:该类基类的元组。
attrs:它是一个字典,包含为该类定义的所有属性
因此动态创建上述A类可以写作:
A = type('A', (), {})
3.元类:
(1).type是创建类的默认元类,指示了类如何被创建.
(2).元类只是一个可以创建类的类,就像普通类具有创建该类实例的能力一样,元类也具有创建类的能力。创建的类是元类的一个实例
(3).类是元类的一个实例
(4).由于type是默认元类,因此如果我们要编写元类,我们必须从type继承。
二.实例
1.自定义元类:
class TestMetaClass(type):
def __new__(cls, name, bases, attrs):
return super().__new__(cls, name, bases, attrs)
(1).继承自元类type
(2).在元类中覆写了__new__
(3).解释器将使用三个参数调用我们的元类,因此元类的__new__将接收四个参数。所以我们要注意__new__元类需要四个参数
(4).在__new__中我们使用超类中的__new__,如果TestMetaClass不是从type继承,实际的类创建将发生在type的__new__中
(5).任何类的__new__收到的第一个参数是类本身(上文代码中的cls)
如果我们编写元类,必须从type继承,必须覆写__new__,并且调用超类的__new__来创建类
2.使用TestMetaClass
class B(metaclass=TestMetaClass):
pass
b = B()
print(type(b))
print(type(B))
输出
<class '__main__.B'>
<class '__main__.TestMetaClass'>
b是类B的一个实例,类B是TestMetaClass的实例
(1).解释器知道默认的元类类型不能用于创建B.而是必须使用TestMetaClass来创建B.
(2).当调用MyMeta时,调用MyMeta的__new__
(3).以上代码等同于:
B = TestMetaClass('B', (), {})
b = B()
print(type(b))
print(type(B))
(4).因为TestMetaClass继承自type,所以TestMetaClass的__new__也可以定义成
class TestMetaClass(type):
def __new__(cls, name, bases, attrs):
return type.__new__(cls, name, bases, attrs)
三.type
1.type(),是一个内置函数,可以检查类型
方法为:
type(some_object)
2.type是一个内置函数,也可以动态创建类:
方法为:
type(cls类名, bases(继承的元组), attrs(属性字典))
3.type也是一个类,是创建类的默认元类
四.何时使用
1.元类使用的比较少,99%的情况下用不到
2.一个简单的例子,限制类的属性:
allowed_attributes = ['first', 'second']
class Meta(type):
def __new__(cls, name, bases, attrs):
attrs_list = list(attrs)
for each_attr in attrs_list:
if not each_attr.startswith('_') and each_attr not in allowed_attributes:
del attrs[each_attr]
print("Attributes after deleting non allowed attributes", attrs)
return type.__new__(cls, name, bases, attrs)
class B(metaclass=Meta):
first = 1
second = 2
third = 3
b = B()
注意:
上文代码中,您或许可能认为直接使用__new__就可以实现,因为__new__就是负责实例的创建.但类B中first,second等属性是静态属性,隶属于类,而不是实例,所以此处使用了元类.元类是负责类的创建.
我们使用__new__来写一个限制实例属性的(不是很恰当)
class My:
def __new__(cls, *args, **kwargs):
print(kwargs)
if not isinstance(kwargs, dict):
raise RuntimeError('参数错误')
if 'c' in kwargs:
raise RuntimeError('不能包含key为c的参数')
return super().__new__(cls)
def __init__(self, **kwargs):
self.args = kwargs
test = My(a=2, b=3, c=100)
print(test.args)
3.ORM的例子
class Field(object):
def __init__(self, name, column_type):
self.__name = name
self.__column_type = column_type
def __str__(self):
return '<%s,%s>' % (self.__name, self.__column_type)
def __getattr__(self, item):
return {'name': self.__name, 'column': self.__column_type}[item]
class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'bigint')
class ModelMetaClass(type):
def __new__(cls, name, bases, attrs):
if name == 'Model':
return type.__new__(cls, name, bases, attrs)
mappings = dict()
for k, v in attrs.items():
if isinstance(v, Field):
mappings[k] = v
for k in mappings.keys():
attrs.pop(k)
attrs['__mappings__'] = mappings
attrs['__table__'] = name
return type.__new__(cls, name, bases, attrs)
class Model(dict, metaclass=ModelMetaClass):
def __init__(self, **kwargs):
super(Model, self).__init__(**kwargs)
def __getattr__(self, key):
try:
return self[key]
except BaseException:
raise AttributeError(r"'Model' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
self[key] = value
def save(self):
fields = []
params = []
args = []
for k, v in self.__mappings__.items():
fields.append(v.name)
params.append('?')
args.append(getattr(self, k, None))
sql = 'insert into %s(%s) values(%s)' % \
(self.__table__, ','.join(fields), \
','.join([str(x) for x in args]))
print('SQL: %s' % sql)
class User(Model):
id = IntegerField('id')
# create user instance
user = User(id=100)
user.save()
浙公网安备 33010602011771号