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,需要写一点构造实例的方法,但是,比静态方法要简洁,此外,也更容易做多态的变换】

对应工厂模式而言:

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

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

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

相关文章

图像边缘检测示例(综合利用阈值分割、数学形态学和边缘检测算子)

一、问题 读入一副灰度图像(如果是彩色图像,可以先将其转化为灰度图像),然后提取比较理想的灰度图像边缘。这里以moon.tif为例。 二、算法 大家一开始容易想到直接利用MATLAB的内置函数edge并采用不同边缘提取算子进行边缘提取&a…

[高考] 学习数学的难点

最近想看一些机器学习的书,发现很多概念,很多符号,很多地方是,不知道具体的意思,不懂其中的内涵,所以需要再重新查阅很多的资料,去理解作者每句话是什么意思。 总结一下难点。以詹姆斯-斯图尔特…

R语言的数据结构-向量

【图书推荐】《R语言医学数据分析实践》-CSDN博客 《R语言医学数据分析实践 李丹 宋立桓 蔡伟祺 清华大学出版社9787302673484》【摘要 书评 试读】- 京东图书 (jd.com) R语言编程_夏天又到了的博客-CSDN博客 在R语言中,数据结构是非常关键的部分,它提…

js 抢红包场景

核心是实际业务场景问题和精度控制问题 class RedPackage {constructor(money, num) {this._money moneythis._num num}getRandomMoney () {if(this._num 1) return this._moneyconst mm parseInt(((this._money - ((this._num -1) * 0.01)) * Math.random() 0.01) * Mat…

集成方案 | Docusign + 泛微,实现全流程电子化签署!

本文将详细介绍 Docusign 与泛微的集成步骤及其效果,并通过实际应用场景来展示 Docusign 的强大集成能力,以证明 Docusign 集成功能的高效性和实用性。 在现代企业运营中,效率和合规性是至关重要的。泛微作为企业级办公自动化和流程管理的解决…

Docker Compose应用实战

文章目录 1、使用Docker Compose必要性及定义2、Docker Compose应用参考资料3、Docker Compose应用最佳实践步骤1_概念2_步骤 4、Docker Compose安装5、Docker Compose应用案例1_网站文件准备2_Dockerfile文件准备3_Compose文件准备4_使用docker-compose up启动容器5_访问6_常见…

51c大模型~合集88

我自己的原文哦~ https://blog.51cto.com/whaosoft/12805165 #Number Cookbook 数字比你想得更复杂——一文带你了解大模型数字处理能力的方方面面 目前大语言模型(Large Language Models, LLMs)的推理能力备受关注。从思维链(Chain of…

LVS能否实现两台服务器的负载均衡

LVS能否实现两台服务器的负载均衡 是的,LVS(Linux Virtual Server)可以实现两台服务器的负载均衡,并且它非常适合这种场景。 LVS(Linux Virtual Server)简介: LVS 是一种基于 Linux 的负载均…

STP(生成树协议)

STP的基本概念 概述 STP是一个用于局域网中消除环路的协议。运行该协议的设备通过彼此交互信息而发现网络中的环路,并对某些接口进行阻塞以消除环路。STP在网络中运行后会持续监控网络的状态,当网络出现拓扑变更时,STP能够感知并且进行自动…

GLM-4-Plus初体验

引言:为什么高效的内容创作如此重要? 在当前竞争激烈的市场环境中,内容创作已成为品牌成功的重要支柱。无论是撰写营销文案、博客文章、社交媒体帖子,还是制作广告,优质的内容不仅能够帮助品牌吸引目标受众的注意力&a…

Android IO 性能优化:全面解析与实践

文章目录 前言1、文件系统与 I/O 流程原理1.1 文件系统架构1.2 文件 I/O 流程 2、优化策略与场景适用2.1 异步 I/O2.2 合并文件操作2.3 页缓存优化2.4 内存映射文件 3. 性能监控与验证总结 前言 在现代 Android 应用中,I/O 性能直接影响用户体验。流畅的响应速度和…

Jetpack Compose赋能:以速破局,高效打造非凡应用

Android Compose 是谷歌推出的一种现代化 UI 框架,基于 Kotlin 编程语言,旨在简化和加速 Android 应用开发。它以声明式编程为核心,与传统的 View 系统相比,Compose 提供了更直观、更简洁的开发体验。以下是对 Android Compose 的…

MinerU:PDF文档提取工具

目录 docker一键启动本地配置下载模型权重文件demo.py使用命令行启动GPU使用情况 wget https://github.com/opendatalab/MinerU/raw/master/Dockerfile docker build -t mineru:latest .docker一键启动 有点问题,晚点更新 本地配置 就是在Python环境中配置依赖和…

UE4_控件蓝图_制作3D生命血条

一:效果图如下: 二、实现步骤: 1、新建敌人 右键蓝图类 选择角色, 重命名为BP_Enemytest。 双击打开,配置敌人网格体 修改位置及朝向 效果如下: 选择合适的动画蓝图类: 人物就有了动作&#x…

【深度学习】深刻理解ViT

ViT(Vision Transformer)是谷歌研究团队于2020年提出的一种新型图像识别模型,首次将Transformer架构成功应用于计算机视觉任务中。Transformer最初应用于自然语言处理(如BERT和GPT),而ViT展示了其在视觉任务…

用于日语词汇学习的微信小程序+ssm

日语词汇学习小程序是高校人才培养计划的重要组成部分,是实现人才培养目标、培养学生科研能力与创新思维、检验学生综合素质与实践能力的重要手段与综合性实践教学环节。本学生所在学院多采用半手工管理日语词汇学习小程序的方式,所以有必要开发日语词汇…

代码随想录-算法训练营day48(动态规划10:买卖股票的最佳时机,买卖股票的最佳时机2)

第九章 动态规划part10● 121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II 详细布置 股票问题是一个动态规划的系列问题,今日安排的题目不多,大家可以慢慢消化。121. 买卖股票的最佳时机 视频讲解:https://www.bilibili.com/video/BV…

docker xxxx is using its referenced image ea06665f255d

Error response from daemon: conflict: unable to remove repository reference “registrxxxxxx” (must force) - container 9642fd1fd4a0 is using its referenced image ea06665f255d 这个错误表明你尝试删除的镜像正在被一个容器使用,因此无法删除。要解决这…

go高性能单机缓存项目

代码 // Copyright 2021 ByteDance Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apach…

ichunqiu-2024年春秋杯网络安全联赛夏季赛-brother

1.打开题目,看到题目我就想到了再后面加一个ls,结果回显了ls,然后又想到会不会是模板注入,尝试{{7*7}},然后页面返回了49,说明存在模板注入 如下,判定为模板注入 看一下系统环境配置 然后看可…