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

Python 单例模式工厂模式和classmethod装饰器

前言:

Python作为面向对象的语言,显然支持基本的设计模式。也具备面向对象的语言的基本封装方法:属性、方法、继承、多态等。但是,做为强大的和逐渐发展的语言,python也有很多高级的变种方法,以适应更多的场景。

我们都知道单例和工厂模式在设计模式中,其实就是一种怪胎。其实就是他们都不是经典的面向对象能够覆盖的场景。

例如,单例,他其实就是非常适配于一个硬件的操控的用例。而工程模型,主要关注的不同的对象的多态的变化。这两张,从根本上讲是从典型的面向对象的体系里面分离出来的典型的普通的例子。

由此,Python作为一个语言也发展出相对应的的适配的额外的方法,就如,我们这章将展示的方法。


1 设计模式的基本概念:

1.1 单例模式:

单例模式确保一个类只有一个实例,并提供一个全局访问点。

class Singleton:_instance = Nonedef __new__(cls):if cls._instance is None:cls._instance = super(Singleton, cls).__new__(cls)return cls._instance# 使用单例模式
singleton1 = Singleton()
singleton2 = Singleton()print(singleton1 is singleton2)  # 输出 True,表示两个变量指向同一个实例

【案,这里创建了两个实例, singleton1 和singleton2 ,这两个不同名字的类实例,其实是一个东西。如果我们用类来代表一个硬件,比如机器视觉的相机或者是PLC,这些都是硬件实体。我们需要用这个实例模式来定义,以避免同一个硬件资源被其他的的任务复用】

1.2 工厂模式:

工厂模式是一种创建型设计模式,它使用工厂方法来创建对象,而不是直接调用构造函数。

class Car:def __init__(self, model, color):self.model = modelself.color = colordef speak(self):return f"This is a {self.model} in {self.color}."class ElectricCar(Car):def speak(self):return f"This is an electric {self.model} in {self.color}."class SportsCar(Car):def speak(self):return f"This is a sports {self.model} in {self.color}."class CarFactory:def create_car(self, model, color, car_type):if car_type == "electric":return ElectricCar(model, color)elif car_type == "sports":return SportsCar(model, color)else:return Car(model, color)# 使用工厂模式创建不同类型的汽车
factory = CarFactory()
my_car = factory.create_car("Toyota Camry", "red", "normal")
my_electric_car = factory.create_car("Nissan Leaf", "blue", "electric")
my_sports_car = factory.create_car("Porsche 911", "yellow", "sports")print(my_car.speak())          # 输出 "This is a Toyota Camry in red."
print(my_electric_car.speak()) # 输出 "This is an electric Nissan Leaf in blue."
print(my_sports_car.speak())    # 输出 "This is a sports Porsche 911 in yellow."

【案,在这个例子中,CarFactory 类的 create_car 方法根据传入的 car_type 参数来决定创建哪种类型的 Car 实例。这样,如果未来需要添加新的汽车类型,比如 HybridCar,你只需要在 CarFactory 类中添加相应的逻辑,而不需要修改其他使用汽车对象的代码。这就是工厂模式的价值所在:它封装了对象的创建逻辑,使得代码更加模块化和易于扩展。】


2 classmethod的装饰器和staticmethod装饰器:

前面的例子里面,我们看到了传统的单例和工厂模式的引入。传统的单例和工厂模式的设计,比较方便的是继承和多态。通过实例,比较方便的是构建继承和多态的方法。但,主要的问题就是需要考虑构建实例后才能使用,这样对多个实例支持的硬件案例,就很麻烦。

2.1 classmethod

在Python中,@classmethod是一个装饰器,用于将一个方法定义为类方法(class method)。类方法与普通的方法(instance method)不同,它不依赖于类的实例(instance),而是依赖于类本身。这意味着类方法的第一个参数总是指向类本身,通常命名为cls

【方法,我们知道面向对象的语言里面,方法就是对象能做哪些事情。一般,方法的定义依赖于类创建的实例,也就是先创建实例,类的方法才有用。而classmethod,是创建了一个类方法。】

类方法的主要作用包括:

  1. 访问类变量:类方法可以直接访问类的变量,而不需要创建类的实例。

  2. 创建实例:类方法可以用来创建类的实例,这在工厂模式中很常见。

  3. 修改类状态:类方法可以修改类的状态,比如添加类变量或者修改类属性。

  4. 继承时保持一致性:在继承时,类方法可以确保子类能够访问父类的类方法。

  5. 实现单例模式:类方法可以用来实现单例模式,确保一个类只有一个实例。

