python单例模式代码-Python单例模式

Singleton(单例) —— 对象创建型模式

在GoF的《设计模式:可复用面向对象软件的基础》如下定义:

意图

保证一个类仅有一个实例,并且提供一个访问它的全局访问点。

适用性

在下面的情况下可以使用Singleton模式

当类只能有一个实例切客户可以从一个众所周知的访问点访问它时。

当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

参与者

Singleton —— 一定一个Instance操作,允许客户访问它的唯一实例。Instance是一个类操作(即Smalltalk中的一个类方法和C++中的一个静态成员函数)。

效果

对唯一实例的受控访问

缩小命名空间 Singleton模式是对全局变量的一种改进。它避免了那些存储唯一实例的全局变量污染命名空间

允许对操作和表示的精化 Singleton类可以有子类。而且用这个扩展类的实例来配置一个应用是很容易的。你可以用你所需要的类的实例在运行时刻配置应用。

允许可变数目的实例 这个模式使得你易于改变你的想法,并允许Singleton类的多个实例。此外,可以用相同的方法来控制应用所使用的实例的数目。只有允许访问Singleton实例的操作需要改变。

比类操作更灵活

php实现

在一些语言(如C++,Java,php)实现单例模式基本上大同小异,私有构造方法使得无法在外部实例化单例对象,然后提供一个静态方法获得单例。以php为例:

<?php

class Singleton

{

// 私有静态属性,用于保存实例

private static $instance = null;

//私有构造方法,不允许在外部使用

private function __construct()

{

// ...

}

//提供一个访问它的静态方法获取实例

public static function getInstance()

{

if (null === self::$instance) {

self::$instance = new self();

}

return self::$instance;

}

//不允许克隆对象

private function __clone() {}

//不允许serialize

private function __sleep() {}

//不允许unserialize

private function __wakeup() {}

}

Python实现

然而python并没有真正的私有化支持。

__new__和 __init__

object.__new__(cls[, ...]):创建一个新的类实例cls时被调用。__new__()是一个静态方法。它将请求实例的类作为其第一个参数。其余的参数是传递给对象构造方法表达式(对类的调用)。__new__()的返回值应该是新的对象实例(通常是cls的一个实例)。

object.__init__(self[, ...]):在实例被创建(由__new__())之后调用,但在它返回给调用者之前。参数是传递给类构造函数表达式的参数。如果基类有__init__()方法,派生类的__init__()方法(如果有的话),必须明确地调用它来确保实例的基类部分的正确初始化。例如:BaseClass.__init__(self, [args...])。

因为__new__()和__init__()共同创建对象。(__new__()用于创建,__init__()用于定制),__init__()不能返回非空值。这样做会导致在运行时引发TypeError。

使用__new__返回同一对象

class Singleton(object):

__instance = None

def __new__(cls, *args, **kwargs):

if cls.__instance is None:

cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)

return Singleton.__instance

测试:

a = Singleton()

b = Singleton()

print id(a)

#4337124816

print id(b)

#4337124816

print a is b

#True

这看起来没什么问题。然而如上面所说__new__()和__init__()共同创建对象。虽然重写了__new__()实现单例,但是__init__()同样会被调用:

class Singleton(object):

__instance = None

def __init__(self):

print 'dosomething'

def __new__(cls, *args, **kwargs):

if cls.__instance is None:

cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)

return Singleton.__instance

结果:

a = Singleton()

#dosomething

b = Singleton()

#dosomething

当然,可以稍作修改,不定义自动调用的__init__()方法,实例化后手动调用自己写的init()方法即可:

class Singleton(object):

__instance = None

def init(self):

print 'dosomething'

def __new__(cls, *args, **kwargs):

if cls.__instance is None:

cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)

cls.__instance.init(*args, **kwargs)

return Singleton.__instance

使用装饰器

使用Python的装饰器可以轻松实现单例模式,而且非常自由,复用性高。

这个也是PEP-0318上的示例:

def singleton(cls):

#定义一个字典局部变量

instances = {}

#闭包函数,可以使用这个局部变量instances

def getinstance():

if cls not in instances:

instances[cls] = cls()

return instances[cls]

#返回闭包

return getinstance

@singleton #相当于singleton(MyClass)

class MyClass:

def __init__(self):

print 'dosomething'

测试:

a = MyClass()

#dosomething 只输出一次

b = MyClass()

print id(a)

#4337108536

print id(b)

#4337108536

print a is b

#True

像"其他语言”一样的单例模式

就是如本文开头所说,像php,java之类的语言的单例模式。不能直接实例化对象,通过公开的静态方法获取对象唯一实例。

class Singleton:

def __init__(self, decorated):

self._decorated = decorated

def Instance(self, *args, **kwargs):

"""

返回单例实例。在它的第一次调用时,它创建一个装饰器类的新实例,并调用'__init__()'方法。

在所有后续调用中,返回已创建的实例。

"""

try:

return self._instance

except AttributeError:

self._instance = self._decorated(*args, **kwargs)

return self._instance

# __call__()方法会在调用装饰器类时触发

# 例如,如果有一个Bar类,并没有使用这个装饰器类。

# 就会在调用 Singleton(Bar)() 时触发

# 如果使用了这个装饰器,如Foo。相当于不能直接调用 Foo() 实例化对象。

def __call__(self):

raise TypeError('Singletons must be accessed through `Instance()`.')

def __instancecheck__(self, inst):

return isinstance(inst, self._decorated)

@Singleton #相当于Singleton(Foo)

class Foo:

def __init__(self):

print 'Foo created'

调用代码:

f = Foo()

# 错误。TypeError: Singletons must be accessed through `Instance()`.

f = Foo.Instance()

g = Foo.Instance()

print f is g

# True

metaclass

以后补充

class Singleton(type):

def __init__(cls, name, bases, dict):

super(Singleton, cls).__init__(name, bases, dict)

cls.instance = None

def __call__(cls,*args,**kw):

if cls.instance is None:

cls.instance = super(Singleton, cls).__call__(*args, **kw)

return cls.instance

class MyClass(object):

__metaclass__ = Singleton

Borg design pattern

这个并不算真正意义上的单例模式,只是让所有实例共享属性。它直接把__dict__指向同一个字典。

参考文章:http://code.activestate.com/recipes/66531/

class Borg:

__shared_state = {}

def __init__(self):

self.__dict__ = self.__shared_state

# and whatever else you want in your class -- that's all!

测试

a = MyClass()

b = MyClass()

print id(a)

#4337108464

print id(b)

#4337108536

print a is b

#False

a.name = 'Vergil' #设置a的属性

print b.name #打印b的属性

#Vergil

print id(a.__dict__)

#4337156456

print id(b.__dict__)

#4337156456

print a.__dict__ is b.__dict__

#True

参考文献

http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons/31887#31887

https://docs.python.org/2/reference/datamodel.html

http://code.activestate.com/recipes/66531/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值