当前位置: 首页 > news >正文

注册表模式:使用注册表和装饰器函数的模块化设计

在现代软件开发中,模块化设计是提高代码可维护性和可扩展性的关键技术之一。本文将探讨如何使用注册表(Registry)和装饰器函数(Decorator Function)来实现模块化设计,提升代码的灵活性和可扩展性。

什么是注册表(Registry)?

注册表是一种设计模式,用于集中管理和访问不同模块。在 Python 中,注册表通常是一个字典,用来存储模块名称和模块类对象的映射关系。通过注册表,可以方便地对模块进行注册、获取和列出操作,从而实现模块化管理。

基本的注册表实现

以下是一个基本的注册表实现:

from loguru import loggerclass Registry(object):"""This class is used to register some modules to registry by a repo name."""def __init__(self, name: str):self._name = nameself._modules = {}@propertydef name(self):return self._name@propertydef modules(self):return self._modulesdef list(self):for m in self._modules.keys():logger.info(f'{self._name}\t{m}')def get(self, module_key):return self._modules.get(module_key, None)def _register_module(self, module_name=None, module_cls=None, force=False):if module_name is None:module_name = module_cls.__name__if module_name in self._modules and not force:raise KeyError(f'{module_name} is already registered in {self._name}')self._modules[module_name] = module_clsmodule_cls._name = module_namedef register_module(self, module_name: str = None, module_cls: type = None, force=False):if not (module_name is None or isinstance(module_name, str)):raise TypeError(f'module_name must be either of None, str, got {type(module_name)}')if module_cls is not None:self._register_module(module_name=module_name, module_cls=module_cls, force=force)return module_clsdef _register(module_cls):self._register_module(module_name=module_name, module_cls=module_cls, force=force)return module_clsreturn _register

特别注意register_module中的_register,register_module 方法根据传入的 module_namemodule_cls 参数,返回一个装饰器函数 _register

使用装饰器函数注册模块

装饰器函数是一种高阶函数,可以在不改变原函数或类的前提下,动态地增加功能。在注册表模式中,装饰器函数可以用于注册模块,简化模块注册的过程。

以下是如何使用装饰器函数注册模块的示例:

DATASETS = Registry('Datasets')@DATASETS.register_module('ChineseDataset')
class ChineseDataset:def __init__(self, oss_dir, max_sample_per_cat=50, shuffle=False):self.oss_dir = oss_dirself.max_sample_per_cat = max_sample_per_catself.shuffle = shuffledef info(self):# 实现具体的逻辑passdef format(self, res):# 实现具体的逻辑pass

在这个示例中,ChineseDataset 类通过装饰器函数 @DATASETS.register_module('ChineseDataset') 自动注册到 DATASETS 注册表中。

装饰器函数的工作原理

在上面的代码中,@DATASETS.register_module('ChineseDataset') 是一个装饰器函数调用。这个装饰器函数的工作原理如下:

  1. DATASETS.register_module('ChineseDataset') 返回一个装饰器函数 _register
  2. @_register 装饰器应用于 ChineseDataset 类,将其作为参数传递给 _register 函数。
  3. _register 函数内部调用 _register_module 方法,将 ChineseDataset 类注册到 DATASETS 注册表中。

具体的 _register 函数定义如下:

def register_module(self, module_name: str = None, module_cls: type = None, force=False):if not (module_name is None or isinstance(module_name, str)):raise TypeError(f'module_name must be either of None, str, got {type(module_name)}')if module_cls is not None:self._register_module(module_name=module_name, module_cls=module_cls, force=force)return module_clsdef _register(module_cls):self._register_module(module_name=module_name, module_cls=module_cls, force=force)return module_clsreturn _register

在这个实现中,register_module 方法根据传入的 module_namemodule_cls 参数,返回一个装饰器函数 _register。当 ChineseDataset 类被装饰时,_register 函数将其注册到 DATASETS 注册表中。

实例化 ChineseDataset

实例化 ChineseDataset 类的步骤发生在 deal_one_dataset 函数中,通过以下代码实现:

ds = DATASETS.get(name)(oss_path)

这段代码首先通过 DATASETS.get(name) 获取注册的 ChineseDataset 类,然后通过 (oss_path) 对其进行实例化。这样,ChineseDataset 类的一个实例就被创建,并存储在 ds 变量中,用于后续的数据处理操作。

为了更清晰地解释,让我们回顾一下实例化 ChineseDataset 类的完整过程。在下面的代码片段中,实例化过程发生在 deal_one_dataset 函数中:

