python 使用装饰器实现单例模式

python的面向切面编程,类似于java的AOP(aspect Oriented programming)。简而言之,这种在运行时,编译时,类和方法加载时,动态地将代码切入到类的指定方法、指定位置的编程思想就是面向切面的编程。
我们管切入到指定类指定方法的代码片段叫做片面,而切入到哪些类、哪些方法则叫切入点。有了aop,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。python中的装饰器,就是这个面向切面编程思想的经典应用。
它的优点是:对原代码毫无入侵行。
 

装饰器

装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。

python中一切皆对象,同样函数也是一个对象。函数对象有一个__name__属性,可以查看函数的名字。
 

def demo():
    print("xxx")

print(demo.__name__)

output:
 demo

假设我们要增强函数demo的功能,比如在函数执行前自动打印日志,但又不希望改变demo()函数的定义,此时就用到了装饰器。这种在代码运行期间动态增加功能的方式,称为装饰器(decorator)。要想明白装饰器首先要明白一个概念即函数即是对象。

函数就是对象.因此,对象:

  • 可以赋值给一个变量
  • 可以在其他函数里定义
  • 函数可以返回另一个函数
  • 函数作为参数传递

比如下面例1用的是函数实现。

例1:

# 装饰器就是把其他函数作为参数的函数
def log(func):
    # # 在函数里面,装饰器在运行中定义函数: 包装.
    # 这个函数将被包装在原始函数的外面,所以可以在原始函数之前和之后执行其他代码.
    def wrapper(*args, **kw):
        print 'call %s():' % func.__name__
        func(*args, **kw)
        print 'after call %s()' % func.__name__
    # 装饰器的返回值刚才包装过的函数
    return wrapper
@log
def demo():
    print("xxx")

demo()


output:
call demo():
xxx
after call demo()

 

2、单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某个类只有一个实例存在。如某个程序的配置文件,程序可能通过一个Settings的类来读取配置文件的信息。如果在程序运行期间有很多地方需要用到配置文件的内容,也就是很多地方需要创建Settings的实例,这就导致程序中存在多个Settings的实例对象,这样会严重浪费内存资源。类似于这种情况,我们希望程序运行期间只存在一个实例对象。

 

3、装饰器来实现单例模式:

思路:装饰器里面的外层变量定义一个字典,里面存放这个类的实例.当第一次创建的时候,就将这个实例保存到这个字典中.
然后以后每次创建对象的时候,都去这个字典中判断一下,如果已经被实例化,就直接取这个实例对象.如果不存在就保存到字典中.

from functools import wraps

def Singleton(cls):
    _instance = {}
    @wraps(cls)
    def _singleton(*args, **kargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kargs)
        return _instance[cls]

    return _singleton

@Singleton
class Settings():
    """Docstring"""
    def __init__(self):
        self.a = "xxx"
        self.b = "xxx"


settings = Settings()
print(settings.a)
print(Settings.__name__)
print(Settings.__doc__)

output:
xxx
Settings
Docstring

代码中@wraps的作用:Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值