python实现单例模式的常用三种方法-基于__new__/使用装饰器以及Python中的值类型、引用类型以及类的静态变量、读取进程和线程ID

news2024/11/25 9:45:55

一、python实现单例模式的常用三种方法-基于__new__,使用装饰器

        涉及到类的使用就会有类的实例化,就会有类单例实现的需求,因为重复实例化会浪费资源。python中的单例模式与别的语言相比,单例实现的方法更丰富。虽然python实现单例的模式的方法有很多,不过在体验后我觉得有必要了解和掌握的也就是使用模块和使用装饰器两种,然后了解一下使用__new__方法实现单例。

1. 使用python模块

        Python模块本身就包含了一个单例实现逻辑,在第一次导入时,会生成.pyc文件,之后导入,就会直接加载.pyc,因此如果在我们在模块中new实例对象,然后在其它的地方直接引用生成的对象,就是单例模式了,python模块singleton.py内容如下:

#模块中的方法
class Singleton(object):
    def test(self):
        print("test")

#直接初始化类	
singleton = Singleton()

在其它的地方使用时,直接导入此文件中的对象即是单例模式的对象
from singleton import singleton

2. 使用__new__方法

        因为python实例化对象的逻辑是先执行类的__new__方法(默认调用object.__new__)实例化对象,再执行类的__init__方法对这个对象进行初始化,所有我们可以在__new__方法中进行控制以实现单例模式,代码示例如下:

class Singleton(object):
    
    def __init__(self):
        pass

    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
			if not hasattr(Singleton, "_instance"):
				Singleton._instance = object.__new__(cls)  
        return Singleton._instance

3. 使用装饰器实现单例模式

        上面的使用__new__方法需要在每个类中去定义方法体,而使用装饰器则可以实现定义一个方法体,然后装饰给所有我们要实现单例模式的类即可,重复利用并简化代码。推荐使用第3种方法.

#定义一个单例方法
def Singleton(cls):
    _instance = {}

    def _singleton(*args, **kargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kargs)
        return _instance[cls]

    return _singleton

#装饰给所有我们要实现单例模式的类即可
@Singleton
class Test(object):
    def test_fun(self):
		pass

        关于线程安全的单例模式,上述第2、3种方法能实现单例模式,但并不是线程安全的单例模式,如果有需求实现线程安全,可以进行改造,添加threading模块并进行加锁控制。示例如下。

