论Python的单例模式和装饰器

TN的人问到我怎么实现。我只大概记得是在一个类中定义一个指向为NULL的变量。然后去创建这个类的对象。如果这个对象为空,就新实例化该类的对象,否则就什么也不做。然后返回这个变量。他又问我怎么去传递引用。我一下子就不知道怎么说了(因为没写过)。这几天查了一下相关资料总算有了实际的概念。

在类中定义一个方法,这个方法去检查和实例化这个变量。但是有两点要注意。一是这个方法应该用类名去直接调用,所以要用@staicmethod声明为静态方法。第二点是要注意多线程的安全问题。所以可以用threading类的方法加锁。


#!/usr/bin/env python
#-*- coding: utf-8 -*-

"""
# Author: DMCC-DATA
# Created Time : Thu 17 Dec 2015 03:31:15 PM CST
# File Name: singleton.py
# Description:
"""

import sys
reload(sys)
sys.setdefaultencoding('utf8')

import os,traceback,logging,multiprocessing,re
import threading

class Singleton():
	instance = None
	a = 1
	mutex = threading.Lock()
	def _init__(self):
		print 'init self'
		pass
	@staticmethod
	def GetInstance():
		if(Singleton.instance==None):
			Singleton.mutex.acquire()
			if(Singleton.instance==None):
				print 'init instance'
				Singleton.instance=Singleton()
			else:
				print 'exist instance'
			Singleton.mutex.release()
		else:
			print 'exist instance'

		return Singleton.instance

def func():
	Singleton.GetInstance()
	Singleton.GetInstance()
	Singleton.GetInstance()

	pool = multiprocessing.Pool(5)
	for i in range(10):
		pool.apply_async(Singleton.GetInstance(),[])
	pool.close()
	pool.join()

if __name__ == '__main__':
	func()


最后提醒一下,其他模块导入这个类使用的时候,记得用模块名.类名.方法名调用
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


但是这个方法需要改动类本身,接下来有个更方便的方法


如果有一个方法,你想对它实现一些增强功能,但是又尽可能避免对它代码的改动,就可以把它当作切面,使用装饰器模式。

写一个包装方法,方法的参数是要装饰的方法和它的参数列表,在这个方法中写一个内嵌包装函数,把要增强的功能和原方法结合起来,这个内嵌函数调用原方法和参数并接收返回值,并返回这个值。然后包装方法返回这个内嵌函数。最后调用这个包装方法,把引用传给原方法。这一步可以使用语法糖@

  1 #!/usr/bin/env python
  2 #-*- coding: utf-8 -*-
  3
  4 """
  5 # Author: DMCC-DATA
  6 # Created Time : Thu 17 Dec 2015 05:14:42 PM CST
  7 # File Name: decorator.py
  8 # Description:
  9 """
 10
 11 import sys
 12 reload(sys)
 13 sys.setdefaultencoding('utf8')
 14
 15 import os,traceback,logging,multiprocessing,re
 16
 17 def deco(func):
 18     def dec(*args):
 19         print 111
 20         res = func(*args)
 21         print 222
 22         return res
 23     return dec
 24
 25 @deco
 26 def add(a,b):
 27     return a+b
 28
 29 def func2():
 30     r = add(3,4)
 31     print r
 32
 33 if __name__ == '__main__':
 34     func2()

实际应用类中的代码

#!/usr/bin/env python
#-*- coding: utf-8 -*-

"""
# Author: DMCC-DATA
# Created Time : Fri 18 Dec 2015 09:37:46 AM CST
# File Name: decsingleton.py
# Description:
"""

import sys
reload(sys)
sys.setdefaultencoding('utf8')

import os,traceback,logging,multiprocessing,re
import time

def singleton(cls):
	instance = {}
	def getinstance(*args):
		if cls not in instance:
			instance[cls] = cls(*args)
		return instance[cls]
	return getinstance

@singleton
# Person() = singleton(Pserson()) 
#(object) 声明继承自object,是一个新类,这里没实际作用
class Person(object):
	def __init__(self):
		self.t = self.gettime() 
		print self.t
	def gettime(self):
		t = time.time()
		return t



def func():
	p1 = Person()
	p2 = Person()
	print p1,p1.t
	print p2,p2.t
	p1.t = 1
	print p1,p1.t
	print p2,p2.t

if __name__ == '__main__':
	func()

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

