python面试指南--Python 如何实现单例模式

Python 如何实现单例模式?请写出至少两种实现方法?

单例模式(Singleton Pattern) 是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。

事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

在 Python 中,我们可以用多种方法来实现单例模式:
1.使用模块; 2. 使 用 new ; 3.使用装饰器; 4. 使用元类(metaclass)。

(1)使用模块:

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成.pyc 文件,当第二次导入时,就会直接加载.pyc 文件,而不会再次执行模块代码。因此我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

1.# mysingle.py
2.class MySingle:
3.def foo(self):
4.pass
5.
6. sinleton = MySingle() 
7. 
8.将上面的代码保存在文件 mysingle.py 中,然后这样使用:
9.from mysingle import sinleton
10.singleton.foo()

(2)使用 new :

为了使类只能出现一个实例,我们可以使用 new 来控制实例的创建过程,

class Singleton(object):
	def new (cls):
	# 关键在于这,每一次实例化的时候,我们都只会返回这同一个 instance 对象
	if not hasattr(cls, 'instance'):
		cls.instance = super(Singleton, cls). new (cls)
	return cls.instance
obj1 = Singleton()
obj2 = Singleton() 

obj1.attr1 = 'value1'
print obj1 is obj2

输出结果:
value1 value1

(3)使用装饰器:

装饰器可以动态的修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例

 def singleton(cls):
 	instances = {}
	def getinstance(*args,**kwargs):
		 if cls not in instances:
			instances[cls] = cls(*args,**kwargs) 
		return instances[cls]
	return getinstance
@singleton
class MyClass:
	a = 1 
	
c1 = MyClass()
c2 = MyClass()
print(c1 == c2) # True 

在上面,我们定义了一个装饰器 singleton,它返回了一个内部函数 getinstance,
该函数会判断某个类是否在字典 instances 中,如果不存在,则会将 cls 作为 key,cls(*args, **kw) 作为 value 存到instances 中 ,否则,直接返回 instances[cls]

(4)使用 metaclass(元类):

元类可以控制类的创建过程,它主要做三件事:

  • 拦截类的创建
  • 修改类的定义
  • 返回修改后的类
class Singleton2(type):
 	def init (self, *args, **kwargs):
		self. instance = None
		super(Singleton2,self). init (*args, **kwargs)
		
	def call (self, *args, **kwargs):
		if self. instance is None:
			self. instance = super(Singleton2,self). call (*args, **kwargs)
		return self. instance

class Foo(object):
    __metaclass = Singleton2 #在代码执行到这里的时候,元类中的 new 方法和 init 方法其实已经被执行了,而不是在 Foo 实例化的时候执行。且仅会执行一次。

foo1 = Foo()
foo2 = Foo()
print (Foo. dict ) #_Singleton instance': < main .Foo object at 0x100c52f10> 存在一个私有属性来保存属性, 而不会污染 Foo 类(其实还是会污染,只是无法直接通过 instance 属性访问)
print (foo1 is foo2) # True

单例模式优缺点

优点:

  • 实例控制:单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

  • 灵活性:因为类控制了实例化过程,所以类可以灵活更改实例化过程。

缺点:

  • 开销:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

  • 可能的开发混淆:使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用 new 关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

  • 对象生成期:不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于 .NET Framework 的语言),只有单例类能够导致单例类中出现悬浮引用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值