成都网站建设服务网络营销推广方案思路
成都网站建设服务,网络营销推广方案思路,网站还难做啊,建设网站企业运营Photo byJoyous From Lofter本文目录类是如何产生的如何使用type创建类理解什么是元类使用元类的意义元类实战#xff1a;ORM.1. 类是如何产生的类是如何产生#xff1f;这个问题肯定很傻。实则不然#xff0c;很多人只知道使用继承的表面形式来创建一个类#xff0c;却不知…Photo byJoyous From Lofter本文目录类是如何产生的如何使用type创建类理解什么是元类使用元类的意义元类实战ORM.1. 类是如何产生的类是如何产生这个问题肯定很傻。实则不然很多人只知道使用继承的表面形式来创建一个类却不知道其内部真正的创建是由type来创建的。type这不是判断对象类型的函数吗是的type通常用法就是用来判断对象的类型。但除此之外他最大的用途是用来动态创建类。当Python扫描到class的语法的时候就会调用type函数进行类的创建。.2. 如何使用type创建类首先type()需要接收三个参数类的名称若不指定也要传入空字符串父类注意以tuple的形式传入若没有父类也要传入空tuple()默认继承object绑定的方法或属性注意以dict的形式传入来看个例子1# 准备一个基类(父类)2class BaseClass:3 def talk(self):4 print(i am people)56# 准备一个方法7def say(self):8 print(hello)910# 使用type来创建User类11User type(User, (BaseClass, ), {name:user, say:say}).3. 理解什么是元类什么是类可能谁都知道类就是用来创建对象的「模板」。那什么是元类呢一句话通俗来说元类就是创建类的「模板」。为什么type能用来创建类因为它本身是一个元类。使用元类创建类那就合理了。type是Python在背后用来创建所有类的元类我们熟知的类的始祖object 也是由type创建的。更有甚者连type自己也是由type自己创建的这就过份了。1 type(type)23 type(object45 type(int)67 type(str)8如果要形象的来理解的话就看下面这三行话。1str用来创建字符串对象的类。2int是用来创建整数对象的类。3type是用来创建类对象的类。反过来看1一个实例的类型是类2一个类的类型是元类3一个元类的类型是type来看下实例1#Python3.72 class MetaPerson(type):3... pass4...5 class Person(metaclassMetaPerson):6... pass7...8 Tom Person()9 print(type(Tom))1011 print(type(Tom.__class__))1213 print(type(Tom.__class__.__class__))14上面是一个简单的示例。下面看一个稍微完整的1# 注意要从type继承2class BaseClass(type):3 def __new__(cls, *args, **kwargs):4 print(in BaseClass)5 return super().__new__(cls, *args, **kwargs)67class User(metaclassBaseClass):8 def __init__(self, name):9 self.name name1011user User(wangbm).4. 使用元类的意义正常情况下我们都不会使用到元类。但是这并不意味着它不重要。假如某一天我们需要写一个框架很有可能就需要用到元类。但是为什么要用它呢不要它会怎样经过我的总结元类的作用过程如下拦截类的创建拦截下后进行修改修改完后返回修改后的类很明显使用元类是要对类进行定制修改。使用元类来动态生成元类的实例而99%的开发人员是不需要动态修改类的因为这应该是框架才需要考虑的事。但是这样说你一定不会服气到底元类用来干什么其实元类的作用就是创建API一个最典型的应用是 Django ORM。.5. 元类实战ORM使用过Django ORM的人都知道有了ORM使得我们操作数据库变得异常简单。ORM的一个类(User)就对应数据库中的一张表。id,name,email,password 就是字段。1class User(BaseModel):2 id IntField(id)3 name StrField(username)4 email StrField(email)5 password StrField(password)67 class Meta:8 db_table user如果我们要插入一条数据我们只需这样做1# 实例化成一条记录2u User(id20180424, namexiaoming,3 emailxiaoming163.com, passwordabc123)45# 保存这条记录6u.save()通常用户层面只需要懂应用就像上面这样操作就可以了。但是今天我并不是来教大家如何使用ORM我们是用来探究ORM内部究竟是如何实现的。我们也可以自己写一个简易的ORM。从上面的User类中我们看到StrField和IntField从字段意思上看我们很容易看出这代表两个字段类型。字段名分别是id,username,email,password。StrField和IntField在这里的用法叫做属性描述符如果对这个不了解的可以查看文章底部的参考文章也是我写的。简单来说呢属性描述符可以实现对属性值的类型范围等一切做约束意思就是说变量id只能是int类型变量name只能是str类型否则将会抛出异常。那如何实现这两个属性描述符呢请看代码。1import numbers23class Field:4 pass56class IntField(Field):7 def __init__(self, name):8 self.name name9 self._value None1011 def __get__(self, instance, owner):12 return self._value1314 def __set__(self, instance, value):15 if not isinstance(value, numbers.Integral):16 raise ValueError(int value need)17 self._value value1819class StrField(Field):20 def __init__(self, name):21 self.name name22 self._value None2324 def __get__(self, instance, owner):25 return self._value2627 def __set__(self, instance, value):28 if not isinstance(value, str):29 raise ValueError(string value need)30 self._value value我们看到User类继承自BaseModel这个BaseModel里定义了数据库操作的各种方法譬如我们使用的save函数也可以放在这里面的。所以我们就可以来写一下这个BaseModel类1class BaseModel(metaclassModelMetaClass):2 def __init__(self, *args, **kw):3 for k,v in kw.items():4 # 这里执行赋值操作会进行数据描述符的__set__逻辑5 setattr(self, k, v)6 return super().__init__()78 def save(self):9 db_columns[]10 db_values[]11 for column, value in self.fields.items():12 db_columns.append(str(column))13 _valuestr(getattr(self, column))14 db_values.append(\_value\)15 sql insert into {table} ({columns}) values({values}).format(16 tableself.db_table,17 columns,.join(db_columns),18 values,.join(db_values))19 # mysql_execute 函数可以自己写。调用驱动插入到数据库20 # 查看完整代码请点击文章底部查看原文21 mysql_execute(sql)从BaseModel类中save函数里面有几个新变量fields: 存放所有的字段属性db_table表名注意上面代码中class BaseModel(metaclassModelMetaClass)请替换成class BaseModel(object) 再阅读。这样更贴合思考顺序。我们思考一下这个u实例的创建过程type - object - BaseModel - User - u这里会有几个问题。init的参数是User实例时传入的所以传入的id是int类型name是str类型。看起来没啥问题若是这样我上面的数据描述符就失效了不能起约束作用。所以我们希望init接收到的id是IntField类型name是StrField类型。同时我们希望这些字段属性能够自动归类到fields变量中。因为做为BaseModel它可不是专门为User类服务的它还要兼容各种各样的表。不同的表表里有不同数量不同属性的字段这些都要能自动类别并归类整理到一起。这是一个ORM框架最基本的。我们希望对表名有两种选择一个是User中若指定Meta信息比如表名就以此为表名若未指定就以类名的小写 做为表名。虽然BaseModel可以直接取到User的db_table属性但是如果在数据库业务逻辑中加入这段复杂的逻辑显然是很不优雅的。上面这几个问题其实都可以通过元类的__new__函数来完成。元类的__new__和普通类的可不一样元类的__new__可以获取到上层类的一切属性和方法包括类名魔法方法。而普通类的__new__ 只能获取到实例化时外界传入的属性。下面就来看看如何用元类来解决这些问题呢请看代码。1class ModelMetaClass(type):2 def __new__(cls, name, bases, attrs):3 if name BaseModel:4 # 第一次进入__new__是创建BaseModel类nameBaseModel5 # 第二次进入__new__是创建User类及其实例nameUser6 return super().__new__(cls, name, bases, attrs)78 # 根据属性类型取出字段9 fields {k:v for k,v in attrs.items() if isinstance(v, Field)}1011 # 如果User中有指定Meta信息比如表名就以此为准12 # 如果没有指定就默认以 类名的小写 做为表名比如User类表名就是user13 _meta attrs.get(Meta, None)14 db_table name.lower()15 if _meta is not None:16 table getattr(_meta, db_table, None)17 if table is not None:18 db_table table1920 # 注意原来由User传递过来的各项参数attrs最好原模原样的返回21 # 如果不返回有可能下面的数据描述符不起作用22 # 除此之外我们可以往里面添加我们自定义的参数23 attrs[db_table] db_table24 attrs[fields] fields25 return super().__new__(cls, name, bases, attrs)至此我们的简易ORM就已经成型。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/86887.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!