import os, json, argparse
from tqdm import tqdm
import multiprocessing as mp
from src import DATASETS, utilsdef parse_args():parser = argparse.ArgumentParser(description='data_parsing', formatter_class=argparse.RawTextHelpFormatter)parser.add_argument("--name", type=str, default='ChineseDataset', help="dataset name")parser.add_argument("--oss-dir", type=str, default='/root/dengbing/bigdata/benchmark/extract/ChineseDataset/', help="oss directory of the dataset")parser.add_argument("--save-path", type=str, default='output.jsonl', help="path for the generated jsonl")args = parser.parse_args()return argsdef deal_one_dataset(name, oss_path):ds = DATASETS.get(name)(oss_path)  # 这里实例化 ChineseDataset 类res = ds.info()res = ds.format(res)return resif __name__ == "__main__":args = parse_args()with open(args.save_path, 'w') as outfile:res = deal_one_dataset(args.name, args.oss_dir)for r in res:j = utils.format_decimals(r)outfile.write(json.dumps(j, ensure_ascii=False) + '\n')

具体步骤

  1. 解析命令行参数

    • parse_args 函数解析命令行参数,获取数据集名称(--name)、OSS 目录(--oss-dir)和保存路径(--save-path)。
  2. 处理单个数据集

    • deal_one_dataset 函数根据传入的 nameoss_path 参数,处理单个数据集。
    • 在这一步中,DATASETS.get(name) 获取已经注册的 ChineseDataset 类,然后通过 (oss_path) 对其进行实例化。
  3. 实例化 ChineseDataset

    • ds = DATASETS.get(name)(oss_path) 实际上是两步操作:
      • DATASETS.get(name) 获取注册在 DATASETS 注册表中的 ChineseDataset 类。
      • (oss_path) 调用类的构造函数,创建一个 ChineseDataset 类的实例,并传递 oss_path 参数。
  4. 调用数据集方法

    • res = ds.info() 调用实例的 info 方法,获取数据集信息。
    • res = ds.format(res) 调用实例的 format 方法,格式化数据集信息。
  5. 保存结果

    • 主程序部分将处理后的数据集结果保存到指定的 JSONL 文件中。
总结

通过使用装饰器函数,ChineseDataset 类可以自动注册到 DATASETS 注册表中,而不需要显式地调用注册方法。这种方式简化了模块的注册过程,使代码更加简洁和易于维护。

装饰器函数和注册表的结合使用,提高了代码的灵活性和可扩展性,使得模块化设计更加高效。在实际开发中,这种设计模式可以广泛应用于插件系统、数据处理管道和其他需要动态管理模块的场景。

相关文章:

注册表模式:使用注册表和装饰器函数的模块化设计

在现代软件开发中,模块化设计是提高代码可维护性和可扩展性的关键技术之一。本文将探讨如何使用注册表(Registry)和装饰器函数(Decorator Function)来实现模块化设计,提升代码的灵活性和可扩展性。 什么是…...

怎样将vue项目 部署在ngixn的子目录下

如果同一服务器的80端口下,需要部署两个或以上数量的vue项目,那么就需要将其中一个vue项目部署在根目录下,其他的项目部署在子目录下. 像这样的配置 访问根目录 / 访问灭火器后台管理,访问 /mall/ 访问商城的后台管理 那么商场的vue项目,这样配置,才能在/mall/下正常访问? 1…...

FPGA开发:Verilog数字设计基础

EDA技术 EDA指Electronic Design Automation,翻译为:电子设计自动化,最早发源于美国的影像技术,主要应用于集成电路设计、FPGA应用、IC设计制造、PCB设计上面。 而EDA技术就是指以计算机为工具,设计者在EDA软件平台上…...

哈希表,算法

一.什么是哈希表 哈希表是一种用于快速数据存取的数据结构。它通过哈希函数将键(key)映射到表中的一个位置,从而实现高效的插入、删除和查找操作。 二.哈希冲突 哈希冲突发生在多个键通过哈希函数映射到哈希表的同一位置时。由于哈希表的大…...

Java数组的定义及遍历

数组的声明 长度不能超过定义的长度。超过则会报错通过下标来访问 数组的遍历 最常用最简单的方法是增强for循环。...

【电路笔记】-反相运算放大器

反相运算放大器 文章目录 反相运算放大器1、概述2、理想反相运算放大器3、实际反相运算放大器3.1 闭环增益3.2 输入阻抗3.3 输出阻抗4、反相运算放大器示例5、总结1、概述 上一篇关于同相运算放大器的文章中已介绍了该运算放大器配置的所有细节,该配置在同相引脚 (+) 上获取输…...

【电子通识】半导体工艺——刻蚀工艺

在文章【电子通识】半导体工艺——光刻工艺中我们讲到人们经常将 Photo Lithography(光刻)缩写成 Photo。光刻工艺是在晶圆上利用光线来照射带有电路图形的光罩,从而绘制电路。光刻工艺类似于洗印黑白照片,将在胶片上形成的图像印…...

