22 元类技术(面向切片编程)|ORM的实现|抽象类与接口类

news2024/10/7 12:18:31

文章目录

  • 前情知识补充
    • hasattr 函数
    • setattr函数
    • getattr函数
    • join 函数
  • 元类技术
    • 使用type创建类
    • 什么是元类(概念总结)
    • \_\_metaclass\_\_属性
      • 使用metaclass 的函数方式进行创建类
      • 使用metaclass 的类方式进行创建类
    • 自定义元类
  • 元类实现ORM
  • 接口类与抽象类
    • 抽象类
    • 接口类
    • 注意点

前情知识补充

hasattr 函数

class ObjectCreator(object):
    pass

my_object = ObjectCreator()

# hasattr用来判断一个对象是否有某个属性,有就是True,没有就是false
print(hasattr(ObjectCreator, 'new_attribute'))

ObjectCreator.new_attribute = 'foo'  # 你可以为类增加属性

print(hasattr(ObjectCreator, 'new_attribute'))

输出:
在这里插入图片描述

setattr函数

这个函数是用来给对象赋属性以及对应的值的

使用的方式:

setattr(object 对象, name 字符串 对象属性, value 属性的值)
>>>class A(object):
...     bar = 1
... 
>>> a = A()
>>> getattr(a, 'bar')          # 获取属性 bar 值
1
>>> setattr(a, 'bar', 5)       # 设置属性 bar 值
>>> a.bar
5

getattr函数

参考链接

基本使用方式

getattr(object 对象, name 对象属性, default 如果不存在则返回的值)

一般用于由用户或者程序自动决定想要访问的属性名时,采用这种方法,并且省去try的异常检测,直接自定义返回值。

样例:

from typing import NamedTuple
 
class Person(NamedTuple):
    '''人类'''
    name: str
    age: int
    job: str
    weight: float
    height: float
 
alex = Person('Alex', 32, 'actor', 60, 178)
 
# 把用户输入的字符串赋值给变量attribute_name
attribute_name = input('''What do you want to know about Alex? 
Enter an attribute name>>>''')
# 注意,上述字符串被传进了这个函数作为第二个参数
# 第三个参数是属性不存在时返回的字符串
print(getattr(alex,attribute_name, 'Sorry, this attribute does not exist.'))

join 函数

参考链接链接

这边只介绍元组:


tuple1 = ('a','b','c')  #定义元组tuple1
'、'.join(tuple1)
输出: a、b、c
 
tuple2 = ('hello','peace','world')  #定义元组tuple2
' '.join(tuple2)
输出:hello peace world

元类技术

先介绍方法,再去介绍相关的概念,感觉比较好理解

使用type创建类

先是关于type的基础介绍:

创建出来的类名称 = type("创建出来的类名称", (元组内部放想要继承的类,), {"print_b": print_b, 字典放类函数})

样例见下:

class A(object):
    num = 100


def print_b(self):
    print(self.num)


@staticmethod
def print_static():
    print("----haha-----")


@classmethod
def print_class(cls):
    print(cls.num)


B = type("B", (A,), {"print_b": print_b, "print_static": print_static,
                     "print_class": print_class})
b = B()
b.print_b()
b.print_static()
b.print_class()

什么是元类(概念总结)

这是因为函数 type 实际上是一个元类。type 就是 Python 在背后用来创建所有类的元类。跟int 一样之所以type全是小写,就是根据于此,int是用来创建整形的变量,type就是用来创建类的类。

__metaclass__属性

python在创建类的时候会经过下面的步骤:

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

使用metaclass 的函数方式进行创建类

def upper_class(class_name, class_parent, class_function: dict):
    """
    这边实现的就是将类元素全部变成大写的
    """
    new_dict = dict()
    for key, function in class_function.items():
        if not key.startswith('__'):
            new_dict[key.upper()] = function

    return type(class_name, class_parent, new_dict)


class Test(object, metaclass=upper_class):
    a = 1


print(Test.a)
print(Test.A)

在这里插入图片描述
输出的结果:
在这里插入图片描述

使用metaclass 的类方式进行创建类

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
		# 值得关注的是需要用这种形式type.__new__而不是使用 type()
        return type.__new__(cls, class_name, class_parents, new_attr)


# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
    bar = 'bip'


print(Foo.BAR)

使用type.__new__而不使用type的原因:链接

自定义元类

正常人不需要,只有在想要看懂框架,特别是深度学习的时候需要搞懂这门技术,自己也不需要这么写OxO

“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python 界的领袖 Tim Peter”

