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

  1 # 一张表一个类,表内每一行就是一个实例
  2 '''
  3     一个单独的元类使用的程序分析。
  4 '''
  5 
  6 class Field(object):
  7     def __init__(self, name, column_type):
  8         self.name = name
  9         self.column_type = column_type
 10 
 11     def __str__(self):
 12         return '(<%s:%s>)' % (self.__class__.__name__, self.name)
 13 
 14 
 15 # self.__class__:得到当前实例的类       self.__class__.__name__:得到当前实例的类的名字
 16 # self.name:实例名字
 17 
 18     __repr__ = __str__
 19 
 20 
 21 class StringField(Field):
 22     def __init__(self, name):
 23         super(StringField, self).__init__(name, 'varchar(100)')
 24 
 25 
 26 class IntegerField(Field):
 27     def __init__(self, name):
 28         super(IntegerField, self).__init__(name, 'bigint')
 29 
 30 
 31 # ModelMetaclass这个元类的__new__()方法在本程序中的作用:
 32 # 1.在依据ModelMetaclass创建Model时,由Model向元类传入的参数为:cls:<class '__main__.ModelMetaclass>;name:Model;bases()传入的bases是一个tuple:(<class 'dict'>,),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 class ModelMetaclass(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 in attrs.items():
 50             if isinstance(v, Field):
 51                 print('Found mapping: %s==>%s' % (k, v))
 52                 mappings[k] = v
 53         for k in mappings.keys():
 54             # print([(k, v) for k, v in attrs.items() if isinstance(v, Field)])
 55             attrs.pop(k)
 56         attrs['__mappings__'] = mappings
 57         attrs['__table__'] = name
 58         # 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             return self[key]
 71         except KeyError:
 72             raise AttributeError(r"'Model' object has no attribute '%s'" % key)
 73 
 74     def __setattr__(self, key, value):
 75         self[key] = value
 76 
 77     def save(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 class User(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))

 

转载于:https://www.cnblogs.com/fishpoint/p/8673191.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值