本篇主要介绍元类,为什么说一切皆对象;如何动态的创建类等;以及ORM,即什么是ORM等知识

一、元类

  1.1 在Python中一切皆对象

  在学习元类中我们首先需要了解一个概念-- python中一切皆对象,那么为什么这么说呢?

  扩展:通过globals()--查看所有的全局变量,当我们定义全局变量时,python会将这些全局变量存放至一个字典中;而其中包含 __builtin__内嵌模块,当我们 globals()["__builtin__"].__dict__,可以看到内嵌模块中的所有内置函数或者内置模块即其对应的引用指针,例如:(只截取了小部分)

  

  类也是对象,当我们定义一个类,其实也是通过另外一个类(type)类创建一个实例对象,只是这个对象比较特殊,拥有着创建实例对象的特殊功能。而可能你就会问了,那么type是由什么类实例化得到的呢? type就是元类,其自身实例对象了其自身。

  

  1.2  使用type创建类

  通常我们定义类有使用以下的方式创建类:

>>> class ObjectCreator(object):
… pass

  而同时 我们也可以通过type实例化得到类对象,其效果是一摸一样的,这种创建类的方式我们称为动态的创建类;

class Test1(object):
name="alex"
age = 30 Test2 = type("Test2",(object,),{"name":"alex","age":30})

  以上两种形式定义的类是完全一样的(除了类名),前者是通过关键字定义的类对象,而后者是通过type类实例化得到的类对象;

  当然也可以为该类定义实例方法、类方法、以及静态方法等,例如:

# 析构方法
def __init__(self,name,age):
self.name = name
self.age = age # 实例方法
def foo(self):
print("in the foo",self) # 类方法
@classmethod
def bar(cls):
print("in the foo",cls) #静态方法
@staticmethod
def cal():
print("in the cal") Test =type("Test",(object,),{"info":"这是一个type实例化的类","foo":foo,"bar":bar,"cal":cal,"__init__":__init__}) test = Test("alex",22)
test.bar()
test.foo()
test.cal()

  1.3  什么是元类?

  元类:通俗来将 元类就是可以创建类的"东西";准确来说:元类就是可以实例化得到类对象的一种类,上述的type类就是元类;

MyClass = MetaClass()  # 使用元类创建出一个对象,这个对象称为“类”
my_object = MyClass() # 使用“类”来创建出实例对象

 即:

  1、可以这样理解:元类通过实例化得到类对象,类通过实例化得到实例化对象。

  例如上述你看到的:

MyClass = type('MyClass', (), {})

  这种方式便是:通过元类type传入参数(参数1-- 得到类对象的名称 , 参数二----该类对象的父类们的父类名,参数三-- 存储该类对象的类属性、类方法),即便是通过这种方式得到一个类对象。

  Python中所有的东西,注意,我是指所有的东西——都是对象。这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来,这个类就是type。

  1.4  自定义元类

  在上述我们知道可以通过type动态的创建类,那么我们是否可以定义一个类,利用继承或者组合的方式,通过派生来为创建的类对象增设一些新的功能呢?

   1.4.1 metaclass

  在自定义元类之前我们需要了解以下 metaclass:

class MyType(type):
def __new__(cls,name,prants,attrs):
print("in the MyType..")
return type(name,prants,attrs)
pass class Foo(object,metaclass=MyType):
pass print(Foo.__class__)

  Python做了如下的操作:

  1. Foo中有 metaclass=MyType 这个属性吗?如果是,Python会通过 meteclass=MyType 创建一个名字为Foo的类(对象)
  2. 如果Python没有找到 metaclass=xxx ,它会继续在Bar(父类)中寻找metaclass=xxx 属性,并尝试做和前面同样的操作。
  3. 如果Python在任何父类中都找不到 metaclass=xxx ,它就会在模块层次中去寻找metaclass=xxx ,并尝试做同样的操作。
  4. 如果还是找不到metaclass=xxx ,Python就会用内置的type来创建这个类对象。

  1.4.2 自定义元类

  自定义元类的主要目的就是为了当创建类时能够自动地改变类。接下来我们实现 元类把所有的属性都改成大写形式,即相当于为原来通过type类创建类对象添加或修改其方法,而不改变源代码的效果,优点类似于装饰器的效果;

