2

Python实现单例模式的多种方法

 2 years ago
source link: https://allenwind.github.io/blog/2455/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Mr.Feng Blog

NLP、深度学习、机器学习、Python、Go

Python实现单例模式的多种方法

一些Pythonic技巧实现的单例模式

  • 目的
    单例模式可以保证一个类只有一个实例,并提供一个访问它的全局访问点。什么情况下需要一个类只能创建一个实例这种情况呢?举一些例子,操作系统只能有一个文件系统,一个窗口管理器。

  • 方法
    为了实现单列模式,我们可以让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建(通过截取创建新对象的请求),并且它可以提供一个访问该实例的方法。

  • 使用
    当类只能有一个实例而且调用端可以从一个公共入口访问。
    作为父类,用来扩展其他只能唯一实例化的类

  • 注意
    注意创建过程中的线程安全性。由于该模式需要一个静态变量来保存唯一的实例,为了线程安全需要改静态变量的线程安全。下面的实现保证线程安全采用加锁的方法。

  • 单例模式中的主动实例化和被动实例化
    主动实例化指在加载主类的时候就实例化单例类,并保存到类的静态变量中,它是线程安全的。被动实例化指在首次调用单例类静态方法或构造器时创建。问题:Python可以实现主动实例化吗?

下面采用两种语言实现,同时考虑线程不安全的情况。

采用类变量是保存唯一实例

class Singleton:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance

class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance

class Demo(Singleton):
spam = 1

考虑线程安全的情况。

import threading

class Singleton:
def __new__(cls, *args, **kwargs):
with threading.Lock():
if not hasattr(cls, '_instance'):
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance

# 这种办法线程安全,但效率不高,没有必要一开始就加锁。可以先检查是否有实例化,
# 然后再加锁检查时候有实例化。第一次检查是为了是否需要进入加锁创建状态,第二
# 次检查是确认加锁前是否已经有现车实例化该类。

class Singleton:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
with threading.Lock():
if not hasattr(cls, '_instance'):
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance

class Demo(Singleton):
spam = 1

使用元类方法

class Singleton(type):
def __init__(self, *args, **kwargs):
self.__instance = None
super().__init__(*args, **kwargs)

def __call__(self, *args, **kwargs):
if self.__instance is None:
super().__call__(*args, **kwargs)
return self._instance
return self.__instance

class Demo(metaclass=Singleton):
spam = 1

# 这种方法线程不安全,但更高级。其本质上和第一中的实现方式是一致的,
# 都采用静态变量来保存唯一实例。但采用元类的方式更使元类在创建类的
# 时候动态创建这个静态变量。如果有不同的类同时需要实现单列模式,但
# 它们又要求不能有同一父类,这种情况可以使用元类的实现。下面是线程
# 安全的方法,为了考虑性能,这一依旧采用先检测再加锁的方法。

class Singleton(type):
def __init__(self, *args, **kwargs):
self.__instance = None
super().__init__(*args, **kwargs)

def __call__(self, *args, **kwargs):
if self.__instance is None:
with threading.Lock():
if self.__instance is None:
super().__call__(*args, **kwargs)
return self.__instance

转载请包括本文地址:https://allenwind.github.io/blog/2455
更多文章请参考:https://allenwind.github.io/blog/archives/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK