南充 网站开发/百度推广开户费用
前言:
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,是创建了一个类方法。】
类方法的主要作用包括:
访问类变量:类方法可以直接访问类的变量,而不需要创建类的实例。
创建实例:类方法可以用来创建类的实例,这在工厂模式中很常见。
修改类状态:类方法可以修改类的状态,比如添加类变量或者修改类属性。
继承时保持一致性:在继承时,类方法可以确保子类能够访问父类的类方法。
实现单例模式:类方法可以用来实现单例模式,确保一个类只有一个实例。
【案,类的方法有别于传统定义的方法,其实就是提供一个直接方法类定义的途径,以避免之前构建单例模式和工厂那种形而上学的方式(比如前面的单例构建,其实通过类方法就很简洁,不需要构造一个单例】
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
的缺点:
灵活性:静态方法不能被子类重写,这限制了它们的灵活性。如果你需要在子类中改变创建实例的行为,静态方法不是一个好选择。
继承:由于静态方法不属于类的MRO(方法解析顺序),它们不能被继承。
多态性:静态方法不支持多态,这意味着你不能在子类中重写它们来改变行为。
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 服务器优化之后,加了多线程,对心跳包进行优化 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报表 功能实现:工作台、数据导出 工作台效果图: 数据导出效果图: 在数据统计页面点击数据导出:生成Excel报表 1. 工作台 1.1 需求分析和设计 1.1.1 产品原…...

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

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

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

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

Docker:WARNING: Published ports are discarded when using host network mode 解决方法
在Docker中,使用主机网络模式(host network mode)时,容器将共享主机的网络命名空间,这意味着容器将直接使用主机的网络接口和端口。因此,当你尝试通过Docker的发布端口功能(publish a port&…...

音视频入门基础:MPEG2-TS专题(12)—— FFmpeg源码中,把各个transport packet组合成一个Section的实现
一、引言 从《音视频入门基础:MPEG2-TS专题(9)——FFmpeg源码中,解码TS Header的实现》可以知道:FFmpeg源码中使用handle_packet函数来处理一个transport packet(TS包),该函数的前半…...

【数据结构】二叉树的性质和存储结构
性质 在二叉树的第i层上至多有2^{i-1}个结点,至少有1个结点 深度为k的二叉树至多有2^{k-1}个结点(k≥1),至少有k个结点 对任何一棵二叉树T,如果其叶子数为n0,度为2的结点数为n2,则n0n21 具有n个结点的完…...

gbase8s之查看锁表的sql
#只能看当前锁表的sql,看不到历史的。 #使用方法: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)
一、问题描述:在springboot项目中的resources中新建mybatis-config.xml文件时,从mybatis文档中复制的代码报错:URI 未注册(设置 | 语言和框架 | 架构和 DTD) 二、解决:在Springboot项目的设置->架构和DTD中添加 红色的网址&…...

Ubuntu上使用system()函数运行不需要输入密码
使用system()运行一些终端命令的时候,需要sudo权限,也就是必须输入密码,那么在程序自启动的时候就无法成功启动。如果设置Ubuntu下所有操作都不需要密码,安全性太低,所以我们可以将需要用到的终端指令给予无需输入密码…...

【MySQL】数据库必备知识:全面整合表的约束与深度解析
前言:本节内容讲述表的约束的相关内容。 表的约束博主将会通过两篇文章进行讲解, 这是第一篇上半部分。 讲到了约束概念。 以及几种常见约束。下面友友们开始学习吧! ps:友友们使用了mysql就可以放心观看喽! 目录 表的约束概念 …...

Windows下Docker快速安装使用教程
在当今软件开发和部署的世界中,Docker 已经成为一个不可或缺的工具。这里不对Docker进行详细阐述,需要系统学习Docker的伙伴可寻求更专业详细的教程或书籍学习。本文主要讲解Windows系统下Docker安装及使用。 一、环境准备 1.1检查电脑是否开启虚拟化 …...

PTA DS 6-2 另类堆栈 (C补全函数)
6-2 另类堆栈 分数 15 全屏浏览 切换布局 作者 DS课程组 单位 浙江大学 在栈的顺序存储实现中,另有一种方法是将Top定义为栈顶的上一个位置。请编写程序实现这种定义下堆栈的入栈、出栈操作。如何判断堆栈为空或者满? 函数接口定义: …...

rk3568之mpp开发笔记mpp移植到开发板
前言: 大家好,今天给大家介绍的内容是rk平台的mpp编解码这块的内容,在rk目前看到有三套框架涉及到编解码内容: 1、rkmedia 2、rockit 3、mpp 这三种不同形式的编解码方式,后面再做详细的框架对比,今天我…...

Vue解决跨域问题
要解决 Vue 项目的跨域问题并通过 vue.config.js 配置代理,可以按照以下步骤修改 vue.config.js 文件。你提供的代码大部分已经正确,只需要做一些格式上的调整。以下是正确的 vue.config.js 配置: // vue.config.jsmodule.exports {devServ…...

Kubernetes Nginx-Ingress | 禁用HSTS/禁止重定向到https
目录 前言禁用HSTS禁止重定向到https关闭 HSTS 和设置 ssl-redirect 为 false 的区别 前言 客户请求经过ingress到服务后,默认加上了strict-transport-security,导致客户服务跨域请求失败,具体Response Headers信息如下; 分析 n…...

TortoiseGit的下载、安装和配置
一、TortoiseGit的简介 tortoiseGit是一个开放的git版本控制系统的源客户端,支持Winxp/vista/win7.该软件功能和git一样 不同的是:git是命令行操作模式,tortoiseGit界面化操作模式,不用记git相关命令就可以直接操作,读…...

如何绕过IP禁令
网站、游戏和应用程序可以屏蔽特定IP地址,从而阻止使用该IP地址的任何人访问其服务。这称为IP禁令。管理员可以出于多种原因(例如发出过多请求或可疑活动)屏蔽IP地址。但是,这些禁令会使收集数据或访问在线内容变得更加困难。 一…...

Vue3的provide和inject实现多级传递的原理
先来看个demo,这个是父组件,代码如下: <template><ChildDemo /> </template><script setup> import ChildDemo from "./child.vue"; import { ref, provide } from "vue"; // 提供响应式的值 c…...