本文示例代碼在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()