在Python中将模块作为单例使用-可以吗?

时间:2018-10-22 12:10:32

标签: python class module singleton

我有一个非常复杂的单例对象。我已经决定对其进行修改,因此它将成为一个单独的模块,其中包含存储数据的模块范围的全局变量。

这种方法是否存在一些陷阱?我只是觉得,这有点怪异,可能有些问题我现在看不到。 也许有人这样做或有一些意见:)在此先感谢您的帮助。 问候。

//最小,完整和可验证的示例:

"""

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

1 个答案:

答案 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()

但这只是当我对类有特别的担忧时(实现重用,适当的可测试性,需要类的其他特殊功能等)。