# 使用__new__方法创建基于线程安全的单例模式
import threading
class Singleton(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        pass

    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = object.__new__(cls)  
        return Singleton._instance
		
# 使用__new__方法创建基于线程安全的单例模式	
import threading
def Singleton(cls):
    _instance = {}
	lock = threading.Lock()

    def _singleton(*args, **kargs):
		with lock:
			if cls not in _instance:
				_instance[cls] = cls(*args, **kargs)
        return _instance[cls]

    return _singleton

#装饰给所有我们要实现单例模式的类即可
@Singleton
class Test(object):
    def test_fun(self):
		pass

        关于多线程模块,thread模块已被废弃,在Python3中不能再使用thread模块。用户可以使用threading模块代替。

二、Python中的值类型、引用类型以及类的-静态-变量

        Python中的数据类型分为值类型和引用类型,值类型通常包含int、float、bool、str、tuple,值类型是不可变的。引用类型包含list、set、dict类型,引用类型是可变的。在python的面向对象中,类不存在像其它语言中存在的static关键词,因此不能使用修饰实现类的静态变量。python面向对象中只有实例变量和类变量两变量概念,根本不存在静态变量的概念。

        接下来我们来看下面这个例子以及其运行结果,结果中有横线来区分开每个执行结果,比较好分别,如下:

#定义四个方法,各操作一些属性
class task1:
    value=1
    def increment(self):
        self.value += 1

class task2:
    value=[]
    def increment(self):
        self.value.append(1)

class task3:
    def __init__(self):
        self.value=[]
    def increment(self):
        self.value.append(1)

class task4:
    value=1
    def increment(self):
        self.value += 1
		
#分别调用四个方法	
if __name__=="__main__":
    a=task1()
    b=task1()
    a.increment()
	print(a.value)
    print(b.value)
    print('-'*30)
	
	a=task2()
    b=task2()
    a.increment()
	print(a.value)
    print(b.value)
    print('-'*30)
	
	a=task3()
    b=task3()
    a.increment()
	print(a.value)
    print(b.value)
    print('-'*30)
	print('-'*30)

    a=task4()
    b=task4()
    task4.value+=1
    print(a.value)
	print(b.value)
    a.increment()
    print(a.value)
    print(b.value)
    print(task4.value)

程序运行结果如下:

===========运行结果=================
2
1
------------------------------
[1]
[1]
------------------------------
[1]
[]
------------------------------
2
2
3
2
2

第1个示例应该如我们预期,只改变了a而b的没有变更。
第2个示例和第1个基本相同,但结果却是a和b都同时发生了改变。
第3个示例在2示例上做了一些改变,从而符合我们的预期。
第4个示例我们改变了task4的属性,其它的类的属性有的有影响,有的却没有影响。
是为什么呢?
    第1个和第2个示例的相同点是都是类的属性,但一个是值类型,一个是引用类型。引用类型的类变量就如同我们其它语言的静态变量,尽管python没有静态变量的概念,但这样操作就实现了静态变量的功能。第3个示例和第2个的区别是第3个用的是实例的变量,所以各自归各自管理。第4个示例,实例化a和b的时候,他们都没有对属性value进行操作,所以打印出来的都是类task4的属性value,而在对象对自己的value进行操作之后,就与类的属性脱离关系,变成自己的属性。 

三、Python中读取程序中的进程和线程ID

    程序调试的时候有时需要看看当前程序的进程和线程ID,可以使用如下的方法。

#引入OS和psutil库
import os
import psutil
import threading

#取得python进程数据
pid = os.getpid()
p = psutil.Process(pid)
print('PID: %d' % pid)
print('PNAME: %s' % p.name())
print(p.__dict__)

#取得线程ID数据
t = threading.currentThread()
print("TID: %d" % t.ident)
print("TID: %d" % t.name)
print("TNAME: %S" % t.getName())
print(t.__dict__)

#print(p)打印出来的结果
psutil.Process(pid=14572, name='python.exe', status='running', started='18:46:27')
#print(p.__dict__)打印出来的结果格式化之后
{
	'_pid': 15144,
	'_name': 'python.exe',
	'_exe': None,
	'_create_time': 1629788019.0382779,
	'_gone': False,
	'_hash': None,
	'_lock': < unlocked _thread.RLock object owner = 0 count = 0 at 0x0000020F41511840 > ,
	'_ppid': None,
	'_proc': < psutil._pswindows.Process object at 0x0000020F416E4700 > ,
	'_last_sys_cpu_times': None,
	'_last_proc_cpu_times': None,
	'_exitcode': < object object at 0x0000020F41BAE470 > ,
	'_ident': (15144, 1629788019.0382779)
}

#print(t)打印出来的结果
<_MainThread(MainThread, started 15280)>
#print(t.__dict__)打印出来的结果格式化之后
{
	'_target': None,
	'_name': 'MainThread',
	'_args': (),
	'_kwargs': {},
	'_daemonic': False,
	'_ident': 7652,
	'_native_id': 7652,
	'_tstate_lock': < locked _thread.lock object at 0x000002A0A834AA20 > ,
	'_started': < threading.Event object at 0x000002A0A834A7F0 > ,
	'_is_stopped': False,
	'_initialized': True,
	'_stderr': < _io.TextIOWrapper name = '<stderr>'
	mode = 'w'
	encoding = 'gbk' > ,
	'_invoke_excepthook': < function _make_invoke_excepthook. < locals > .invoke_excepthook at 0x000002A0A8352CA0 >
}

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

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

相关文章

MobaXterm使用

Linux连接工具MobaXterm详细使用教程-CSDN博客

Elasticsearch学习笔记(五)Elastic stack安全配置二

一、手动配置http层SSL 通过前面的配置&#xff0c;我们为集群传输层手动配置了TLS&#xff0c;集群内部节点之间的通信使用手动配置的证书进行加密&#xff0c;但是集群与外部客户端的http层目前还是使用的自动配置&#xff0c;集群中HTTP的通信目前仍然使用自动生成的证书ht…

【韩顺平Java笔记】第7章:面向对象编程(基础部分)【227-261】

文章目录 227. 重载介绍228. 重载快速入门229. 重载使用细节230. 重载课堂练习1231. 232. 重载课堂练习2,3233. 可变参数使用233.1 基本概念233.2 基本语法233.3 快速入门案例 234. 可变参数细节235. 可变参数练习236. 作用域基本使用237. 作用域使用细节1238. 作用域使用细节2…

Docker安装部署和常用命令

Docker 是一种开源的平台&#xff0c;旨在帮助开发者和运维人员更轻松地创建、部署和运行应用程序。通过将应用程序及其依赖项打包到一个名为容器的标准化单位中&#xff0c;Docker 提供了一种轻量级的虚拟化解决方案。与传统虚拟机相比&#xff0c;Docker 容器可以在同一主机上…

GoogleNet原理与实战

在2014年的ImageNet图像识别挑战赛中&#xff0c;一个名叫GoogLeNet 的网络架构大放异彩。以前流行的网络使用小到11&#xff0c;大到77的卷积核。本文的一个观点是&#xff0c;有时使用不同大小的卷积核组合是有利的。 回到他那个图里面你会发现,这里的一个通过我们最大的池化…

12条职场经验总结

01 事干得好不好尚且不说&#xff0c;但是话一定要说得漂亮。 比如&#xff0c;当领导给你安排工作的时候&#xff0c;你一定要非常积极地响应&#xff0c;拍着胸脯跟领导说“放心吧”。至于后续到底怎么干&#xff0c;再结合实际情况有的放矢地把握。 02 当别人夸奖你的时…

记录使用crypto-js、jsencrypt实现js加密的方法

实用为主&#xff0c;直接上干货。 使用工具&#xff1a;pycharm专业版2020.3.2。 记录通过crypto-js模块、jsencrypt模块两种方式实现加密。 本文在pycharm中新建一个项目&#xff0c;一步一步记录实现步骤。 一、新建pycharm项目并新建两个js文件&#xff0c;分别命名为c…

Python 工具库每日推荐 【Requests】

文章目录 引言Python网络库的重要性今日推荐:Requests工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例1:获取天气信息案例分析案例2:文件上传案例分析高级特性会话和Cookie处理自定义请求头超时设置代理设置扩展阅读与资源优缺点分析优点:缺…

Markdown 语法详解大全(超级版)(三)——甘特图语法详解

Markdown 语法详解大全(超级版)&#xff08;三&#xff09;——甘特图语法详解 Markdown 语法详解大全(超级版)&#xff08;一&#xff09; Markdown 语法详解大全(超级版)&#xff08;二&#xff09; Markdown 语法详解大全(超级版)&#xff08;三&#xff09; Markdown 语法…

[Linux#61][UDP] port | netstat | udp缓冲区 | stm32

目录 0. 预备知识 1. 端口号的划分范围 2. 认识知名端口号 3. netstat 命令 4. pidof 命令 二.UDP 0.协议的学习思路 1. UDP 协议报文格式 报头与端口映射&#xff1a; 2. UDP 的特点 面向数据报&#xff1a; 3. UDP 的缓冲区 4. UDP 使用注意事项 5. 基于 UDP 的…

栈的介绍与实现

一. 概念与结构 栈&#xff1a;⼀种特殊的线性表&#xff0c;其只允许在固定的⼀端进⾏插⼊和删除元素操作。进⾏数据插⼊和删除操作的⼀端称为栈顶&#xff0c;另⼀端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out的原则。 压栈&#xff1a;栈的插…

平面电磁波(解麦克斯韦方程)电场相位是复数的积分常数,电场矢量每个分量都有一个相位。磁场相位和电场一样,这是因为无损介质中实数的波阻抗

注意无源代表你立方程那个点xyzt处没有源&#xff0c;电场磁场也是这个点的。 j电流面密度&#xff0c;电流除以单位面积&#xff0c;ρ电荷体密度&#xff0c;电荷除以单位体积。 j方程组有16个未知数&#xff0c;每个矢量有三个xyz分量&#xff0c;即三个未知数&#xff0c;…

k8s的简介和部署

一、k8s简介 在部署应用程序的方式上面&#xff0c;主要经历了三个阶段&#xff1a; 传统部署:互联网早期&#xff0c;会直接将应用程序部署在物理机上优点:简单&#xff0c;不需要其它技术的参与缺点:不能为应用程序定义资源使用边界&#xff0c;很难合理地分配计算资源&…

fiddler抓包18-1_导出jmeter脚本(jmx文件)

课程大纲 方法1 ① 下载2个扩展文件&#xff0c;FiddlerExtensions.dll和FiddlerExtensions.pdb&#xff0c;到Fiddler根目录中的“ImportExport”下&#xff0c;重启Fiddler。 下载链接: https://pan.baidu.com/s/1qtLoaiTd-VfHFb3UIPoSZw?pwdtwcu提取码: twcu ② Fiddler导…

UIAbility组件

一、作用 UIAbility组件是系统调度的基本单元,为应用提供绘制界面的窗口。一个应用可以包含一个或多个UIAbility组件 1、每一个UIAbility组件实例都会在最近任务列表中显示一个对应的任务。 如果开发者希望在任务视图中看到一个任务,建议使用“一个UIAbility+多个页面”的方…

Qt教程(002):Qt项目创建于框架介绍

二、创建Qt项目 2.1 创建项目 【1、New Project】 【2、选择Qt Widgets Application】 【3、设置项目名称和保存路径】 注意&#xff0c;项目名称和路径不要带中文。 【4、选择QWidget】 带菜单栏的窗口QMainWindow空白窗口QWidget对话框窗口QDialog 【5、编译】 2.2 项目框…

No.3 笔记 | Web安全基础:Web1.0 - 3.0 发展史

大家好&#xff01;作为一个喜欢探索本质的INTP&#xff0c;我整理了一份简明易懂的Web安全笔记。希望能帮助你轻松掌握这个领域的核心知识。 这份笔记涵盖了Web发展的历程&#xff0c;从静态的Web 1.0到智能化的Web 3.0。我们将探讨URL和HTTP协议&#xff0c;揭示它们在网络中…

【深度学习基础模型】神经图灵机(Neural Turing Machines, NTM)详细理解并附实现代码。

【深度学习基础模型】神经图灵机&#xff08;Neural Turing Machines, NTM&#xff09;详细理解并附实现代码。 【深度学习基础模型】神经图灵机&#xff08;Neural Turing Machines, NTM&#xff09;详细理解并附实现代码。 文章目录 【深度学习基础模型】神经图灵机&#xf…

利用条件概率解决“两个孩子的性别问题”

利用条件概率解决“两个孩子的性别问题”&#xff1a;深入分析与扩展 在日常生活中&#xff0c;概率问题常常会带来直观上的困惑&#xff0c;尤其是在涉及到条件概率的时候。今天我们讨论的这个问题是一个非常经典的例子&#xff1a;已知一对父母有两个孩子&#xff0c;其中一…