元类实现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)

        # if name == 'User':
        #     attrs.pop('hello')
        
        # 将之前的uid/name/email/password以及对应的对象引用、类名字
        attrs['__mappings__'] = mappings  # 保存属性和列的映射关系
        attrs['__table__'] = name  # 假设表名和类名一致
        return super().__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()

建议一步一步调试看看函数的执行流程。

接口类与抽象类

抽象类的定义就是:作为微信支付宝的父类,定义了一个具有支付功能的设计类,但是又没有具体实现,需要子类去实现具体的功能的一种类。

接口类的定义就是:一个接口就是一个类,在这个类当中,我们尽量希望有少 或者 仅有一个方法,也即方法即类,在后面使用的时候,我们使用一个子类去继承一个个接口类,并且都将其实例化到各个类代码当中。

二者使用的场景不同:抽象类希望的是本身具有越多的属性越好,然后子类继承,实例化即可,而接口类希望的是本身方法越少越好,最好自己就是一个行为。

抽象类

同样也需要用到元类技术metaclass,以及需要额外导入一个包:
“from abc import abstractmethod, ABCMeta” 使用内部的装饰器@abstractmethod即可创建出一个抽象属性(意思就是子类需要将其定义其功能,而自己只需要写个名字)

from abc import abstractmethod, ABCMeta


# 使用了抽象方法的类,就是抽象类,Payment就是一个抽象类
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass


class Alipay(Payment):
    def pay(self, money):  # 这里类的方法不是一致的pay,导致后面调用的时候找不到pay
        print('支付宝支付了')


# 如果子类中没有实现抽象方法,实例化对象时,就会报错
p = Alipay()

接口类

from abc import abstractmethod, ABCMeta


class WalkAnimal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):
        pass


class SwimAnimal(metaclass=ABCMeta):
    @abstractmethod
    def swim(self):
        pass


class FlyAnimal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):
        pass


# 如果正常一个老虎有跑和跑的方法的话,我们会这么做
class Tiger(WalkAnimal, SwimAnimal):
    def walk(self): pass
    def swim(self): pass


t = Tiger()

如上,就不进行解释了。

注意点

注意点:

  1. 抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计。
  2. 在继承抽象类的过程中,我们应该尽量避免多继承;
  3. 而在继承接口的时候,我们反而鼓励你来多继承接口, 一般情况下 单继承 能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现,多继承的情况 由于功能比较复杂,所以不容易抽象出相同的功能的具体实现写在父类中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/971148.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分治NTT/在线卷积

https://www.luogu.com.cn/problem/P4721 已知 g g g,求 考虑分治,现在在 [ l , r ] [l,r] [l,r],先计算 [ l , m i d ] [l, mid] [l,mid],然后计算 [ l , m i d ] [l, mid] [l,mid] 对 [ m i d 1 , r ] [mid1,r] [mid1,r…

Java elasticsearch scroll模板实现

一、scroll说明和使用场景 scroll的使用场景:大数据量的检索和操作 scroll顾名思义,就是游标的意思,核心的应用场景就是遍历 elasticsearch中的数据; 通常我们遍历数据采用的是分页,elastcisearch还支持from size的方…

Redis基础知识(二):事务机制

文章目录 一、什么是事务机制?二、Redis模式下如何实现事务机制?2.1 显式开启一个事务2.2 将命令入队列Queue2.3 执行事务或丢弃2.4 EXEC命令执行示例2.5 DISCARD命令:放弃事务2.6 因为命令错误导致的事务回滚 三、Redis事务机制能实现哪些属…

气象监测——关于气象监测站的介绍

在科技日益发展的今天,人类对自然环境的认识和依赖程度越来越高。气象监测站作为用于收集、分析和传播气象数据的设施,为天气预报、气候变化研究、灾害防治等方面提供数据支持。随着科技的不断进步,气象监测站已经发展成为集多种高科技设备于…

leetcode 594.最长和谐子序列(滑动窗口)

