专栏首页JetpropelledSnake在Python中实现单例模式

在Python中实现单例模式

有些时候你的项目中难免需要一些全局唯一的对象,这些对象大多是一些工具性的东西,在Python中实现单例模式并不是什么难事。以下总结几种方法:

使用类装饰器

使用装饰器实现单例类的时候,类本身并不知道自己是单例的,所以写代码的人可以不care这个,只要正常写自己的类的实现就可以,类的单例有装饰器保证。

def singleton(cls):
    instancec = {}
    def _wrapper(*args,**kwargs):
        if cls not in instances:
            instances[cls] = cls(*args,**kwargs)
        return instances[cls]
    return _wrapper

你会发现singleton装饰器内部使用了一个dict。当然你也可以用其他的方式,不过以下的实现是错误的:

def singleton(cls):
    _instance = None #外部作用域的引用对于嵌套的内部作用域是只读的
    def _wrapper(*args, **kwargs):
        if _instance is None: 
            #解释器会抛出"UnboundLocalError: ...referenced before assignment"
            _instance = cls(*args, **kwargs) 
                #赋值行为使解释器将"_instance"看作局部变量
        return _instance
    return _wrapper             

使用元类(__metaclass__)和可调用对象(__call__)

Python的对象系统中一些皆对象,类也不例外,可以称之为”类型对象”,比较绕,但仔细思考也不难:类本身也是一种对象,只不过这种对象很特殊,它表示某一种类型。是对象,那必然是实例化来的,那么谁实例化后是这种类型对象呢?也就是元类。

  Python中,class关键字表示定义一个类对象,此时解释器会按一定规则寻找__metaclass__,如果找到了,就调用对应的元类实现来实例化该类对象;没找到,就会调用type元类来实例化该类对象。

  __call__是Python的魔术方法,Python的面向对象是”Duck type”的,意味着对象的行为可以通过实现协议来实现,可以看作是一种特殊的接口形式。某个类实现了__call__方法意味着该类的对象是可调用的,可以想像函数调用的样子。再考虑一下foo=Foo()这种实例化的形式,是不是很像啊。结合元类的概念,可以看出,Foo类是单例的,则在调用Foo()的时候每次都返回了同样的对象。而Foo作为一个类对象是单例的,意味着它的类(即生成它的元类)是实现了__call__方法的。所以可以如下实现:

class Singleton(type):
    def __init__(cls, name, bases, attrs):
        super(Singleton, cls).__init__(name, bases, attrs)
        cls._instance = None
    def __call__(cls, *args, **kwargs):
        if cls._instance is None
            # 以下不要使用'cls._instance = cls(*args, **kwargs)', 防止死循环,
            # cls的调用行为已经被当前'__call__'协议拦截了
            # 使用super(Singleton, cls).__call__来生成cls的实例
            cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instance
 
class Foo(object): #单例类
    __metaclass__ = Singleton
 
>>>a = Foo()
>>>b = Foo()
>>>a is b
>>>True
>>>a.x = 1
>>>b.x
>>>1

使用__new__

__init__不是Python对象的构造方法,__init__只负责初始化实例对象,在调用__init__方法之前,会首先调用__new__方法生成对象,可以认为__new__方法充当了构造方法的角色。所以可以在__new__中加以控制,使得某个类只生成唯一对象。具体实现时可以实现一个父类,重载__new__方法,单例类只需要继承这个父类就好。

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance
 
class Foo(Singleton): #单例类

参考:http://python.jobbole.com/87514/ 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python设计模式之单例模式

      本系列文章是希望将软件项目中最常见的设计模式用通俗易懂的语言来讲解清楚,并通过Python来实现,每个设计模式都是围绕如下三个问题: 为什么?即为什么要使用...

    Jetpropelledsnake21
  • SQL学习笔记四(补充-1-1)之MySQL单表查询补充部分:SQL逻辑查询语句执行顺序

    在这些SQL语句的执行过程中,都会产生一个虚拟表,用来保存SQL语句的执行结果(这是重点),我现在就来跟踪这个虚拟表的变化,得到最终的查询结果的过程,来分析整个...

    Jetpropelledsnake21
  • Linux学习笔记之AIX系统上压缩与解压文件

    C:是本地到其他设备  x:是其他设备到本地  r:是追加,比如打包时,将其他文件追加进来使用该参数。

    Jetpropelledsnake21
  • Python中的单例模式

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

    py3study
  • 尝试绕过验证码

    最近出了点安全事故,有人盗号。而且手段极其简单,就是暴力破解。 为了提高安全性,UI的界面加了验证机制。这也为自动化测试提高了难度。

    赵云龙龙
  • “单例模式有四样写法,你知道么?”——孔乙己

    单例模式(Singleton Pattern)是最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    BigYoung小站
  • Lua(3) ——Cocos之_语法糖c

        在使用Lua的时候,cocos2d-x为我们提供了一个 class(classname, super) 这个函数。

    py3study
  • Python实现Singleton模式的

    使用python实现设计模式中的单例模式。单例模式是一种比较常用的设计模式,其实现和使用场景判定都是相对容易的。本文将简要介绍一下python中实现单例模式的几...

    py3study
  • Python单例模式(Singleton)的N种实现

    很多初学者喜欢用全局变量,因为这比函数的参数传来传去更容易让人理解。确实在很多场景下用全局变量很方便。不过如果代码规模增大,并且有多个文件的时候,全局变量就会变...

    Crossin先生
  • python 魔法方法连载四 __new__()

    在学习__new__(cls,[ *args]) 方法之前,我们知道,当实例化一个对象时,首先调用的是 __init__()方法初始化对象,但在我们学习了了__...

    cctester

扫码关注云+社区

领取腾讯云代金券