大厂面试真实案例!Python实现单例模式的五种写法!转载
原创大家好,我是菜鸟兄弟!大家好,我是菜鸟兄弟!大家好,我是菜鸟兄弟!大家好,我是菜鸟兄弟!
大厂面试python如果你不提前做好准备,突然问,老鸟有点不知所措。单人模式是什么?
单件模式(单件模式Singleton Pattern) 是一种常见的软件设计模式,其主要目的是确保特定类只存在一个实例。当您只想让一个类的一个实例出现在整个系统中时,Singleton对象就派上了用场。
例如,服务器程序的配置信息存储在文件中,客户端可以通过 AppConfig 类从配置文件中读取信息。如果在程序运行期间有许多地方使用配置文件的内容,即需要在许多地方创建 AppConfig 对象,这导致存在多个 AppConfig 实例对象,这可能会严重浪费内存资源,特别是在存在大量配置文件内容的情况下。
事实上,类似于事实,类似于 AppConfig 对于这样的类,我们希望在程序运行时期间只存在一个实例对象。
在 Python 单例模式可以通过多种方式实现。
-
使用模块
-
使用装饰器使用装饰器使用装饰器使用装饰器
-
使用类
-
基于
__new__
方法实现 -
基于 metaclass 方式实现
以下是详细情况。在此详细说明。以下是一些细节。以下是更多细节。
使用模块
其实,Python 模块是一种自然的单例模式,因为模块生成 .pyc
文件,当第二次导入完成时,它将直接加载 .pyc
文件,而无需再次执行模块代码。
因此,我们只需要在一个模块中定义相关的函数和数据,就可以获得单个实例对象。
如果我们真的想要一个单人班,考虑一下。
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
将上述代码保存在文件中 mysingleton.py 如果您想使用它,可以将该文件中的对象直接导入到其他文件中,该对象是Singleton模式的对象
from mysingleton import singleton
使用装饰器使用装饰器使用装饰器使用装饰器
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 A(object):
a = 1
def __init__(self, x=0):
self.x = x
a1 = A(2)
a2 = A(3)
使用类
class Singleton(object):
def __init__(self):
pass
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
一般来说,人们认为这就完成了单例模式,但在使用多线程时会出现问题。
class Singleton(object):
def __init__(self):
pass
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
import threading
def task(arg):
obj = Singleton.instance()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
执行程序后,将打印以下结果。
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
似乎也不是问题,那是因为执行太快了,如果 __init__
有一些方法有很多方法有几种方法 IO 操作时,您会发现问题所在。操作时,您会看到问题所在。手术,你就会发现问题所在。操作,就会发现问题所在。
这里我们穿过下面我们穿过这里我们穿过下面我们穿过 time.sleep
模拟,我们有上面的模拟 __init__
下面的代码被添加到该方法中。方法,并使用以下代码。
def __init__(self):
import time
time.sleep(1)
重新执行程序后,结果如下所示。
<__main__.Singleton object at 0x034A3410>
<__main__.Singleton object at 0x034BB990>
<__main__.Singleton object at 0x034BB910>
<__main__.Singleton object at 0x034ADED0>
<__main__.Singleton object at 0x034E6BD0>
<__main__.Singleton object at 0x034E6C10>
<__main__.Singleton object at 0x034E6B90>
<__main__.Singleton object at 0x034BBA30>
<__main__.Singleton object at 0x034F6B90>
<__main__.Singleton object at 0x034E6A90>
出现了一个问题!如上创建的单实例不支持多线程。
解决方案:锁定!解锁部分并行执行,锁定部分串联执行,降低了速度,但保证了数据安全。
import time
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
time.sleep(1)
@classmethod
def instance(cls, *args, **kwargs):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
def task(arg):
obj = Singleton.instance()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
time.sleep(20)
obj = Singleton.instance()
print(obj)
打印结果如下。打印输出结果如下。结果打印如下。打印输出如下所示。
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
差不多就是这样,但是当程序执行时仍然有一个小问题, time.sleep(20)
之后,当实例化下面的对象时,它此时已经是单例模式。
但我们还是加了锁,这不是很好,然后进行了一些优化 intance
方法,只需将其更改为以下内容即可。
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
这样,可以支持多个线程的单实例模式就完成了。 +
import time
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
time.sleep(1)
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
def task(arg):
obj = Singleton.instance()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
time.sleep(20)
obj = Singleton.instance()
print(obj)
以这种方式实现的单例模式在使用上受到限制,以后的实例化必须通过 obj = Singleton.instance()
如果用 obj = Singleton()
这不是一个单一的例子。这不是一个单一的案例。这不是一件独一无二的事情。
基于 __new__
方法实现
通过上面的例子,我们可以知道当我们实现单个实例时,为了确保线程安全,我们需要在内部添加锁。
我们知道,当我们实例化一个对象时,我们首先执行类 __new__
方法(当我们不编写它时,默认调用是 object.__new__
),实例化对象;然后执行类 __init__
方法来初始化这个对象,我们所能做的就是在此基础上实现单例模式。
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
obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)
def task(arg):
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
打印结果如下。打印输出结果如下。结果打印如下。打印输出如下所示。
<__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
使用单例模式的这种方法,稍后将以与通常实例化相同的方式实例化对象 obj = Singleton()
。
基于 metaclass 方式实现
相关知识:
-
类由 type 创建,在创建类时,创建,在创建类时创建,在创建类时type 的
__init__
方法被自动执行,类方法被自动执行,类() 执行 type 的__call__
方法(类的__new__
方法、类方法、类方法的类方法、__init__
方法) -
对象由类创建,在创建对象时,类
__init__
方法被自动执行,对象方法被自动执行,对象()执行类的__call__
方法
例子:
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
pass
obj = Foo()
# 执行type的 __call__ 方法,则调用该方法,该方法调用调用该方法的方法,并调用 Foo类(是type的宾语(宾语)(宾语) __new__方法,该方法用于创建对象,然后调用 Foo类(是type的宾语(宾语)(宾语) __init__方法,该方法用于初始化对象。方法,用于初始化对象。用于初始化对象的方法。方法来初始化该对象。
obj() # 执行Foo的 __call__ 方法
元类的使用。元类的使用。元类的使用。元类的使用。
class SingletonType(type):
def __init__(self,*args,**kwargs):
super(SingletonType,self).__init__(*args,**kwargs)
def __call__(cls, *args, **kwargs): # 这里的cls,即Foo类
print(cls,cls)
obj = cls.__new__(cls,*args, **kwargs)
cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
return obj
class Foo(metaclass=SingletonType): # 指定创建Foo的type为SingletonType
def __init__(self,name):
self.name = name
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
obj = Foo(xx)
实现单例模式。单例模式的实现。实施单件模型。实现单例模式。
import threading
class SingletonType(type):
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with SingletonType._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
return cls._instance
class Foo(metaclass=SingletonType):
def __init__(self,name):
self.name = name
obj1 = Foo(name)
obj2 = Foo(name)
print(obj1,obj2)
作者:听风作者:听风
推荐阅读:
入门: 最完整的零基学习最全面的零基学习最完整的零基学习Python的问题 | 从零开始学习从零基础学习从零基础学习8个月的Python | 实战项目 |学Python这是捷径这是捷径就是这条捷径
干货:爬行豆瓣短评,电影《后来的我们》 | 38年NBA最佳球员分析最佳球员分析 | 从万众期待到口碑惨败!唐探3令人失望 | 笑新一天图龙记笑新一天图龙集 | 谜语之王回答灯谜之王灯谜之王谜语之王 |用Python人山人海素描图人山人海素描图人山人海 Dishonor太火了,我用机器学习做了一个迷你推荐系统电影
趣味:弹球游戏 | 九宫格 | 漂亮的花 | 两百行Python日常酷跑游戏日常酷跑游戏日常酷跑游戏!
AI: 会写诗的机器人会写诗的机器人会写诗的机器人 | 给图片上色给图片上色给图片上色 | 预测收入 | 《耻辱》太火了,我用机器学习做了一部迷你推荐系统电影
小工具: Pdf转Word易于修复表单和水印!易于处理的表单和水印!易于修复表单和水印!简单的表格和水印! | 一键把html将页面另存为网页另存为网页另存为pdf!| 再见PDF提款费!提款费!提款费!提款费用! | 用90构建最强大的代码行构建最强大的代码行构建最强大的代码行PDF转换器,word、PPT、excel、markdown、html一键转换 | 制作一个固定的低成本机票提醒!制作一张别针的低价机票提醒! |60代码行做了一个语音墙纸切换,天天见女士!
年度弹出式文案年度弹出式文案
-
1). 卧槽!Pdf转Word用Python轻松搞定 !
-
2).学Python闻起来好香!我用100一行代码做了一个网站,帮助人们做了一行代码,做了一个网站,帮助了人们做了一行代码,帮助了人们PS旅行图片赚鸡腿吃旅行图片赚鸡腿
-
3).第一次播放量过亿,火爆全网,我分析了《波妹》,发现了这些秘密
-
4). 80一行行代码!使用Python让救济金做正确的事做做的人做好事的人A梦分身
-
5).你必须掌握的东西你必须掌握20个python代码,简短而紧凑,永无止境的有用代码,简短而甜蜜,永无止境的有用的代码,简短而紧凑,永无止境的使用代码,简短而甜蜜,永无止境的用途
-
6). 30个Python古怪技能集古怪小贴士收藏古怪技能集
-
7). 我总结的80《菜鸟学习专页》《菜鸟学习专页》《菜鸟学习》Python精选干货.pdf》,都是干货
-
8). 再见Python!我要学Go了!2500词深度分析词深度分析词深度分析 !
-
9).发现一只舔狗的福利!这Python爬虫神器太酷了,不能自动下载女孩的照片
点击阅读原文点击查看点击点击阅读点击阅读原文点击查看B放我鸽子看录像!站在我的录像带上!在视频里放我鸽子!站在我的录像带上!
版权声明
所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除