十二、元类和ORM的实现

2023-10-11 13:52
文章标签 实现 元类 十二 orm

本文主要是介绍十二、元类和ORM的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 一、元类
    • 1.1 动态创建类
    • 1.2 使用type创建类
    • 1.3 使用type创建带有方法的类
    • 1.4 __metaclass__属性
    • 1.5 自定义元类
  • 二、ORM的实现
    • 2.1 通过元类实现简单数据库insert操作

一、元类

元类是面向对象编程中的一个概念,用于创建类的类。在Python中,一切都是对象,包括类本身。而元类就是用来创建这些类的。
元类提供了控制类创建过程的功能,它可以在类被定义时自动执行一些操作。可以将元类视为类的模板,它定义了类的行为、属性和方法。

1.1 动态创建类

因为类也是对象,你可以在运行时动态的创建它们,就像其他任何对象一样。首先,你可以在函数中创建类,使用class关键字即可,Python解释器在执行的时候就会创建一个对象。

def choose_class(name):if name == 'foo':# 定义一个Foo类,同时会创建一个Foo的对象, 注意不是Foo的实例对象.class Foo(object):passreturn Foo  # 注意:返回的是类, 而不是类的实例else:class Bar(object):passreturn Barif __name__ == '__main__':foo_class = choose_class('foo')print("foo_class===> " + str(foo_class))# 创建Foo类的实例对象foo_obj = foo_class()print("foo_obj===> " + str(foo_obj))

输出结果:

foo_class===> <class '__main__.choose_class.<locals>.Foo'>
foo_obj===> <__main__.choose_class.<locals>.Foo object at 0x101208a60>

但这还不够动态,因为你仍然需要自己编写整个类的代码。由于类也是对象,所以它们必须是通过什么东西来生成的才对。

1.2 使用type创建类

当你使用class关键字时,Python解释器自动创建这个对象。但就和Python中的大多数事情一样,Python仍然提供给你手动处理的方法。内建函数type除了可以查看对象的类型是什么, 它还可以用来动态的创建类.
语法如下:

type(类名, 由父类名称组成的元组(针对继承的情况,可以为空),包含属性和方法的字典(名称和值))
  • 参数2是元组中是父类的名字,而不是字符串
  • 参数3是添加的类属性,并不是实例属性, 此外还能添加实例方法、类方法、静态方法。
    用法示例:
# 定了一个Test类, 参数2指定继承object类,参数3指定类的属性
Test = type("Test", (object,), {'bar':True})t = Test()
print(t.bar)

上面定义类的方式相当于:

class Test(object):bar = True

1.3 使用type创建带有方法的类

@classmethod
def class_method(cls, value):print("class_method:" + cls.class_attr + " " + value)@staticmethod
def static_method(value):print("static_method:" + value)def obj_method(self):print("obj_method:" + self.class_attr)# 定义class
TestClass = type("Test", (object,),{'class_attr': 'hello', 'class_method': class_method, 'static_method': static_method,'obj_method': obj_method})# 创建实例
test = TestClass()
# 调用实例方法
test.obj_method()# 调用类方法
TestClass.class_method('通过类名调用类方法')
test.class_method('通过实例对象调用类方法')# 调用静态方法
TestClass.static_method('通过类名调用静态方法')
test.static_method('通过实例对象调用静态方法')

1.4 __metaclass__属性

你可以在定义一个类的时候为其添加__metaclass__属性。

class Foo(object):__metaclass__ = something…...省略...

如果你这么做了,Python就会用元类来创建类Foo。小心点,这里面有些技巧。你首先写下class Foo(object),但是类Foo还没有在内存中创建。Python会在类的定义中寻找__metaclass__属性,如果找到了,Python就会用它来创建类Foo,如果没有找到,就会用内建的type来创建这个类。
当你写如下代码时 :

class Foo(Bar):pass

Python做了如下的操作:

  1. Foo中有__metaclass__这个属性吗?如果是,Python会通过__metaclass__创建一个名字为Foo的类(对象)
  2. 如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。
  3. 如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
  4. 如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。
    现在的问题就是,你可以在__metaclass__中放置些什么代码呢?答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type。

1.5 自定义元类

元类的主要目的就是为了当创建类时能够自动地改变类。
假设你想让你的模块里所有的类的属性都是大写形式。有好几种方法可以办到,但其中一种就是通过在模块级别设定__metaclass__。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。
幸运的是,__metaclass__实际上可以被任意调用,它并不需要是一个正式的类。所以,我们这里就先以一个简单的函数作为例子开始。
(1) Python2中

# -*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):# class_name 会保存类的名字 Foo# class_parents 会保存类的父类 object# class_attr 会以字典的方式保存所有的类属性# 遍历属性字典,把不是__开头的属性名字变为大写new_attr = {}for name, value in class_attr.items():if not name.startswith("__"):new_attr[name.upper()] = value# 调用type来创建一个类return type(class_name, class_parents, new_attr)class Foo(object):__metaclass__ = upper_attr  # 设置Foo类的元类为upper_attrbar = 'bip'print(hasattr(Foo, 'bar')) # False
print(hasattr(Foo, 'BAR')) # Truef = Foo()
print(f.BAR) # bip