vue-router 之如何在模版(template)中获取路由配置信息?

vue-router 之如何在模版(template)中获取路由配置信息? 获取当前路由信息 在vue3 中,route通常使用useRoute()钩子获取的,**代表当前激活的路由信息。**它包含了与当前路由相关的数据,比如路径、参数、查…...

HPL 源码结构分析

文件夹结构: $ cd /home/hipper/ex_hpl_hpcg/ $ pwd $ mkdir ./openmpi $mkdir ./openblas $mkdir ./hpl $ tree 1. 安装openmpi 1.1.1 使用Makefile下载配置编译安装 openmpi Makefile: all:wget https://download.open-mpi.org/release/open-m…...

Java代码审计篇 | ofcms系统审计思路讲解 - 篇3 | 文件上传漏洞审计

文章目录 0. 前言1. 文件上传代码审计【有1处】1.1 可疑点1【无漏洞】1.1.1 直接搜索upload关键字1.1.2 选择第一个,点进去分析一下1.1.3 分析this.getFile()方法1.1.4 分析new MultipartRequest(request, uploadPath)1.1.5 分析isSafeFile()方法1.1.6 分析request.…...

【Kubernetes】常见面试题汇总(五)

目录 13.简述 Kubernetes Replica Set 和 Replication Controller 之间有什么区别? 14.简述 kube-proxy 作用? 15.简述 kube-proxy iptables 原理? 16.简述 kube-proxy ipvs 原理? 13.简述 Kubernetes Replica Set 和 Replicat…...

MySQL 解决时区相关问题

在使用 MySQL 的过程中,你可能会遇到时区相关问题,比如说时间显示错误、时区不是东八 区、程序取得的时间和数据库存储的时间不一致等等问题。其实,这些问题都与数据库时区设 置有关。 MySQL Server 中有 2 个环境变量和时区有关,…...

SpringSecurity Context 中 获取 和 更改 当前用户信息的问题

SpringSecurity Context 获取和更改用户信息的问题 SecurityContext 异步线程中获取用户信息 今天在做项目时遇到了一个问题,我需要获取当前用户的 ID。之前,前端并没有存储用户信息,我一直是在后端的 service 中通过 SecurityContext 来获…...

Makefile的四种赋值运算符

Makefile有四种赋值运算符:简单赋值(:)、递归赋值()、条件赋值(?)和追加赋值() 1. 简单赋值(:) 作用:覆盖之前的值。若在多次简单赋…...

framebuffer

framebuffer:帧缓冲、帧缓存 Linux内核为显示提供的一套应用程序接口(驱动内核支持) 分辨率:像素点的总和 像素点: 显示屏:800*600(横向有800个像素点,纵向有600个像素点&#x…...

7.科学计算模块Numpy(4)ndarray数组的常用操作(二)

引言 书接上回,numpy能作为python中最受欢迎的数据处理模块,脱离不了它最核心的部件——ndarray数组。那么,我们今天就来了解一下numpy中对ndarray的常用操作。 通过阅读本篇博客,你可以: 1.掌握ndarray数组的分割 …...

抖音评论区截流脚本软件详细使用教学,抖音私域获客引流的五种方法。

1.先说下什么是抖音截流玩法,截流顾名思义就是在别的博主的视频下面去截流评论潜在流量,然后用评论文案的形式或者其它方式吸引用户加我们的私域~ 玩截流一定不是主动去私信别人,这个就不叫截流了,且一个账号私信多了一定会降权和…...

Linux_kernel移植uboot07

一、移植 根据硬件平台的差异,将代码进行少量的修改,修改过后的代码在目标平台上运行起来 移植还需要考虑硬件环境,驱动只需要考虑内核的环境 二、移植内容 1、移植Uboot uboot属于bootloader的一种,还有其他的bootloader&#x…...

Day-04-QFile打开文件的两种方式

一、UI界面设置两个按键&#xff0c;并直接转到槽函数 二、两种代码展示 #include <QFile> #include <QDebug>//此两种方式中调用函数&#xff0c;应包含的头文件void Widget::on_btnReadFile01_clicked()//第一种打开方式 {//1. 打开文件QFile file;file.setFile…...

第三部分:4---进程地址空间

目录 数组的空间分配解析&#xff1a; 物理地址和虚拟地址&#xff1a; 虚拟地址空间&#xff1a; 进程地址空间的本质&#xff1a; 为什么要有进程地址空间&#xff1f; 页表对进程访问内存的检查&#xff1a; 进程地址空间和页表如何关联起来&#xff1f; 进程的独立…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...