请选择 进入手机版 | 继续访问电脑版
搜索
房产
装修
汽车
婚嫁
健康
理财
旅游
美食
跳蚤
二手房
租房
招聘
二手车
教育
茶座
我要买房
买东西
装修家居
交友
职场
生活
网购
亲子
情感
龙城车友
找美食
谈婚论嫁
美女
兴趣
八卦
宠物
手机

PythonI/O进阶学习笔记_7.python动态属性,__new__和__init__和元类编程(

[复制链接]
查看: 11|回复: 0

8498

主题

8498

帖子

2万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
25504
发表于 2019-12-2 19:55 | 显示全部楼层 |阅读模式
content:
上:
1.property静态属性
2.__getattr__和__setattr__的区分和在属性查找中的感化
3.属性描摹符 和属性查找进程
4.__new__和__init__的区分
下:
5.什么是元类和自界说元类
6.用元类实现orm
=====================
五.什么是元类和自界说元类
1.什么是元类
在大白元类的时候,必要具有对python中类和实例的建立的概念有所了解,必要温习该系列的3中的类和工具那一章。了解类的建立、实例的建立、type和父类的继续次第等。
在类的相关章节中也提到了,元类就是类的类。也就是元类就是负责建立类的一种工具。可以大白为,元类就是负责天生类的。而 type 就是内建的元类。也就是 Python 自带的元类。

2.怎样自界说利用元类
a.模拟python中静态建立类
既然我们晓得python中齐全皆工具,类也是,所以类也是可以被建立的,那末我们自己是新一个传入类名,而且静态天生类的方式:
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息 1525498-20191202142103719-943957604

传入类名,在create_class中返回同名字的类名。

b.用type来加倍灵活的建立类
可是现实上在a中建立类照旧比力蠢的。要在方式中去一个个判命名字。
-  用type来静态建立类:
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息 1525498-20191202142438342-932389546

间接输入类名,便可以返回一个类。背面的参数要求:必须传递第一个参数,为类。而且传递进去的函数不加括号,为间接的函数工具。
这样的类就像是class User: pass 没有自界说的属性和方式。

-  建立传递类的属性和方式:
建立类的属性:
http://www.waysfocus.com/https://www.cnblogs.com/file:///C:/Users/dall/AppData/Local/Temp/enhtmlclip/Image(5).png
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息
传递类的方式:先建立一个函数,函数必须传递一个参数,为类。而且传递进去的函数不加括号,为间接的函数工具。
http://www.waysfocus.com/https://www.cnblogs.com/file:///C:/Users/dall/AppData/Local/Temp/enhtmlclip/Image(6).png
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息

- 继续父类
留意父类传递的那个参数典范为tuple。而且要加逗号,否则报错。
http://www.waysfocus.com/https://www.cnblogs.com/file:///C:/Users/dall/AppData/Local/Temp/enhtmlclip/Image(7).png
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息

3.metaclass
a.利用元类
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息
这个metaclass可以控制User2的构成。那末为什么可以控制类的构成呢?metaclass相关博客: https://www.cnblogs.com/xybaby/p/7927407.html b.元类的建立次第建立类的时候,会去找metaclass这个属性。末端都找不到metaclass的时候,才会挪用type去建立类。c.什么时候用元类将建立user的new进程,托给元类。而不必要自己来做。
六. 实现简易django的orm
1.想要实现的成果
什么是orm?
即Object-Relationl Mapping,它的感化是在关系型数据库和工具之间作一个映照,这样,我们在具体的操纵数据库的时候,就不必要再去和复杂的SQL语句打交道,只要像平常操为难刁难象一样操纵它便可以了 。
具体的orm和django这类web框架的orm的计划自行查找材料哦~
我们想要实现类似于django中建立表对应的类的方式:
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息 1525498-20191202143826406-316588922

所以必要实现的有:CharField类  IntField类  而且能实现save来insert。能把User类中界说的属性举行对应,Meta里的属性能被特定处置赏罚。
2.全部实现步伐
a.首先 IntField必要举行初始化、实现对参数举行检查。让InterField称为int属性描摹符。同理,Charfield也是。
  1. class InterField:    def __init__(self,value,min_length=None,max_length=None):        self._value=value        self._min_value=min_length        self._max_value=max_length        if self._min_value is not None:            if not isinstance(self._min_value,numbers.Integral):                raise ValueError("Value Must be Intergral")            elif self._min_value < 0:                raise ValueError("Value Must large than 0")        if self._max_value is not None:            if not isinstance(self._max_value,numbers.Integral):                raise ValueError("Value must be Intergral")            elif self._max_value  self._max_length:            raise ValueError("Value's length must less than max length")
复制代码

b.界说元类来设备特定的属性和方式
重点是,建立一个元类,来指定建立User的时候必要设定的很多属性,例如meta和save。在User类中是没有分析这些属性怎样去设定、限制和用法的。而我们必要在建立User的时候,注册进很多自己的属性到User里来。比如django中,天生一个django中的表的时候,meta默许有很多属性是被设定了的,才会有我们建立一个表的类,只要设定key,value,django就自动帮助把对应的属性和功用建立好了。django中的大略设定:
  1. class ModelBase(type):"""Metaclass for all models.""" def __new__(cls, name, bases, attrs, **kwargs):    super_new = super().__new__    # Also ensure initialization is only performed for subclasses of Model    # (excluding Model class itself).    parents = [b for b in bases if isinstance(b, ModelBase)]    if not parents:        return super_new(cls, name, bases, attrs)    # Create the class.    module = attrs.pop('__module__')    new_attrs = {'__module__': module}    classcell = attrs.pop('__classcell__', None)    if classcell is not None:        new_attrs['__classcell__'] = classcell        attr_meta = attrs.pop('Meta', None)    # Pass all attrs without a (Django-specific) contribute_to_class()    # method to type.__new__() so that they're properly initialized    # (i.e. __set_name__()).    contributable_attrs = {}    for obj_name, obj in list(attrs.items()):        if _has_contribute_to_class(obj):            contributable_attrs[obj_name] = obj        else:            new_attrs[obj_name] = obj    new_class = super_new(cls, name, bases, new_attrs, **kwargs)    abstract = getattr(attr_meta, 'abstract', False)    meta = attr_meta or getattr(new_class, 'Meta', None)    base_meta = getattr(new_class, '_meta', None)  app_label = None# Look for an application configuration to attach the model to.  app_config = apps.get_containing_app_config(module)  if getattr(meta, 'app_label', None) is None:   if app_config is None:      if not abstract:      raise RuntimeError(        "Model class %s.%s doesn't declare an explicit "        "app_label and isn't in an application in "        "INSTALLED_APPS." % (module, name)        )    else:      app_label = app_config.label......
复制代码
我们模拟User间接设备它的元类为 modelMetaClass。而且再元类中实现__new__来对传进去的参数做处置赏罚。首先用元类的__new__来打印传递到__new__中的参数。
http://www.waysfocus.com/https://www.cnblogs.com/file:///C:/Users/dall/AppData/Local/Temp/enhtmlclip/Image(10).png
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息
http://www.waysfocus.com/https://www.cnblogs.com/file:///C:/Users/dall/AppData/Local/Temp/enhtmlclip/Image(11).png
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息
可以瞥见args的列传进去的底子就是name(类名)、bases、attrs(属性dict)。将参数用这三个变量取代。与django中设备的变量同等。
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息 1525498-20191202162412366-1453683375
对传递进去的attrs举行操纵,假如是在User内界说的charfield、interfield这类典范的字段,间接用__new__天生对应的key、value。可是对User类中界说的meta这类属性,对里面的一些属性的界说就必要做对应的处置赏罚。又由于我们想把InterField、CharField这类属性描摹符作为key,value存储,meta属性里的一些字段做特定处置赏罚,所以我们让各类属性描摹符类继续同一个Field来判定能否都是Field类来做同一key value处置赏罚。在User继续了修改过的元类以后。再User类中界说init,就能再pycharm中看到User中的变量。
  1. class Field:    passclass ModelMetaClass(type):    def __new__(cls, name, bases, attrs, **kwargs):        fields=dict()        for key,value in attrs.items():            if isinstance(value,Field):                fields[key]=value        attrs_meta=attrs.get("Meta",None)        _meta={}        db_table=name.lower()        if attrs_meta is not None:            table=getattr(attrs_meta,"db_table",None)            if table is not None:                db_table=table        attrs["db_table"]=db_table        attrs["_meta"]=attrs_meta        attrs["fields"]=fields        del fields["Meta"]        return super().__new__(cls,name, bases, attrs,**kwargs)
复制代码
debug以后的成果:
我的关键词 PythonI/O进阶进修笔记_7.python静态属性,__new__和__init__和元类编程(  热门消息 1525498-20191202163125497-201182145


c.界说User类的父类
可是在我们现实利用的时候,不大要每个User去界说__init__函数,save函数这样,所以我们就用一个modle父类,让User这些类来继续。必要留意的是:假如界说一个父类BaseModel,必要在BaseModel继续的元类中判定假如传进来的name是BaseModel,就间接__new__便可以了。由于在BaseModel中,是没有界说fields这些工具的。而且在父类中,界说好save方式。末端完整的代码为:
  1. import numbersclass Field:    passclass InterField(Field):    def __init__(self,db_column=None,min_value=None,max_value=None):        self._min_value=min_value        self._max_value=max_value        self.db_column=db_column        if self._min_value is not None:            if not isinstance(self._min_value,numbers.Integral):                raise ValueError("Value Must be Intergral")            elif self._min_value < 0:                raise ValueError("Value Must large than 0")        if self._max_value is not None:            if not isinstance(self._max_value,numbers.Integral):                raise ValueError("Value must be Intergral")            elif self._max_value  self._max_length:            raise ValueError("Value's length must less than max length")class ModelMetaClass(type):    def __new__(cls, name, bases, attrs, **kwargs):        if name=="BaseModel":            super().__new__(cls,name,bases,attrs,**kwargs)        fields=dict()        for key,value in attrs.items():            if isinstance(value,Field):                fields[key]=value        attrs_meta=attrs.get("Meta",None)        _meta={}        db_table=name.lower()        if attrs_meta is not None:            table=getattr(attrs_meta,"db_table",None)            if table is not None:                db_table=table        attrs["db_table"]=db_table        attrs["_meta"]=attrs_meta        attrs["fields"]=fields        if attrs_meta:            del attrs["Meta"]        return super().__new__(cls,name, bases, attrs,**kwargs)class ModelBase(metaclass=ModelMetaClass):    def __init__(self,*args,**kwargs):        for key,value in kwargs.items():            setattr(self,key,value)        return super().__init__()    def save(self):        fields=[]        values=[]        for key,value in self.fields.items():            db_column=value.db_column            if db_column is None:                db_column=key.lower()            fields.append(db_column)            value=getattr(self,key)            values.append(str(value))        sql = "insert {db_table}({fields}) value({values})".format(db_table=self._meta.db_table,fields=",".join(fields),values=",".join(values))        passclass User(ModelBase):    name=CharField(max_length=10)    age=InterField(min_value=0,max_value=100)    class Meta:        db_table="user"    def _test(self):        print("_test:",self.age)if __name__=="__main__":    user=User()    user.name="bobby"    user.age=23    user._test()    user.save()
复制代码


  

免责声明:假如加害了您的权益,请联系站长,我们会实时删除侵权内容,感谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright © 2006-2014 淄博新闻网-淄博日报 淄博晚报 淄博财经新报 掌中淄博 淄博专业新闻资讯发布网站 版权所有 法律顾问:高律师 客服电话:0791-88289918
技术支持:迪恩网络科技公司  Powered by Discuz! X3.2
快速回复 返回顶部 返回列表