(2) 在Python3中

# -*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):# 遍历属性字典,把不是__开头的属性名字变为大写new_attr = {}for name, value in class_attr.items():if not name.startswith("__"):new_attr[name.upper()] = value# 调用type来创建一个类return type(class_name, class_parents, new_attr)# 定义类的时候指定metaclass
class Foo(object, metaclass=upper_attr):bar = 'bip'print(hasattr(Foo, 'bar')) # False
print(hasattr(Foo, 'BAR')) # Truef = Foo()
print(f.BAR) # bip

现在让我们再做一次,这一次用一个真正的class来当做元类。

# coding=utf-8class UpperAttrMetaClass(type):# __new__ 是在__init__之前被调用的特殊方法# __new__是用来创建对象并返回之的方法# 而__init__只是用来将传入的参数初始化给对象# 你很少用到__new__,除非你希望能够控制对象的创建# 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__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__方法# 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'))  # 输出:Truef = Foo()
print(f.BAR)  # 输出:'bip'

二、ORM的实现

ORM 是 python编程语言后端web框架 Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM。
一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应MySQL语句。
所谓的ORM就是让开发者在操作数据库的时候,能够像操作对象时通过xxxx.属性=yyyy一样简单,这是开发ORM的初衷。

2.1 通过元类实现简单数据库insert操作

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)# 处理sql的insert语句生成
class Model(object, metaclass=ModelMetaclass):def __init__(self, **kwargs):for name, value in kwargs.items():print('__init__: %s ==> %s' % (name, value))# 给属性设置值setattr(self, name, value)def save(self):fields = []args = []for k, v in self.__mappings__.items():# 字段取元组中的第一个作为sql的字段fields.append(v[0])# 字段对应的值通过getattr方法获取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)# 继承父类Model
class User(Model):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"u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
u.save()

运行结果如下:

Found mapping: uid ==> ('uid', 'int unsigned')
Found mapping: name ==> ('username', 'varchar(30)')
Found mapping: email ==> ('email', 'varchar(30)')
Found mapping: password ==> ('password', 'varchar(30)')
__init__: uid ==> 12345
__init__: name ==> Michael
__init__: email ==> test@orm.org
__init__: password ==> my-pwd
SQL: insert into User (uid,username,email,password) values (12345,'Michael','test@orm.org','my-pwd')

这篇关于十二、元类和ORM的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/188518

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

基于Springboot + vue 的抗疫物质管理系统的设计与实现

目录 📚 前言 📑摘要 📑系统流程 📚 系统架构设计 📚 数据库设计 📚 系统功能的具体实现    💬 系统登录注册 系统登录 登录界面   用户添加  💬 抗疫列表展示模块     区域信息管理 添加物资详情 抗疫物资列表展示 抗疫物资申请 抗疫物资审核 ✒️ 源码实现 💖 源码获取 😁 联系方式 📚 前言 📑博客主页:

探索蓝牙协议的奥秘:用ESP32实现高质量蓝牙音频传输

蓝牙(Bluetooth)是一种短距离无线通信技术,广泛应用于各种电子设备之间的数据传输。自1994年由爱立信公司首次提出以来,蓝牙技术已经经历了多个版本的更新和改进。本文将详细介绍蓝牙协议,并通过一个具体的项目——使用ESP32实现蓝牙音频传输,来展示蓝牙协议的实际应用及其优点。 蓝牙协议概述 蓝牙协议栈 蓝牙协议栈是蓝牙技术的核心,定义了蓝牙设备之间如何进行通信。蓝牙协议

python实现最简单循环神经网络(RNNs)

Recurrent Neural Networks(RNNs) 的模型: 上图中红色部分是输入向量。文本、单词、数据都是输入,在网络里都以向量的形式进行表示。 绿色部分是隐藏向量。是加工处理过程。 蓝色部分是输出向量。 python代码表示如下: rnn = RNN()y = rnn.step(x) # x为输入向量,y为输出向量 RNNs神经网络由神经元组成, python

利用Frp实现内网穿透(docker实现)

文章目录 1、WSL子系统配置2、腾讯云服务器安装frps2.1、创建配置文件2.2 、创建frps容器 3、WSL2子系统Centos服务器安装frpc服务3.1、安装docker3.2、创建配置文件3.3 、创建frpc容器 4、WSL2子系统Centos服务器安装nginx服务 环境配置:一台公网服务器(腾讯云)、一台笔记本电脑、WSL子系统涉及知识:docker、Frp

基于 Java 实现的智能客服聊天工具模拟场景

服务端代码 import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;public class Serv