class UpperAttrMetaClass(type):
# __new__ 是在__init__之前被调用的特殊方法
# __new__是用来创建对象并返回之的方法
# 而__init__只是用来将传入的参数初始化给对象
# 你很少用到__new__,除非你希望能够控制对象的创建
# 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
# 如果你希望的话,你也可以在__init__中做些事情
# 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
def __new__(cls, class_name, class_parents, class_attr):
# 遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value # 方法1:通过'type'来做类对象的创建
return type(class_name, class_parents, new_attr) # 方法2:复用type.__new__方法
# 这就是基本的OOP编程,没什么魔法
# return type.__new__(cls, class_name, class_parents, new_attr) # python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
bar = 'bip' # python2的用法
# class Foo(object):
# __metaclass__ = UpperAttrMetaClass
# bar = 'bip' print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True f = Foo()
print(f.BAR)
# 输出:'bip'

 其本质是:

  就是这样,除此之外,关于元类真的没有别的可说的了。但就自定义元类本身而言,它们其实是很简单的:

  1. 拦截类的创建
  2. 修改类
  3. 返回修改之后的类

二、ORM

 2.1 什么是ORM?

  ORM 是 python编程语言后端web框架 Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM。

  一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,用它实例化传入的实例属性作为记录,当对这个实例对象操作时,能够对应MySQL语句。

  

  

  1. 所谓的ORM就是让开发者在操作数据库的时候,能够像操作对象时通过xxxx.属性=yyyy一样简单,这是开发ORM的初衷;
  2. 只不过ORM的实现较为复杂,Django中已经实现了 很复杂的操作,本节知识 主要通过完成一个 insert相类似的ORM,理解其中的道理就就可以了;例如:
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
# 判断是否需要保存
for k, v in attrs.items():
# 判断是否是指定的StringField或者IntegerField的实例对象
if isinstance(v, tuple):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v # 删除这些已经在字典中存储的属性
for k in mappings.keys():
attrs.pop(k) # 将之前的uid/name/email/password以及对应的对象引用、类名字
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
attrs['__table__'] = name # 假设表名和类名一致
return type.__new__(cls, name, bases, attrs) class User(metaclass=ModelMetaclass):
uid = ('uid', "int unsigned")
name = ('username', "varchar(30)")
email = ('email', "varchar(30)")
password = ('password', "varchar(30)")
# 当指定元类之后,以上的类属性将不在类中,而是在__mappings__属性指定的字典中存储
# 以上User类中有
# __mappings__ = {
# "uid": ('uid', "int unsigned")
# "name": ('username', "varchar(30)")
# "email": ('email', "varchar(30)")
# "password": ('password', "varchar(30)")
# }
# __table__ = "User"
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value) def save(self):
fields = [] # 用来存储获取的字段名
args = [] # 用来存储值
for k, v in self.__mappings__.items():
fields.append(v[0])
args.append(getattr(self, k, None)) # 由于传入的值需为字符串类型则进行转换
args_temp = list()
for temp in args:
# 判断入如果是数字类型
if isinstance(temp, int):
args_temp.append(str(temp))
elif isinstance(temp, str):
args_temp.append("""'%s'""" % temp)
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))
print('SQL: %s' % sql) u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()

  优化如下:

class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
# 判断是否需要保存
for k, v in attrs.items():
# 判断是否是指定的StringField或者IntegerField的实例对象
if isinstance(v, tuple):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v # 删除这些已经在字典中存储的属性
for k in mappings.keys():
attrs.pop(k) # 将之前的uid/name/email/password以及对应的对象引用、类名字
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
attrs['__table__'] = name # 假设表名和类名一致
return type.__new__(cls, name, bases, attrs) class Model(object, metaclass=ModelMetaclass):
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value) def save(self):
fields = []
args = []
for k, v in self.__mappings__.items():
fields.append(v[0])
args.append(getattr(self, k, None)) args_temp = list()
for temp in args:
# 判断入如果是数字类型
if isinstance(temp, int):
args_temp.append(str(temp))
elif isinstance(temp, str):
args_temp.append("""'%s'""" % temp)
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))
print('SQL: %s' % sql) class User(Model):
uid = ('uid', "int unsigned")
name = ('username', "varchar(30)")
email = ('email', "varchar(30)")
password = ('password', "varchar(30)") u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()

  over~~~

  