【案,类的方法有别于传统定义的方法,其实就是提供一个直接方法类定义的途径,以避免之前构建单例模式和工厂那种形而上学的方式(比如前面的单例构建,其实通过类方法就很简洁,不需要构造一个单例】

class MyClass:count = 0  # 类变量@classmethoddef increment_count(cls):cls.count += 1@classmethoddef get_count(cls):return cls.count# 使用类方法
MyClass.increment_count()
print(MyClass.get_count())  # 输出 1

上面的代码,就是在类里面创立了类方法,increment_count,这样直接用类的名字+类方法就可以完成对类的控制了。

这一点,对单例模式(硬件代表)尤其方便,我本来类就是代表硬件特性,采用了类方法,就可以直接方便的访问这些硬件的功能了。

 【案,值得注意的是,get_count的方法的第一个参数cls,是类Myclass本身。】cls = class .

现在,我们把第一节里面的工厂模式,用classmethod的类方法进行修改。

class Animal:def speak(self):raise NotImplementedError("Subclasses must implement this method")class Dog(Animal):def speak(self):return "Woof!"class Cat(Animal):def speak(self):return "Meow!"class AnimalFactory:@classmethoddef get_animal(cls, animal_type):if animal_type == "dog":return Dog()elif animal_type == "cat":return Cat()else:raise ValueError("Unknown animal type")# 使用工厂模式
dog = AnimalFactory.get_animal("dog")
cat = AnimalFactory.get_animal("cat")print(dog.speak())  # 输出 "Woof!"
print(cat.speak())  # 输出 "Meow!"

 在这个示例中,AnimalFactory 类的 get_animal 方法被定义为一个类方法,使用 @classmethod 装饰器。这意味着 get_animal 方法的第一个参数是类本身,这里我们命名为 cls。在这个方法中,我们根据传入的 animal_type 参数来创建相应的动物实例。使用 @classmethod 的好处是,我们可以在不创建类实例的情况下调用这个方法,这在工厂模式中是常见的做法,因为工厂方法通常不需要类的特定实例,而是需要类本身来创建新实例。


2.2 staticmethod

class Dog:def speak(self):return "Woof!"class Cat:def speak(self):return "Meow!"class AnimalFactory:@staticmethoddef get_animal(animal_type):if animal_type == "dog":return Dog()elif animal_type == "cat":return Cat()else:raise ValueError("Unknown animal type")# 使用工厂模式
dog = AnimalFactory.get_animal("dog")
cat = AnimalFactory.get_animal("cat")print(dog.speak())  # 输出 "Woof!"
print(cat.speak())  # 输出 "Meow!"

【案,在工厂模式里面,我们创建了猫和狗两个类,然后,我们没有用猫和狗的类来创建实例。而是通过动物的类,让后,通过动物类来调用猫和狗的类的实例的创建。】

使用 @staticmethod 的缺点:

  1. 灵活性:静态方法不能被子类重写,这限制了它们的灵活性。如果你需要在子类中改变创建实例的行为,静态方法不是一个好选择。

  2. 继承:由于静态方法不属于类的MRO(方法解析顺序),它们不能被继承。

  3. 多态性:静态方法不支持多态,这意味着你不能在子类中重写它们来改变行为。


3 小结:

3.1 self 和 cls

self 参数:

  • self 引用的是类的实例。
  • 用途self 是实例方法的第一个参数,用于访问和修改实例的状态(属性和方法)。
  • 行为self 指向调用方法的实例。当你通过实例调用一个方法时,Python自动将该实例作为 self 参数传递给方法。

cls 参数:

  • cls 引用的是类本身。
  • 用途cls 是类方法的第一个参数,用于访问和修改的状态(类属性和方法),以及创建类的实例
  • 行为cls 指向类本身。类方法可以通过 cls 访问类属性和方法,也可以调用其他类方法,并且可以创建类的实例。

3.1.1 self的例子:

class MyClass:def __init__(self, value):self.value = value  # 使用 self 访问实例属性def print_value(self):print(self.value)  # 使用 self 访问实例属性instance = MyClass(10)
instance.print_value()  # 输出 10

【self,在例子里面作为一个默认的参数,对外是封装的,透明的。在创建类的实例的时候函数init,传递第二个参数的时候,self自动起了衔接类之间的指代和传递的工作,最终,value=50,通过self赋值给了实例里面的类value,self理解为类内部的一个句柄】 

3.1.2 cls的例子:

class MyClass:class_var = "I am a class variable"@classmethoddef print_class_var(cls):print(cls.class_var)  # 使用 cls 访问类属性@classmethoddef create_instance(cls, value):return cls(value)  # 使用 cls 创建实例MyClass.print_class_var()  # 输出 "I am a class variable"
new_instance = MyClass.create_instance(20)
new_instance.print_value()  # 输出 20

【案,上面这个例子很好的说明了cls的使用,结合classmethod,首先,通过create_instance方法+cls,类内部句柄,构造了一个类内部的动态实例构造,cls(value),然后在调用这个创建实例的方法的时候,传入了外部参数value。】

3.2 classmethod(类方法) and staticmethod(静态类)

3.2.1 classmethod(类方法)

class MyClass:class_var = "I am a class variable"@classmethoddef my_class_method(cls):print("Class variable:", cls.class_var)MyClass.my_class_method()  # 输出 "Class variable: I am a class variable"

3.2.2 staticmethod

class Car:def __init__(self, model):self.model = modeldef speak(self):return f"This is a {self.model}"class CarFactory:@staticmethoddef create_car(model):return Car(model)# 使用工厂模式
my_car = CarFactory.create_car("Toyota Camry")
print(my_car.speak())  # 输出 "This is a Toyota Camry"

 【案,我们看到这两种方法的主要区别,就是要不要构建实例来访问类方法。当然,类方法也可以构造实例如本文3.1.2,需要写一点构造实例的方法,但是,比静态方法要简洁,此外,也更容易做多态的变换】

对应工厂模式而言:

  • 如果你需要一个简单的工厂方法,不需要访问类属性,也不想被子类重写,那么静态方法是一个很好的选择。
  • 如果你需要在子类中重写工厂方法,或者需要访问类属性来决定如何创建实例,那么类方法是更好的选择。

相关文章:

Python 单例模式工厂模式和classmethod装饰器

前言: Python作为面向对象的语言,显然支持基本的设计模式。也具备面向对象的语言的基本封装方法:属性、方法、继承、多态等。但是,做为强大的和逐渐发展的语言,python也有很多高级的变种方法,以适应更多的…...

计算机键盘简史 | 键盘按键功能和指法

注:本篇为 “计算机键盘简史 | 键盘按键功能和指法” 相关文章合辑。 英文部分机翻未校。 The Evolution of Keyboards: From Typewriters to Tech Marvels 键盘的演变:从打字机到技术奇迹 Introduction 介绍 The keyboard has journeyed from a humb…...

【数字信号处理】期末综合实验,离散时间信号与系统的时域分析,离散信号 Z 变换,IIR 滤波器的设计与信号滤波,用窗函数法设计 FIR 数字滤波器

关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…...

面试技术点之安卓篇

一、基础 二、高级 三、组件 Android中SurfaceView和TextureView有什么区别? 参考 Android中SurfaceView和TextureView有什么区别? 四、三方框架 五、系统源码 六、性能优化...

Windows Terminal ssh到linux

1. windows store安装 Windows Terminal 2. 打开json文件配置 {"$help": "https://aka.ms/terminal-documentation","$schema": "https://aka.ms/terminal-profiles-schema","actions": [{"command": {"ac…...

自适应卡尔曼滤波(包括EKF、UKF、CKF等)的创新思路——该调什么、不该调什么

在调节自适应卡尔曼滤波时,需要注意的参数和矩阵都对滤波器的性能有直接影响。本文给出详细的说明,包括相关公式和 MATLAB 代码示例 文章目录 需要调节的参数1. **过程噪声协方差矩阵 Q Q Q**:2. **测量噪声协方差矩阵 R R R**:…...

SpringBoot项目监听端口接受数据(NIO版)

文章目录 前言服务端相关配置核心代码 客户端 前言 环境: JDK:64位 Jdk1.8 SpringBoot:2.1.7.RELEASE 功能: 使用Java中原生的NIO监听端口接受客户端的数据,并发送数据给客户端。 服务端 相关配置 application.ym…...

QT实战--带行号的支持高亮的编辑器实现(2)

本文主要介绍了第二种实现带行号的支持高亮的编辑器的方式,基于QTextEdit实现的,支持自定义边框,背景,颜色,以及滚动条样式,支持输入变色,复制文本到里面变色,支持替换,是一个纯专业项目使用的编辑器 先上效果图: 1.头文件ContentTextEdit.h #ifndef CONTENT_TEXT_…...

(翻译)网络安全书籍推荐列表

注:对于所有的书籍链接,我都会寻找中文版重新链接,如无中文版,则按原文链接英文版。并且所有书籍名称保留英文名称 这是一个我建立的一个有关计算机安全的书籍列表,它们都是很有用的“计算机安全”这个主题的相关数据。…...

TcpServer 服务器优化之后,加了多线程,对心跳包进行优化

TcpServer 服务器优化之后&#xff0c;加了多线程&#xff0c;对心跳包进行优化 TcpServer.h #ifndef TCPSERVER_H #define TCPSERVER_H#include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <vector> #include <map> #…...

黑马程序员Java项目实战《苍穹外卖》Day12

苍穹外卖-day12 课程内容 工作台Apache POI导出运营数据Excel报表 功能实现&#xff1a;工作台、数据导出 工作台效果图&#xff1a; 数据导出效果图&#xff1a; 在数据统计页面点击数据导出&#xff1a;生成Excel报表 1. 工作台 1.1 需求分析和设计 1.1.1 产品原…...

经纬度解析到省市区【开源】

现在业务中有需要解析经纬度到省市区。 按理说可以直接使用高德&#xff0c;百度之类的。 但是老板太抠。于是去找开源项目。找了一圈&#xff0c;数据都太老了&#xff0c;而且有时候编码还不匹配。 所以诞生了这个项目&#xff0c;提供完整的一套省市区编码和定位反解析。…...

bug:uniapp运行到微信开发者工具 白屏 页面空白

1、没有报错信息 2、预览和真机调试都能正常显示&#xff0c;说明代码没错 3、微信开发者工具版本已经是win7能装的最高版本了&#xff0c;1.05版 链接 不打算回滚旧版本 4、解决&#xff1a;最后改调试基础库为2.25.4解决了&#xff0c;使用更高版本的都会报错&#xff0c;所…...

旧版本 MySQL 处理字符表情写入问题

报错信息 新增数据 java.sql.SQLException: Incorrect string value: \xF0\x9F\x91\x8D\xE5\x8F... for column解决方案 老项目&#xff0c;而且是旧版本&#xff0c;且表情不影响业务&#xff0c;直接简单粗暴的过滤掉即可&#xff0c;有还原的需求也可以 toUnicode 转为字…...

vue使用v-if和:class完成条件渲染

1.使用v-if 和v-else 完成主body和暂无数据两个<tbody>标签的条件渲染(注意与v-show效果的区别) 2.v-for完成列表渲染 3.:class完成分数标红的条件控制 删哪个就传哪个的id&#xff0c;基于这个id去过滤掉相同id的项&#xff0c;把剩下的项返回 <td><a click.p…...

Docker:WARNING: Published ports are discarded when using host network mode 解决方法

在Docker中&#xff0c;使用主机网络模式&#xff08;host network mode&#xff09;时&#xff0c;容器将共享主机的网络命名空间&#xff0c;这意味着容器将直接使用主机的网络接口和端口。因此&#xff0c;当你尝试通过Docker的发布端口功能&#xff08;publish a port&…...

音视频入门基础:MPEG2-TS专题(12)—— FFmpeg源码中,把各个transport packet组合成一个Section的实现

一、引言 从《音视频入门基础&#xff1a;MPEG2-TS专题&#xff08;9&#xff09;——FFmpeg源码中&#xff0c;解码TS Header的实现》可以知道&#xff1a;FFmpeg源码中使用handle_packet函数来处理一个transport packet&#xff08;TS包&#xff09;&#xff0c;该函数的前半…...

【数据结构】二叉树的性质和存储结构

性质 在二叉树的第i层上至多有2^{i-1}个结点,至少有1个结点 深度为k的二叉树至多有2^{k-1}个结点&#xff08;k≥1&#xff09;&#xff0c;至少有k个结点 对任何一棵二叉树T&#xff0c;如果其叶子数为n0&#xff0c;度为2的结点数为n2&#xff0c;则n0n21 具有n个结点的完…...

gbase8s之查看锁表的sql

#只能看当前锁表的sql&#xff0c;看不到历史的。 #使用方法&#xff1a;sh 脚本文件名 库名 表名 database$1 table$2 hexoncheck -pt $database:$table|grep -i partnum|awk {printf ("%x|",$3)} #echo $hex #echo ${hex%?} #ownonstat -k |grep -iE ${he…...

URI 未注册(设置 语言和框架 架构和 DTD)

一、问题描述&#xff1a;在springboot项目中的resources中新建mybatis-config.xml文件时&#xff0c;从mybatis文档中复制的代码报错&#xff1a;URI 未注册(设置 | 语言和框架 | 架构和 DTD) 二、解决&#xff1a;在Springboot项目的设置->架构和DTD中添加 红色的网址&…...

别再为OSGB数据导入SuperMap iDesktop发愁了!手把手教你搞定倾斜摄影配置文件生成与常见报错

三维GIS实战&#xff1a;从OSGB到SuperMap iDesktop的完整避坑指南 当无人机航拍的倾斜摄影数据第一次在SuperMap iDesktop中成功加载时&#xff0c;那种从二维平面跃入三维空间的震撼感&#xff0c;是每个GIS从业者都难忘的体验。然而&#xff0c;这份喜悦往往被配置文件生成失…...

物联网平台资本逻辑与开发实战:从涂鸦融资看行业价值回归

1. 从资本视角看物联网平台&#xff1a;一场关于“入口”与“生态”的持久战最近和几个做硬件的朋友聊天&#xff0c;大家不约而同地提到了一个词&#xff1a;“上云”。这个“云”&#xff0c;指的就是物联网开发平台。从智能家居的插座、灯泡&#xff0c;到工业产线上的传感器…...

3步解决Beyond Compare 5评估模式错误:密钥生成与完全激活指南

3步解决Beyond Compare 5评估模式错误&#xff1a;密钥生成与完全激活指南 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 当Beyond Compare 5的30天评估期结束后&#xff0c;软件会显示"评…...

Linux 系统安装 MySQL(CentOS8/Ubuntu),命令行实操完整版

前言开发和服务器部署基本都是 Linux 环境&#xff0c;本篇手把手教你 CentOS8 和 Ubuntu 两大主流系统命令行安装 MySQL&#xff0c;全程命令复制即用&#xff0c;无多余操作。一、通用前置准备关闭防火墙、关闭 SELinux&#xff08;服务器环境可选&#xff09;bash运行# Cent…...

LLM资源库:大语言模型开发者的高效导航与实战指南

1. 项目概述&#xff1a;一个汇聚LLM资源的“藏宝图”在人工智能&#xff0c;特别是大语言模型&#xff08;LLM&#xff09;领域&#xff0c;技术迭代的速度快得让人眼花缭乱。每天都有新的模型发布、新的工具开源、新的论文发表。对于开发者、研究者甚至是刚入门的学习者来说&…...

dnSpyEx终极指南:5个技巧快速掌握.NET程序调试与编辑

dnSpyEx终极指南&#xff1a;5个技巧快速掌握.NET程序调试与编辑 【免费下载链接】dnSpy Unofficial revival of the well known .NET debugger and assembly editor, dnSpy 项目地址: https://gitcode.com/gh_mirrors/dns/dnSpy 还在为调试没有源代码的.NET程序而烦恼&…...

3分钟掌握网页视频下载:Chrome扩展VideoDownloadHelper完全指南

3分钟掌握网页视频下载&#xff1a;Chrome扩展VideoDownloadHelper完全指南 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 你是否曾经遇到想…...

md-wechat:让Markdown完美兼容微信公众号排版的工具实战

1. 项目概述&#xff1a;一个让Markdown在微信生态里“活”起来的工具如果你和我一样&#xff0c;是个重度Markdown爱好者&#xff0c;同时又需要在微信生态里频繁地分享技术文档、产品说明或者个人笔记&#xff0c;那你一定体会过那种割裂感。在Typora或VS Code里写得行云流水…...

使用 Taotoken 后模型 API 响应延迟与稳定性效果实测观察

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 使用 Taotoken 后模型 API 响应延迟与稳定性效果实测观察 作为一名需要频繁调用大模型 API 的开发者&#xff0c;模型服务的响应速…...

Airtable MCP服务器:AI与数据协作的自动化新范式

1. 项目概述&#xff1a;当Airtable遇上MCP&#xff0c;数据协作的自动化新范式 如果你和我一样&#xff0c;日常工作中重度依赖Airtable来管理项目、追踪任务、甚至搭建轻量级的业务系统&#xff0c;那你一定也遇到过这样的痛点&#xff1a;数据是活的&#xff0c;但流程是死…...