[python]动态实例化
前言
最近在查一个服务的问题时,看到有一段代码if .. elif ... 写了近百行,类似
if command == "xxx":
obj = CommandX()
obj.run()
# ...
elif command == "yyy":
obj = CommandY()
obj.run()
# ...
elif command == "zzz":
obj = CommandZ()
obj.run()
# ...
# ...
翻了下git记录,最开始其实只有两三个条件判断,后来command越加越多,就这么延续下来了。
代码逻辑其实没什么问题,也很简单明了,就是看起来有点丑,而且我还开了比较高的桌面缩放,导致一屏幕几乎都是这段if ... elif
看来看去越发觉得丑,先写个demo看看能不能跑通代码。
方式1, 字典映射
如果需要判断的条件比较少,用字典做映射还是挺方便的,但如果条件多,看起来还是挺丑的。
from abc import ABC, abstractmethod
class AbstractCommand(ABC):
@abstractmethod
def run(self):
pass
class CommandA(AbstractCommand):
def run(self):
return "this is command A"
class CommandB(AbstractCommand):
def run(self):
return "this is command B"
class CommandC(AbstractCommand):
def run(self):
return "this is command C"
class CommandFactory:
@staticmethod
def create_command(command_type: str) -> AbstractCommand:
command_mapping = {
"cmda": CommandA,
"cmdb": CommandB,
"cmdc": CommandC
}
cls = command_mapping.get(command_type.lower())
if not cls:
raise ValueError(f"Unknown command type: {command_type}")
return cls()
if __name__ == "__main__":
cmd = CommandFactory.create_command("cmda")
assert cmd.run() == "this is command A"
cmd = CommandFactory.create_command("cmdb")
assert cmd.run() == "this is command B"
cmd = CommandFactory.create_command("cmdc")
assert cmd.run() == "this is command CD" # should be exception
cmd = CommandFactory.create_command("cmdd") # should be exception
assert cmd.run() == "this is command D"
方式2, __init_subclass__
《流畅的Python(第2版)》的最后一章提到了这个__init__subclass__,根据python官方文档:
当所在类派生子类时此方法就会被调用。cls 将指向新的子类。如果定义为一个普通实例方法,此方法将被隐式地转换为类方法。传给一个新类的关键字参数会被传给上级类的
__init_subclass__。 为了与其他使用__init_subclass__的类兼容,应当去掉需要的关键字参数再将其他参数传给基类。
借助这个机制,可以在实现抽象基类时自动注册子类,避免手动维护注册表。
from abc import ABCMeta, abstractmethod
from threading import Lock
from collections import UserDict
class ThreadSafeDict(UserDict):
"""线程安全的字典"""
def __init__(self):
super().__init__()
self._lock = Lock()
def __setitem__(self, key, item):
with self._lock:
super().__setitem__(key, item)
class Command(metaclass=ABCMeta):
registry = ThreadSafeDict()
def __init__(self):
pass
@abstractmethod
def run(self):
pass
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.registry[cls.__name__.lower()] = cls # 自动注册子类
# 子类定义即自动注册
class CommandA(Command):
def run(self):
return "this is command a!"
class CommandB(Command):
def run(self):
return "this is command b!"
class CommandC(Command):
def run(self):
return "this is command b!"
def create_command(command_type: str) -> Command:
"""工厂函数"""
cls = Command.registry.get(command_type.lower())
if not cls:
raise ValueError(f"Unknown command type: {command_type}")
return cls()
if __name__ == "__main__":
cmd = create_command("CommandA")
assert cmd.run() == "this is command a!"
cmd = create_command("CommandB")
assert cmd.run() == "this is command b!"
cmd = create_command("CommandC")
assert cmd.run() == "this is command cc!" # should be exception
cmd = create_command("CommandD")
assert cmd.run() == "this is command b!" # should be exception
乍一看还是挺不错的,但是也有个缺点,那就是如果各个类分散在不同模块中,那么工厂函数所在的模块就要写一堆from xxx import ...
如果module和类命名比较规范,也可以这么动态加载类
import importlib
def create_class(module_name, class_name):
module = importlib.import_module(module_name)
cls = getattr(module, class_name)
return cls()
补充
自动注册类看起来炫,但是对代码阅读来说不是很直观。易读还是美观?这是一个问题。
[python]动态实例化的更多相关文章
- Python 动态创建函数【转】
知乎上也有相似的问题 偶然碰到一个问题,初想是通过动态创建Python函数的方式来解决,于是调研了动态创建Python函数的方法. 定义lambda函数 在Python中定义lambda函数的写法很简 ...
- PHP动态实例化对象并向构造函数传递参数
在框架开发,模块化开发等场合,我们可能有一种需求,那就是在PHP运行时动态实例化对象. 什么是动态实例化对象呢?我们先来看一下PHP有一种变量函数(可变函数)的概念,例如如下代码: function ...
- python动态类型
在python中,省去了变量声明的过程,在引用变量时,往往一个简单的赋值语句就同时完成了,声明变量类型,变量定义和关联的过程,那么python的变量到底是怎样完成定义的呢? 动态类型 python使用 ...
- c# 动态实例化一个泛型类
动态实例化一个类,比较常见,代码如下 namespace ConsoleApp2 { public class MyClass { } } Type classType = Type.GetType( ...
- 【Python】python动态类型
在python中,省去了变量声明的过程,在引用变量时,往往一个简单的赋值语句就同时完成了,声明变量类型,变量定义和关联的过程,那么python的变量到底是怎样完成定义的呢? 动态类型 python使用 ...
- python爬虫的一些小小问题、python动态正则表达式
1.首先urllib不能用了,需要引入的是urllib2,正则re. #coding=utf-8 # import urllib import urllib2 import re def getHtm ...
- python动态添加属性和方法
---恢复内容开始--- python动态添加属性: class Person(object): def __init__(self,newName,newAge): self.name = newN ...
- ABP框架 - 介绍 VS2017调试器无法附加到IIS进程(w3wp.exe) c# 动态实例化一个泛型类
ABP框架 - 介绍 在14,15年间带领几个不同的团队,交付了几个项目,在这个过程中,虽然几个项目的业务不一样,但是很多应用程序架构基础性的功能却是大同小异,例如认证.授权.请求验证.异常处理. ...
- Python动态网页爬虫-----动态网页真实地址破解原理
参考链接:Python动态网页爬虫-----动态网页真实地址破解原理
- python 动态生成变量名以及动态获取变量的变量名
前言需求: 必须现在需要动态创建16个list,每个list的名字不一样,但是是有规律可循,比如第一个list的名字叫: arriage_list_0=[],第二个叫arriage_list_1=[] ...
随机推荐
- halcon 入门教程(二)Blob分析(二值化,联通区域,分割区域,提取区域)保姆级教程
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/18781187 有兴趣可以多看其他的halcon教程 halcon 学习教程目录 OK,今天讲h ...
- oracle数据库体系架构详解
在学习oracle中,体系结构是重中之重,一开始从宏观上掌握它的物理组成.文件组成和各种文件组成.掌握的越深入越好.在实际工作遇到疑难问题,其实都可以归结到体系结构中来解释.体系结构是对一个系统的框架 ...
- 团队小规模本地大模型服务平台搭建 - Ubuntu
实现目标和考虑因素 部署一个支持多用户同时使用.多模型运行的离线局域网大模型服务器 需要考虑以下几个关键因素: 大模型的加载和管理.使用一个基础大模型,根据实战需要创建多个专用模型,模型管理方便可靠. ...
- .NET 生成PDF文件
1.网上检索N种解决方案 QuestPDF:简单方便实用,文档也相对来说全,但是开源协议,当企业规模大的100W美金需要收费,未来存在潜在版权问题. itext7:感觉实用偏复杂,项目类库引用复杂,不 ...
- sql 使用with 递归
---前提:有上下级关系的关系表 ---示例:组织架构表 DECLARE @orgId NVARCHAR(20)='0001'; --向下递归,查询@orgId 下的所有结点...包括儿子-孙子节 ...
- 深入理解泛型-重写泛型类方法遇到的问题(涉及JVM反编译字节码)
下面的代码DateInterval类想重写父类Pair<LocalDate>中的setSecond方法,保证设置的第二个日期要在第一个日期之后,不能出现second早于first的情况.这 ...
- 『Plotly实战指南』--饼图绘制高级篇
在数据可视化的世界里,饼图是最直观的展示比例关系的工具之一. 然而,传统的静态饼图已经无法满足现代数据分析的需求.Plotly作为一款强大的可视化库,不仅提供了饼图丰富的基础功能,还支持交互效果和动态 ...
- study PostgreSQL【3-get数据库中all表以及表的字段信息】
get一表的字段相关信息: SELECT col_description(a.attrelid,a.attnum) as comment,pg_type.typname as typename,a.a ...
- 【Linux】基于Exynos4412的U-Boot引导程序移植
[Linux]基于Exynos4412的U-Boot引导程序移植 零.准备 首先我们得去下载好U-Boot的源码,因为用的芯片是2012年出的Exynos4412,因此我们选择这个时间节点附近的U-B ...
- Windows系统设置开机自启动+分块压缩+文件共享
开机自启动+分块压缩+文件共享 一.设置开机自启动 win+R 打开运行窗口,输入 shell:startup 此时桌面会弹出一个目录文件夹,只需要将需要启动的软件放入该文件夹即可开机自启. C:\U ...