• 注册
当前位置:1313e > python >正文

Python实现单例模式

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

定义

An implementation of the singleton pattern must:

  1. ensure that only one instance of the singleton class ever exists; and
  2. provide global access to that instance.

单例模式就是保证类在整个使用过程中有且只有一个实例.

Python原理

要想保证类的使用过程中有且只有一个实例, 就需要对Python中类的实例化, 以及实例化后的使用过程有所了解. 这个过程主要涉及到3个方法:

  1. __new__
  2. __init__
  3. __call__

这3个方法的调用过程是: 首先调用__new__, 来生成新的实例; 其次, 调用__init__对新实例进行相关设置; 最后, 如果类中实现了__call__方法的话, 那么类的实例也是一个可调用对象, 调用实例时instance()其实就是调用实例所属的类类的__call__方法.

清楚了3个方法的调用时机, 再结合单例模式的定义就不难实现Python版本的单例模式了.

Python实现

Python中实现单例模式主要有一下几种方式:

  1. __call__
  2. __new__

__call__

在python中一切都是对象, 类其实也是一个对象, 一个类是其元类(MetaClass)的实例(定义类的时候其实就会调用元类的__init__方法).

这样理解过来, 类的实例初始化实际上就是通过调用了类的元类的__call__方法实现的.

# coding: utf-8
"""
代码摘在mininet源代码
"""class Singleton( type ):"""Singleton pattern from WikipediaSee http://en.wikipedia.org/wiki/Singleton_PatternIntended to be used as a __metaclass_ param, as shown for the classbelow."""def __new__( cls, *args, **kw ):return super( Singleton, cls ).__new__( cls, *args, **kw )def __init__( cls, name, bases, dict_ ):super( Singleton, cls ).__init__( name, bases, dict_ )cls.instance = Nonedef __call__( cls, *args, **kw ):if cls.instance is None:cls.instance = super( Singleton, cls ).__call__( *args, **kw )return cls.instanceclass MininetLogger( Logger, object ):"""Mininet-specific loggerEnable each mininet .py file to with one import:from mininet.log import [lg, info, error]...get a default logger that doesn't require one newline per loggingcall.Inherit from object to ensure that we have at least one new-style baseclass, and can then use the __metaclass__ directive, to prevent thiserror:TypeError: Error when calling the metaclass basesa new-style class can't have only classic basesIf Python2.5/logging/__init__.py defined Filterer as a new-style class,via Filterer( object ): rather than Filterer, we wouldn't need this.Use singleton pattern to ensure only one logger is ever created."""__metaclass__ = Singletondef __init__( self ):Logger.__init__( self, "mininet" )# create console handlerch = StreamHandlerNoNewline()# create formatterformatter = logging.Formatter( LOGMSGFORMAT )# add formatter to chch.setFormatter( formatter )# add ch to lgself.addHandler( ch )self.setLogLevel()def setLogLevel( self, levelname=None ):"""Setup loglevel.Convenience function to support lowercase names.levelName: level name from LEVELS"""level = LOGLEVELDEFAULTif levelname is not None:if levelname not in LEVELS:raise Exception( 'unknown levelname seen in setLogLevel' )else:level = LEVELS.get( levelname, level )self.setLevel( level )self.handlers[ 0 ].setLevel( level )# pylint: disable=method-hidden# "An attribute inherited from mininet.log hide this method" (sic)# Not sure why this is occurring - this function definitely gets called.# See /usr/lib/python2.5/logging/__init__.py; modified from warning()def output( self, msg, *args, **kwargs ):"""Log 'msg % args' with severity 'OUTPUT'.To pass exception information, use the keyword argument exc_infowith a true value, e.g.logger.warning("Houston, we have a %s", "cli output", exc_info=1)"""if self.manager.disable >= OUTPUT:returnif self.isEnabledFor( OUTPUT ):self._log( OUTPUT, msg, args, kwargs )# pylint: enable=method-hidden

每次实例化MininetLogger时, 其实调用了Singleton的__call__方法, 这个可以在Singleton和MininetLogger类中相关方法添加打印日志进行验证.

当然Singleton还有其他的定义方式:

# https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python
class Singleton(type):_instances = {}def __call__(cls, *args, **kwargs):if cls not in cls._instances:cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)return cls._instances[cls]

但是这种方式在多个类(A, B)同时指向Singleton为__metaclass__的话, 当实例化A后, 可以通过B._instances看到到A的instance.

__new__

每次实例化一个类的新实例的时候其实会调用类的__new__方法, 这样就可以通过在类的__new__方法中进行唯一实例的控制.

# https://stackoverflow.com/questions/6760685/creating-a-singleton-in-pythonclass Singleton(object):_instance = Nonedef __new__(cls, *args, **kwargs):if not isinstance(cls._instance, cls):cls._instance = object.__new__(cls, *args, **kwargs)return cls._instanceclass A(Singleton):passid(A()) == id(A())
# True

总结

单例模式就是保证在整个程序使用过程中无论实例化(class())多少次, 在内存中只保存一个实例. 在Python中通过利用__new____call__两个魔法函数就可以通过在类或者类的元类中定义这两个方法实现单例模式.

转载于:https://my.oschina.net/alazyer/blog/908709

本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 162202241@qq.com 举报,一经查实,本站将立刻删除。

最新评论

欢迎您发表评论:

请登录之后再进行评论

登录