本文示例代码在python3.7下python
class A: pass a = A() print(type(a)) print(type(A))
输出sql
<class '__main__.A'> <class 'type'>
a是A类的实例,类A(是一个class)是type的实例(注意:类A是type的实例,是object的子类,全部新式类的根类都是object)app
name:这将是须要建立的类的名称。对于咱们的状况,它将是字符串'A'。
bases:该类基类的元组。
attrs:它是一个字典,包含为该类定义的全部属性函数
所以动态建立上述A类能够写做:spa
A = type('A', (), {})
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__来建立类blog
class B(metaclass=TestMetaClass): pass b = B() print(type(b)) print(type(B))
输出
<class '__main__.B'>
<class '__main__.TestMetaClass'>继承
b是类B的一个实例,类B是TestMetaClass的实例字符串
B = TestMetaClass('B', (), {}) b = B() print(type(b)) print(type(B))
class TestMetaClass(type): def __new__(cls, name, bases, attrs): return type.__new__(cls, name, bases, attrs)
方法为:
type(some_object)get
方法为:
type(cls类名, bases(继承的元组), attrs(属性字典))
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)
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()