我有一个非常复杂的单例对象。我已经决定对其进行修改,因此它将成为一个单独的模块,其中包含存储数据的模块范围的全局变量。
这种方法是否存在一些陷阱?我只是觉得,这有点怪异,可能有些问题我现在看不到。 也许有人这样做或有一些意见:)在此先感谢您的帮助。 问候。
//最小,完整和可验证的示例:
"""
This is __init__.py of the module, that could be used as a singleton:
I need to set and get value of IMPORTANT_VARIABLE from different places in my code.
Folder structure:
--singleton_module
|
-__init__.py
Example of usage:
import singleton_module as my_singleton
my_singleton.set_important_variable(3)
print(my_singleton.get_important_variable())
"""
IMPORTANT_VARIABLE = 0
def set_important_variable(value):
global IMPORTANT_VARIABLE
IMPORTANT_VARIABLE = value
def get_important_variable():
return IMPORTANT_VARIABLE
答案 0 :(得分:2)
从技术上讲,Python模块是单例的,因此从这个角度来看,您的代码没有特别的问题(单例的常见问题除外)。我只是在all_lower中拼写了变量(ALL_UPPER表示伪常量),并在其前加了一个单引号(“保护”)或双引号(“真正私有”),以明确说明它不属于公共API(标准的Python命名约定)。
现在单身人士是否是一个好主意,这是另一个争论,但这不是重点...
例如,在一种潜在的情况下,我可能会丢失数据,或者该模块可能在不同的代码位置两次导入,因此,如果在函数范围之内或类似的范围内导入,则不会是单例。
每个进程只能实例化一个模块(第一次导入),然后从sys.modules
直接获得后续导入。可以在同一模块中拥有两个不同实例的唯一情况是,该模块是通过两条不同的路径导入的,只有在您的sys.path
有点破损(例如:
src/
foo/
__init.py
bar/
__init__.py
baaz/
__init__.py
mymodule.py
在sys.path
中同时包含“ src”和“ foo”,然后一次将mymodule
导入为from foo.bar.baaz import mymodule
,第二次导入from bar.baaz import mymodule
不用说这是一个简陋的案例,但是它可能发生并导致难以诊断的错误。请注意,遇到这种情况时,您确实还有很多其他问题,例如对mymodule
中的任何内容进行身份测试。
此外,我不确定使用对象而不是模块会提高安全性
不是。
我只是问,如果这不是一个坏习惯,也许有人这样做并发现了一些问题。这可能不是流行的模式
好吧,恰恰相反,您经常会发现有关将模块作为单例使用的建议,而不是仅使用具有静态方法,类方法和类属性的类(在Python中实现单例的另一种方法)。当您的示例确实具有状态时,这通常涉及用作状态空间的无状态类,但这并没有多大实际意义。
现在您将无法获得所有不错的面向对象功能,例如计算属性,继承,魔术方法等,但是我想您已经了解了。
就我而言,根据上下文,我宁愿使用一个普通的类,但仅将该类的一个实例作为模块的API公开,即:
# mymodule.py
__all__ = ["mysingleton"]
class __MySingletonLike(object):
def __init__(self):
self._variable = 42
@property
def variable(self):
return self._variable
@variable.setter
def variable(self, value):
check_value(value) # imaginary validation
self._variable = value
mysingleton = __MySingleton()
但这只是当我对类有特别的担忧时(实现重用,适当的可测试性,需要类的其他特殊功能等)。