除此之外,还可以利用Python的__metaclass__和__dic__分别实现。后者又可以称作重写new方法,但是只是把所有实例对象共享属性,每次产生一个新对象。算作伪单例吧。


__metaclass__元类方法代码:

#!/usr/bin/env python
#-*- coding: utf-8 -*-


"""
# Author: DMCC-DATA
# Created Time : Thu 17 Dec 2015 03:31:15 PM CST
# File Name: singleton.py
# Description:
"""

import sys
reload(sys)
sys.setdefaultencoding('utf8')

import os,traceback,logging,multiprocessing,re,time
import threading

class Singleton(type):
<span style="white-space:pre">	</span>def __init__(cls,name,bases,dict):
<span style="white-space:pre">		</span>super(Singleton,cls).__init__(name,bases,dict)
<span style="white-space:pre">		</span>cls.instance = None


<span style="white-space:pre">	</span>def __call__(cls,*args,**kw):
<span style="white-space:pre">		</span>if cls.instance is None:
<span style="white-space:pre">			</span>cls.instance = super(Singleton,cls).__call__(*args,**kw)
<span style="white-space:pre">		</span>return cls.instance

class SingletonCls(object):
<span style="white-space:pre">	</span>a = 1
<span style="white-space:pre">	</span>__metaclass__ = Singleton
<span style="white-space:pre">	</span>def __init__(self):
<span style="white-space:pre">		</span>self.t = self.gettime() 
<span style="white-space:pre">		</span>print self.t
<span style="white-space:pre">	</span>def gettime(self):
<span style="white-space:pre">		</span>t = time.time()
<span style="white-space:pre">		</span>return t

def func():
<span style="white-space:pre">	</span>a1 = SingletonCls()
<span style="white-space:pre">	</span>a2 = SingletonCls()
<span style="white-space:pre">	</span>print a1,a1.a
<span style="white-space:pre">	</span>print a2,a2.a
<span style="white-space:pre">	</span>a1.a = 2
<span style="white-space:pre">	</span>a1.x = 999
<span style="white-space:pre">	</span>print a1,a1.a,a1.x
<span style="white-space:pre">	</span>print a2,a2.a,a2.x
<span style="white-space:pre">	</span>
if __name__ == '__main__':
<span style="white-space:pre">	</span>func()


共享属性方法代码:

#!/usr/bin/env python
#-*- coding: utf-8 -*-

"""
# Author: DMCC-DATA
# Created Time : Thu 17 Dec 2015 03:31:15 PM CST
# File Name: singleton.py
# Description:
"""
import sys
reload(sys)
sys.setdefaultencoding('utf8')

import os,traceback,logging,multiprocessing,re,time
import threading


class Borg(object):
<span style="white-space:pre">	</span>_state = {}
<span style="white-space:pre">	</span>def __new__(cls,*args,**kw):
<span style="white-space:pre">		</span>ob = super(Borg,cls).__new__(cls,*args,**kw)
<span style="white-space:pre">		</span>ob.__dict__ = cls._state
<span style="white-space:pre">		</span>print 'init'
<span style="white-space:pre">		</span>return ob

class SingletonCls(Borg):
<span style="white-space:pre">	</span>a = 1
<span style="white-space:pre">	</span>def __init__(self):
<span style="white-space:pre">		</span>self.t = self.gettime() 
<span style="white-space:pre">		</span>print self.t
<span style="white-space:pre">	</span>def gettime(self):
<span style="white-space:pre">		</span>t = time.time()
<span style="white-space:pre">		</span>return t

def func():
<span style="white-space:pre">	</span>a1 = SingletonCls()
<span style="white-space:pre">	</span>a2 = SingletonCls()
<span style="white-space:pre">	</span>print a1,a1.a
<span style="white-space:pre">	</span>print a2,a2.a
<span style="white-space:pre">	</span>a1.a = 2
<span style="white-space:pre">	</span>a1.x = 999
<span style="white-space:pre">	</span>print a1,a1.a,a1.x
<span style="white-space:pre">	</span>print a2,a2.a,a2.x


if __name__ == '__main__':
<span style="white-space:pre">	</span>func()


综上,在python实现单例模式有4种方法,前三种只实例化一个对象,最后一种实例化许多个相同属性的对象。其中第一个又要改写类本身。所以真正实用的就是装饰器法和元类法了。最喜欢的当然还是装饰器啦

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值