Python中实现单例模式时,为什么仿照经典代码却出现了非单例状态,代码哪里出错了?
Python中实现单例模式时,为什么仿照经典代码却出现了非单例状态,代码哪里出错了?
python 中直接模块级常量就是单例
你遇到的问题很常见,通常是因为对Python的模块导入机制和类变量作用域理解不够。经典的单例模式实现(比如用__new__方法)在大多数情况下是有效的,但如果在多线程环境或者模块导入方式特殊时,可能会被意外打破。
最常见的一个错误是:在类定义内部直接实例化,并且这个实例化代码在模块导入时被执行了多次。比如下面这个有问题的写法:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
# 错误:在类定义后立即创建实例
singleton = Singleton()
如果这个模块被多个地方以不同方式导入(比如相对导入和绝对导入混用),singleton = Singleton()这行代码可能会执行多次,导致实际上创建了多个“单例”实例。
正确的做法是延迟实例化,并且确保实例化只发生一次。更健壮的实现:
class Singleton:
_instance = None
_initialized = False
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not self._initialized:
# 你的初始化代码
self._initialized = True
# 使用时再实例化,不要提前创建
def get_singleton():
return Singleton()
如果你用的是装饰器方式,也要注意装饰器是否被多次应用。另外,检查一下你的导入语句,确保没有循环导入或者重复导入的情况。
建议:用__new__加_initialized标志来确保真正的单例。
我的第一处代码是仿照经典实现, 而且自己也看不少书, 都是推荐这种写法
我的疑惑在于: 是不是我写错了 ?
单例模式 建议用 new,不是用 init
应该用__new__只创建一个实例
你这是那里看到的推荐写法,“看了不少书”?你可以列出书名。另外楼上都是正解
你这种写法只是共用一个类变量,但是每次都实例化 BackgroundScheduler
正解。
还有,看了你给的链接 https://github.com/faif/python-patterns/blob/master/creational/borg.py
人家写的没错,通过继承共用类变量来实现单例
是不是我还要继承下( 我原以为那个继承, 就是做做样子的, 直接使用基类不就完了 :P )
但是, 如果我使用 str 之类的, 就和他的完全保持一致了
使用 new , 见过, 但是没有深入了解其原理过
清一色的 Borg 推荐: https://www.google.com/search?q=python+singleton&oq=python+singleton+&aqs=chrome…69i57.6145j0j7&sourceid=chrome&ie=UTF-8
但是都加了一个继承, 看起来那个继承, 不是我认为「多余的」
:P
反正各种解决方法就是了, 大家也木有一个统一的意见, 貌似也木有最佳实践了
python 中最佳实践就是模块级常量
模块,简单安全
可以试下这个单例装饰器,定义类的时候加在前面就行
#!/usr/bin/env python
# -- coding: utf-8 --
class SingletonDecorator:
def init(self, klass):
self.klass = klass
self.instance = None
def call(self, *args, **kwds):
if self.instance is None:
self.instance = self.klass(*args, **kwds)
return self.instance


