博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于廖雪峰提到的元类的应用实例的解释
阅读量:6931 次
发布时间:2019-06-27

本文共 6925 字,大约阅读时间需要 23 分钟。

class Field(object):    def __init__(self, name, column_type):        self.name = name        self.column_type = column_type    def __str__(self):        return '<%s:%s' % (self.__class__.__name__, self.name)class StringField(Field):    def __init__(self, name):        super(StringField, self).__init__(name, 'varchar(100)')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)        print(attrs)        print('Found model: %s' % name)        mappings = dict()        for k, v in attrs.items():                    if isinstance(v, Field):    #这个有点难理解,为什么不是k,而是v                print('Found mapping: %s ==> %s' % (k, v))                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, **kw):        super(Model, self).__init__(**kw)    def __getattr__(self, key):        try:            return self[key]        except KeyError:            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(params))        print('SQL: %s' % sql)        print('ARGS: %s' % str(args))class User(Model):    # 定义类的属性到列的映射:    id = IntegerField('id')    name = StringField('username')    email = StringField('email')    password = StringField('password')u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd',sdfjojf='sdfe')u.save()

当创建实例时,需要调用User类,首先会检查有没有__metaclass__属性,找到了,通过metalclass创建类(基于User类,传入的name为User,父类为Model,属性为User类的属性)。之后在实例化过程中,需要调用创建的新的User类中的方法,如果没有,需要到父类(metalclass创建新类会传承User类的父类)中查找,比如说之后会调用__init__方法,之后又调用save方法。

结果为:

Found model: UserFound mapping: email ==> 
Found mapping: password ==>
Found mapping: id ==>
Found mapping: name ==>
SQL: insert into User (password,email,username,id) values (?,?,?,?)ARGS: ['my-pwd', 'test@orm.org', 'Michael', 12345]

另外:__metaclass__函数中传递的是在__dict__中可以查询到的特殊类属性。

程序来源:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319106919344c4ef8b1e04c48778bb45796e0335839000

所以,我们加几行代码:

1 class Field(object): 2  3     def __init__(self, name, column_type): 4         self.name = name 5         self.column_type = column_type 6  7     def __str__(self): 8         return '<%s:%s' % (self.__class__.__name__, self.name) 9 10 class StringField(Field):11 12     def __init__(self, name):13         super(StringField, self).__init__(name, 'varchar(100)')14 15 class IntegerField(Field):16 17     def __init__(self, name):18         super(IntegerField, self).__init__(name, 'bigint')19 20 class ModelMetaclass(type):21 22     def __new__(cls, name, bases, attrs):   #传入的是类的属性23         if name=='Model':24            return type.__new__(cls, name, bases, attrs)25         print(attrs)    #后来加26         print('Found model: %s' % name)27         mappings = dict()28 29         for k, v in attrs.items():30             if isinstance(v, Field):#这个有点难理解,为什么不是k,而是v31                 print('Found mapping: %s ==> %s' % (k, v))   #这里是将k赋值为id,name,email,password,所以type(k)为str32                 mappings[k] = v33         for k in mappings.keys():34             attrs.pop(k)    #删除一些属性35         attrs['__mappings__'] = mappings # 保存属性和列的映射关系36         attrs['__table__'] = name # 假设表名和类名一致37         return type.__new__(cls, name, bases, attrs)38 39 class Model(dict, metaclass=ModelMetaclass):40 41     def __init__(self, **kw):42         super(Model, self).__init__(**kw)43 44     def __getattr__(self, key):45         try:46             return self[key]47         except KeyError:48             raise AttributeError(r"'Model' object has no attribute '%s'" % key)49 50     def __setattr__(self, key, value):51         self[key] = value52 53     def save(self):54         fields = []55         params = []56         args = []57         for k, v in self.__mappings__.items():58             fields.append(v.name)59             params.append('?')60             args.append(getattr(self, k, None))61         sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))62         print('SQL: %s' % sql)63         print('ARGS: %s' % str(args))64 65 class User(Model):66     # 定义类的属性到列的映射:67     id = IntegerField('id')68     name = StringField('username')69     email = StringField('email')70     password = StringField('password')71 72 73 print('...')74 for i, v in User.__dict__.items():   #后来加75     print(i, v)76 print('...')77 78 u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd',sdfjojf='sdfe')79 u.save()

会得到下面的结果:

{'__module__': '__main__', '__qualname__': 'User', 'id': <__main__.IntegerField object at 0x0051FC50>, 'name': <__main__.StringField object at 0x0051FC70>, 'email': <__main__.StringField object at 0x0051FC90>, 'password': <__main__.StringField object at 0x0051FCB0>}Found model: UserFound mapping: id ==> 
, 'name': <__main__.StringField object at 0x0051FC70>, 'email': <__main__.StringField object at 0x0051FC90>, 'password': <__main__.StringField object at 0x0051FCB0>}__table__ User__doc__ None...SQL: insert into User (id,username,email,password) values (?,?,?,?)ARGS: [12345, 'Michael', 'test@orm.org', 'my-pwd']

关于57行,类中有的属性(类中__dict__可以查到的属性),可以在定义的函数中使用可以通过self.属性  查询到!

比如:

class P():    def qss(self):        print(self.__module__)print(dir(P))print(P.__dict__)p=P()p.qss()

运行结果:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'qss']{
'__module__': '__main__', 'qss':
, '__dict__':
, '__weakref__':
, '__doc__': None}__main__

 在元类中选择重新定义 __new__() 方法还是 __init__() 方法取决于你想怎样使用结果类。__new__() 方法在类创建之前被调用,通常用于通过某种方式(比如通过改变类字典的内容)修改类的定义。而 __init__() 方法是在类被创建之后被调用,当你需要完整构建类对象的时候会很有用。如果要用 super() 函数来搜索之前的定义。它只能在类的实例被创建之后,并且相应的方法解析顺序也已经被设置好了。

转载于:https://www.cnblogs.com/wangzixuan-welcome/p/6284642.html

你可能感兴趣的文章
mongodb 在window下安装测试
查看>>
Ueditor踩坑之旅(react)
查看>>
AbstractQueuedSynchronizer 原理分析 - 独占/共享模式
查看>>
iOS 前后台机制以及后台唤醒机制【个人学习】
查看>>
js 基本字符串和字符串对象
查看>>
python中yaml配置文件模块的使用
查看>>
k8s与CICD--将drone部署到kubernetes中,实现agent动态收缩
查看>>
React Ref or Not?
查看>>
Linux开机启动二三事
查看>>
16道初级脚本算法,你要挑战一下吗?
查看>>
万圣节动画-canvas像素点
查看>>
SpringCloud(第 028 篇)ConfigServer 配置管理微服务
查看>>
Chrome 61 Beta:JavaScript 模块,桌面端的支付请求 API,Web Share API 和 WebUSB
查看>>
你还在等着用户反馈BUG?
查看>>
Pandas中时间和日期处理
查看>>
利用JS在AWS上构建大规模弹性Web应用
查看>>
《A Practical Guide to Continuous Delivery》作者访谈录
查看>>
系统监控:top vs Htop vs Glances
查看>>
《The Coaching Booster》问与答
查看>>
TOP15大有用的Helm Charts工具列表
查看>>