Python 使用装饰器尝试编写DTO

Python 使用装饰器尝试编写DTO,第1张

文章目录
  • 前言
  • 一、为什么选择使用装饰器?
  • 二、尝试
    • 1.编写基础架构
    • 2.为装饰器添加方法
    • 3.举例编写其他方法
  • 总结


前言

在了解和学习了 mybaits之后,我有时会感觉CURD居然能这么方便。所以我在编写python代码时,常常会想到能不能实现类似的方法,减轻CURD的工作量。
所以我进行了一些简单的尝试……


一、为什么选择使用装饰器?

装饰器的优点是能够抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。即,可以将函数“修饰”为完全不同的行为,可以有效的将业务逻辑正交分解。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
如何理解 Python 装饰器

二、尝试 1.编写基础架构

首先,定义学生DTO,它包含三个字段:学号姓名和年龄

class Student:
    __slots__ = ('id', 'name', 'age')

    def __init__(self, id: int, name: str, age: int):
        self.id = id
        self.name = name
        self.age = age

下面先创建一个装饰器框架

def db(**kwargs):
    def wrapper(cls):
    	# TODO coding here
        return cls
    return wrapper

然后给学生类加上注解,并且我希望能传入学生DTO对应的表名:

@db(table_name='t_student')
class Student:
    __slots__ = ('id', 'name', 'age')
	...
2.为装饰器添加方法

首先,我想通过Student.get_table_name方法能够输出我们传给装饰器的表名。修改装饰器:

def db(table_name: str):
    def wrapper(cls):
        @classmethod
        def get_table_name(cls):
            return table_name
        cls.get_table_name = get_table_name
        return cls
    return wrapper

因为get_table_name应该是一个类方法,所以需要在该方法上添加@classmethod装饰器。编写个简单测试用例:

if __name__ == '__main__':
    print('Student:\t', Student.get_table_name())

运行可以看到结果:

Student:	 t_student

这说明我们的想法应该是可以实现的

3.举例编写其他方法

下面是我编写的一个小demo,写道这儿的时候感觉有点困了,所以就只有这一点,而且也没写与数据库交互相关的模块,有时间再填坑,或者等一个有缘人帮帮我。

def db(table_name: str):
    def wrapper(cls):
        @classmethod
        def get_table_name(cls):
            return table_name

        @classmethod
        def get_insert_sql(cls):
            return f"insert into `{table_name}` ({','.join(cls.__slots__)}) " \
                   f"values ({','.join((f'%({field})s' for field in cls.__slots__))})"

        def get_values(self):
            return {field: getattr(self, field) if hasattr(self, field) else None for field in self.__slots__}

        @staticmethod
        def create_from_dict(values):
            values = dict(dict.fromkeys(cls.__slots__), **values)
            return cls(**values)

        cls.get_table_name = get_table_name
        cls.get_insert_sql = get_insert_sql
        cls.get_values = get_values
        cls.create_from_dict = create_from_dict
        return cls
    return wrapper


@db(table_name='t_student')
class Student:
    __slots__ = ('id', 'name', 'age')

    def __init__(self, id: int, name: str, age: int):
        self.id = id
        self.name = name
        self.age = age


@db(table_name='t_score')
class Score:
    __slots__ = ('id', 'stu_id', 'score')

    def __init__(self, id: int, stu_id: int, score: int):
        self.id = id
        self.stu_id = stu_id
        self.score = score



if __name__ == '__main__':
    stu = Student(10086, '小明', 18)
    print('values:\t\t', stu.get_values())
    print('format sql:\t', Student.get_insert_sql())
    print('sql:\t\t', Student.get_insert_sql() % stu.get_values())

    scr = Score.create_from_dict({
        'id': 123456,
        'stu_id': stu.id,
        'score': 60
    })
    print('\nscore:\t\t', scr.get_insert_sql() % scr.get_values())

可以看见结果:

values:		 {'id': 10086, 'name': '小明', 'age': 18}
format sql:	 insert into `t_student` (id,name,age) values (%(id)s,%(name)s,%(age)s)
sql:		 insert into `t_student` (id,name,age) values (10086,小明,18)

score:		 insert into `t_score` (id,stu_id,score) values (123456,10086,60)

请在python3.9及以上版本运行该段代码


总结

利用装饰器能极大减少相似代码的编写,提高效率。而且添加修改方法时也不需要在每一个类中都进行一遍。对于我来说,这是目前最满足我想法的一种实现,但本人基本没啥水平,希望大佬们能给我些建议(直接写成库最好了,如果有现成的务必推荐给我)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/799018.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存