python做meta分析_python的MetaClass的代码分析。基于廖雪峰博客代码

本文详细分析了Python中的MetaClass,以廖雪峰的代码为例,展示了如何使用元类创建数据库模型。元类`ModelMetaclass`用于处理Model类中的字段,将Field实例转换为映射关系,并在实例化Model子类时自动构建SQL插入语句。通过元类,程序员可以自定义类的属性和行为,实现模型与数据库表的映射。
摘要由CSDN通过智能技术生成

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))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值