04 -- 元类和ORM的更多相关文章

  1. Python 元类实现ORM

    ORM概念 ORM(Object Ralational Mapping,对象关系映射)用来把对象模型表示的对象映射到基于 SQL  的关系模型数据库结构中去.这样,我们在具体的操作实体对象的时候,就不 ...

  2. 元类实现ORM

    1. ORM是什么 ORM 是 python编程语言后端web框架 Django的核心思想,"Object Relational Mapping",即对象-关系映射,简称ORM. ...

  3. 使用元类 编写ORM

    元类 一句话: 元类定制类的创建行为 知识点 1.类的创建: python这种动态语言,函数和类的定义,不是编译时定义的,而是运行时动态创建的. Python解释器遇到class定义时,仅仅是扫描一下 ...

  4. 元类、orm

    目录 一.内置函数exec 二.元类 1. 什么是元类 2. 元类的作用 3. 创建类的两种方法 4. 怎么自定义创建元类 三.ORM 1. ORM中可能会遇到的问题 2. ORM中元类需要解决的问题 ...

  5. 元类应用ORM实现

    首先看下一个简单的例子 # 需求 import numbers class Field: pass class IntField(Field): # 数据描述符 def __init__(self, ...

  6. python-元类和使用元类实现简单的ORM

    元类 面向对象中,对象是类的实例,即对象是通过类创建出来的,在python中,一切皆对象,同样,类也是一个对象,叫做类对象,只是这个类对象拥有创建其子对象(实例对象)的能力.既然类是对象,那么类是通过 ...

  7. Python面向对象篇之元类,附Django Model核心原理

    关于元类,我写过一篇,如果你只是了解元类,看下面这一篇就足够了. Python面向对象之类的方法和属性 本篇是深度解剖,如果你觉得元类用不到,呵呵,那是因为你不了解Django. 在Python中有一 ...

  8. 神级程序员通过两句话带你完全掌握Python最难知识点——元类!

    千万不要被所谓"元类是99%的python程序员不会用到的特性"这类的说辞吓住.因为 每个中国人,都是天生的元类使用者 学懂元类,你只需要知道两句话: 道生一,一生二,二生三,三生 ...

  9. Python中的元类

    从前面"Python对象"文章中了解到,在Python中一切都是对象,类可以创建实例对象,但是类本身也是对象. class C(object): pass c = C() prin ...

随机推荐

  1. LeetCode_443. String Compression

    443. String Compression Easy Given an array of characters, compress it in-place. The length after co ...

  2. Spring MVC -- MVC设计模式(演示4个基于MVC框架的案例)

    对于简单的Java Web项目,我们的项目仅仅包含几个jsp页面,由于项目比较小,我们通常可以通过链接方式进行jsp页面间的跳转. 但是如果是一个中型或者大型的项目,上面那种方式就会带来许多维护困难, ...

  3. knuth洗牌算法

    首先来思考一个问题: 设计一个公平的洗牌算法 1. 看问题,洗牌,显然是一个随机算法了.随机算法还不简单?随机呗.把所有牌放到一个数组中,每次取两张牌交换位置,随机 k 次即可. 如果你的答案是这样, ...

  4. vue -- router路由跳转错误 , NavigationDuplicated

    vue-router ≥3.0版本回调形式以及改成promise api的形式了,返回的是一个promise,如果路由地址跳转相同, 且没有捕获到错误,控制台始终会出现如图所示的警告 (注:3.0以下 ...

  5. [LeetCode] 752. Open the Lock 开锁

    You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: '0', '1', '2', '3', ...

  6. public interface ICloneable

    using System.Runtime.InteropServices; namespace System{ // // 摘要: // 支持克隆,即用与现有实例相同的值创建类的新实例. [ComVi ...

  7. 【视频开发】【计算机视觉】doppia编译之三:编译安装opencv库

    这里我介绍2种方法 (1)利用别人写好的脚本编译,相对来说省力一点  上Github下载别人写好的脚本文件,网址 https://github.com/jayrambhia/Install-OpenC ...

  8. springboot实战日记(一)数据库基本信息

    摘要:基于spring boot的后端实现,开发一个微信小程序点餐系统,主要是写写思路和遇到的问题以及分享读到的好文章. 项目分析: 1.角色划分,就是开有什么人使用这个系统,买家(手机端),卖家(p ...

  9. 基于thinkphp5框架做一个可以区别开发、测试、生产三种环境的配置加载

    在日常的开发测试中我们经常会遇到本地开发和测试或者线上配置参数不同的场景,必要你要是使用一个三方的支付,它的本地测试和线上的key值或者账号存在不同.最基本的做法是本地用测试参数,提交到测试的时候再改 ...

  10. Javaspring+mybit+maven中实现定时任务

    背景:在Javaspring中,定时的启动某一个任务时,使用@Scheduled来实现 Javaspring工程创建好之后,直接创建下面的class文件即可.具体的用法可参照 https://www. ...