Python中实现单例模式的最佳方法

Python中实现单例模式的最佳方法

技术背景

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。在Python中,有多种方式可以实现单例模式,每种方式都有其优缺点和适用场景。

实现步骤

1. 使用元类

元类是类的类,通过元类可以控制类的创建过程。以下是一个使用元类实现单例模式的示例:

1
2
3
4
5
6
7
8
9
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]

class Logger(metaclass=Singleton):
pass

在Python 3中,可以这样使用:

1
2
class Logger(metaclass=Singleton):
pass

如果希望每次调用类时都执行__init__方法,可以在Singleton.__call__if语句中添加:

1
2
else:
cls._instances[cls].__init__(*args, **kwargs)

2. Python 2和3兼容版本

为了使代码在Python 2和3中都能工作,可以使用以下方案:

1
2
3
4
5
6
7
8
9
10
11
12
class _Singleton(type):
""" A metaclass that creates a Singleton base class when called. """
_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]

class Singleton(_Singleton('SingletonMeta', (object,), {})): pass

class Logger(Singleton):
pass

3. 使用装饰器

装饰器也可以用来实现单例模式,以下是一个简单的装饰器实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def singleton(class_):
class class_w(class_):
_instance = None
def __new__(class2, *args, **kwargs):
if class_w._instance is None:
class_w._instance = super(class_w, class2).__new__(class2, *args, **kwargs)
class_w._instance._sealed = False
return class_w._instance
def __init__(self, *args, **kwargs):
if self._sealed:
return
super(class_w, self).__init__(*args, **kwargs)
self._sealed = True
class_w.__name__ = class_.__name__
return class_w

@singleton
class MyClass(object):
def __init__(self, text):
print(text)
@classmethod
def name(class_):
print(class_.__name__)

4. 使用类变量

通过重写__new__方法来返回类的同一个实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class SingletonClass:
_instance = None

def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls)
cls._instance._initialized = False
return cls._instance

def __init__(self, *args, **kwargs):
if self._initialized:
return

self.attr1 = args[0]
self._initialized = True

5. 使用模块

在Python中,模块只会被导入一次,因此可以利用模块来实现单例模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# log.py
import datetime
file_name=None

def set_file_name(new_file_name: str):
global file_name
file_name=new_file_name

def write(message: str):
global file_name
if file_name:
with open(file_name, 'a+') as f:
f.write("{} {}\n".format(datetime.datetime.now(), message))
else:
print("LOG: {}", message)

使用方式:

1
2
3
import log
log.set_file_name("debug.log")
log.write("System starting")

核心代码

以下是几种常见实现方式的核心代码:

元类实现

1
2
3
4
5
6
7
8
9
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]

class MyClass(metaclass=Singleton):
pass

装饰器实现

1
2
3
4
5
6
7
8
9
10
11
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance

@singleton
class MyClass:
pass

类变量实现

1
2
3
4
5
6
7
class SingletonClass:
_instance = None

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

最佳实践

  • 使用元类:当需要对类的创建过程进行更多控制时,元类是一个不错的选择。它可以确保子类也遵循单例模式,并且可以在创建实例时进行一些额外的操作。
  • 使用装饰器:装饰器可以使代码更加简洁,并且可以方便地应用于现有的类。但需要注意的是,装饰器可能会影响类的继承和方法调用。
  • 使用模块:如果单例模式只是简单地提供一些全局变量和函数,使用模块是最简单的方式。

常见问题

  • 序列化问题:使用元类实现单例模式时,序列化可能会导致创建新的实例。可以使用基类继承和__new__方法来解决这个问题。
  • 线程安全问题:在多线程环境中,需要确保单例模式的实现是线程安全的。可以使用锁机制来保证在同一时间只有一个线程可以创建实例。
  • 继承问题:使用装饰器实现单例模式时,可能会影响类的继承。在使用时需要注意这一点。

Python中实现单例模式的最佳方法
https://119291.xyz/posts/python-singleton-pattern-implementation/
作者
ww
发布于
2025年5月26日
许可协议