1 #一张表一个类,表内每一行就是一个实例
2 '''
3 一个单独的元类使用的程序分析。4 '''
5
6 classField(object):7 def __init__(self, name, column_type):8 self.name =name9 self.column_type =column_type10
11 def __str__(self):12 return '()' % (self.__class__.__name__, self.name)13
14
15 #self.__class__:得到当前实例的类 self.__class__.__name__:得到当前实例的类的名字
16 #self.name:实例名字
17
18 __repr__ = __str__
19
20
21 classStringField(Field):22 def __init__(self, name):23 super(StringField, self).__init__(name, 'varchar(100)')24
25
26 classIntegerField(Field):27 def __init__(self, name):28 super(IntegerField, self).__init__(name, 'bigint')29
30
31 #ModelMetaclass这个元类的__new__()方法在本程序中的作用:
32 #1.在依据ModelMetaclass创建Model时,由Model向元类传入的参数为:cls:;name:Model;bases()传入的bases是一个tuple:(,),attrs是一个由Model类中的所有的方法名和方法函数地址组成的dict.
33 #然后再传入该元类后,执行__new__(),由于name=='Model'所以返回由type('Model', (dict,), attrs)所组成的类。return了,不往下执行。
34 #2.在准备创建User类时,可以见class User上的注释。此时name==User。在__new__()内执行时。if失效。往后运行,创建一个名为mappings的dict。mappings的作用是用来存储此时User里面的4个属性(id,name,password,email).并将作为一个属性返回。
35 #由于attrs包含了User中的所有的属性。所以先要用isinstance(v,Field)判断是不是id/name/password/email中的一个。若找到,则复制如mappings中。
36 #删除User的4个id/name/password/email属性(防止造成实例的属性遮盖类的同名属性)。
37 #添加两个属性__mappings__和__table__。并把最后的attrs作为最后要生成的名为User的类的所有方法。
38
39
40 classModelMetaclass(type):41 def __new__(cls, name, bases, attrs):42 #print('hello',cls,'---',name,'---',bases,'---',attrs)
43 if name == 'Model': #如果名字==Model。那么久用type创建一个类。在这里,name:要创建的类的名字;bases:要创建的类的父类;attrs:类的方法与函数对照字典。
44 #print(attrs)
45 return type.__new__(cls, name, bases, attrs)46 #return super().__new__(cls, name, bases, attrs)
47 print('Found model:%s' %name)48 mappings =dict()49 for k, v inattrs.items():50 ifisinstance(v, Field):51 print('Found mapping: %s==>%s' %(k, v))52 mappings[k] =v53 for k inmappings.keys():54 #print([(k, v) for k, v in attrs.items() if isinstance(v, Field)])
55 attrs.pop(k)56 attrs['__mappings__'] =mappings57 attrs['__table__'] =name58 #print(attrs)
59 return type.__new__(cls, name, bases, attrs)60
61
62 class Model(dict, metaclass=ModelMetaclass):63 def __init__(self, **kw):64 #print(Model.mro())
65 #调用父类dict类的__init__方法,需要传入一个dict。
66 super(Model, self).__init__(**kw)67
68 def __getattr__(self, key):69 try:70 returnself[key]71 exceptKeyError:72 raise AttributeError(r"'Model' object has no attribute '%s'" %key)73
74 def __setattr__(self, key, value):75 self[key] =value76
77 defsave(self):78 fields =[]79 params =[]80 args =[]81 for k, v in self.__mappings__.items():82 #print(v.name)
83 fields.append(v.name)84 params.append('?')85 #当u=User(......)后,u就具有了4个属性u.id=12345 u.name='Michael' u.email='test@orm.org' u.password='my-pwd'
86 args.append(getattr(self, k, None))87 sql = 'insert into %s (%s) values (%s)' % (self.__table__,88 ','.join(fields),89 ','.join(params))90 #join()函数
91 #语法: 'sep'.join(seq) 该例为:','.join(fields) 对应的:sep=, seq=fields.
92 #参数说明
93 #sep:分隔符。可以为空
94 #seq:要连接的元素序列、字符串、元组、字典
95 #上面的语法即:以sep作为分隔符,将seq所有的元素合并成一个新的字符串
96 #返回值:返回一个以分隔符sep连接各个元素后生成的字符串
97 print('SQL: %s' %sql)98 #print(args)
99 print('ARGS: %s' %str(args))100
101
102 #当用户定义一个class User(Model)时,Python解释器首先在当前类User的定义中查找metaclass,如果没有找到,
103 #就继续在父类Model中查找metaclass,找到了,就使用Model中定义的metaclass的ModelMetaclass来创建User类,
104 #也就是说,metaclass可以隐式地继承到子类,但子类自己却感觉不到。
105
106
107 #在创建User时,程序会先执行完里面的4条属性声明语句。然后再将包含该4条属性和所有的方法组成一个dict。传入ModelMetaclass的__new__中。
108
109
110 #通过使用元类,程序员可以在这里自定义一个类(数据库的一张表)需要输入哪些元素。
111
112 classUser(Model):113 id = IntegerField('id')114 name = StringField('username')115 email = StringField('email')116 password = StringField('password')117
118
119 #在这里时,User类里面没有4个单独的id/name/password/email属性,只有__mappings__和__table__属性。
120
121 #print(type(User.id))
122 #print(dir(User))
123 u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')124 #print(u.name.name)
125 #print(u.id.name)
126 #print(u.email.name)
127 #print(u.password.name)
128 #print(dir(u.id))
129 #print(u.id.name)
130 u.save()131 #print(dir(Model))