⭐️ 题目描述 🌟 leetcode链接:最长和谐子序列 思路: 第一步先将数组排序,在使用滑动窗口(同向双指针),定义 left right 下标,比如这一组数 {1,3,2,2,5,2,3,7} 排序后 {1,2,2,2,3,…

Java问题诊断和排查工具

文章目录 一、前言二、Java问题诊断和排查工具1、JDK自带工具2、常用命令3、JAVA Dump:3.1、jps3.2、jstack3.3、jmap3.3.1、jmap -heap pid:查看堆使用情况3.3.2、jmap -histo pid:查看堆中对象数量和大小3.3.3、jmap -dump:formatb,fileheapdump pid&a…

教你如何高效批量分割长视频,让你的视频制作更轻松

在视频制作过程中,我们常常需要从长视频中分割出一些重要的片段,以便进行后续的编辑和处理。然而,这是一项耗时且繁琐的任务。今天,我们将为您介绍一种高效分割长视频的方法,让您在视频制作中更高效、更便捷。 首先&am…

C. To Add or Not to Add

题目: 样例1: 输入 5 3 6 3 4 0 2输出 3 4 样例2: 输入 3 4 5 5 5输出 3 5 样例3: 输入 5 3 3 1 2 2 1输出 4 2 思路: 贪心题目,化分离数为块。这里要注意的是 需要进行的排序 以及操作的过程是什么样子…

【本地代码问题】启动程序,报错:java.lang.IllegalArgumentException: No selectors

启动程序的时候报错了 问题怎么出现的解决方式,注释掉jetty的内容,回归tomcat的使用 问题怎么出现的 我本地启动程序的时候报错了:报的是这个错误,可能和容器的选择有关吧 解决方式,注释掉jetty的内容,回…

2.2 PE结构:文件头详细解析

PE结构是Windows系统下最常用的可执行文件格式,理解PE文件格式不仅可以理解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,DOS头是PE文件开头的一个固定长度的结构体,这个结构体的大小为64字节&#xf…

MyBatisPlus之逻辑删除、MyBatisPlus解决并发问题的乐观锁机制

🐌个人主页: 🐌 叶落闲庭 💨我的专栏:💨 c语言 数据结构 javaEE 操作系统 石可破也,而不可夺坚;丹可磨也,而不可夺赤。 MyBatisPlus 一、 逻辑删除1.1 数据库表中添加逻辑…

广州华锐互动:3D数字孪生楼宇资产管理系统展示楼宇实时信息

3D数字孪生楼宇资产管理系统由广州华锐互动开发,是一种基于数字孪生技术的智能化展示平台,它可以将楼宇的各项数据进行实时展示,为楼宇的管理者和使用者提供便捷的信息查询和服务。以下是一些实用功能: 1.实时监控:实时…

问道管理:刚刚,“金九”来了?

今天早盘,A股商场可谓“全面开花”。 银行、白酒等权重板块携手发力,带动上证指数、深证成指半日涨超1%;北交所股票更是全线飘红,北证50指数盘中最大涨幅超越8%,半日上涨5.85%。 到午间休市,A股商场超越3…

【C++】智能指针(RAII)详解

我们在上篇文章中(异常处理详解)提到了 RAII 。那么本篇文章会对此进行详解。重点是智能指针的详解。其中会讲解到 RAII 思想、auto_ptr、unique_ptr、shared_ptr、weak_ptr、循环引用问题。希望本篇文章会对你有所帮助。 文章目录 一、为什么需要智能指…

【java】【项目实战】[外卖九]项目优化(缓存)

目录 一、问题说明 二、环境搭建 2.1 Git管理代码 2.1.1 创建本地仓库 2.1.2 创建远程仓库 2.1.3 创建分支--》推送到远程仓库 2.2 maven坐标 2.3 配置文件application.yml 2.4 配置类RedisConfig 三、缓存短信验证码 3.1 实现思路 3.2 代码改造 3.2.1 UserContro…

CS420 课程笔记 P5 - 内存编辑 数据类型

文章目录 IntroductionData typesBooleansNegative numbers (Signed integers)Floating-point numbers (fractional numbers) Unknown value scansHealth findingFloat finding (Player position hack / Teleport hack) Additional things Introduction 这节课将结束数据类型并…

POI实现word文档导出

1 需求 在列表页面中点击合同按钮,跳转到合同页面 页面中有下载按钮,点击下载按钮,把页面展示的内容导出到word中。 2 分析 2.1 POI操作Word的API介绍 poi对低版本的doc本身支持的就不好所以我们直接说高版本的docx版本的api。 1、poi…

朴素,word,任何参考文献导入endnote

朴素,word,任何参考文献导入endnote 注意:对于以下这几种不做阐述,看其他帖子都有讲述: 这里的参考文献指的是类似于: [1]. Li Y, Lu Y, Huo X, et al. Bandgap tuning strategy by cations and halide io…

【python零基础入门学习】python基础篇之文件对象open、模块以及函数的使用(三)

本站以分享各种运维经验和运维所需要的技能为主 《python》:python零基础入门学习 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8》暂未更新 《docker学习》暂未更新 《ceph学习》ceph日常问题解…

【人月神话】重新探索人月神话:软件工程的现实与挑战

人月神话是一篇由美国软件工程师弗雷德里克布鲁克斯所写的软件工程经典之作,最早发表于1975年。这篇文章的全名是《人月神话:软件工程的神话与现实》(The Mythical Man-Month: Essays on Software Engineering),它涵盖…