在Python中将模块作为单例使用-可以吗? [英] Using module as a singleton in Python - is that ok?

查看:51
本文介绍了在Python中将模块作为单例使用-可以吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've got a really complex singleton object. I've decided to modify it, so it'll be a separate module with module--wide global variables that would store data.

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

Are there some pitfalls of this approach? I just feel, like that's a little bit hacky, and that there may be some problems I cannot see now. Maybe someone did this or have some opinion :) Thanks in advance for help. Regards.

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

// Minimal, Complete, and Verifiable example:

"""

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

推荐答案

从技术上讲,Python模块是单例,因此从这个角度来看,您的代码没有特别的问题(单例的常见问题除外).我只需在all_lower中拼写该变量(ALL_UPPER表示伪常量),并在其前加一个单引号(保护")或双引号(真正私有"),以明确说明它不是公共API的一部分(标准的Python命名约定).

Technically, Python modules ARE singletons, so from this point of view there's no particular issue (except the usual issues with singletons that is) with your code. I'd just spell the varibale in all_lower (ALL_UPPER denotes a pseudo-constant) and prefix it with either a single ("protected") or double ("really private") leading underscore to make clear it's not part of the public API (standard Python naming convention).

现在,单身人士是否是一个好主意,这是另一个争论,但这不是重点……

Now whether singletons are a good idea is another debate but that's not the point here...

例如,在一种潜在的情况下,我可能会丢失数据,或者该模块可能在不同的代码位置两次导入,因此,如果在函数范围之内或类似的范围内导入,则不会是单例.

e.g that in one potential situation I may lost data, or that module could be imported in different places of code two times, so it would not be a singleton if imported inside scope of function or something like that.

每个进程只能实例化一个模块(第一次导入),然后从 sys.modules 直接获取后续的导入.可能具有同一模块的两个不同实例的唯一情况是,该模块是通过两个不同的路径导入的,只有在 sys.path 有点破损的情况下(例如,这样的情况),这种情况才会发生:

A module is only instanciated once per process (the first time it's imported), then subsquent imports will directly get if from sys.modules. The only case where you could have two distinct instances of the same module is when the module is imported by two different path, which can only happens if you have a somewhat broken sys.path ie something like this:

src/
  foo/
    __init.py
    bar/
      __init__.py
      baaz/
         __init__.py
         mymodule.py

sys.path 中同时带有"src"和"foo",然后从foo.bar.baaz中以的形式导入 mymodule 一次,导入mymodule ,第二次以从bar.baaz导入mymodule

with both "src" and "foo" in sys.path, then importing mymodule once as from foo.bar.baaz import mymodule and a second time as from bar.baaz import mymodule

不用说这是一个退化的案例,但是它可能发生并导致难以诊断的错误.请注意,遇到这种情况时,确实还有很多其他问题,例如对 mymodule 中的任何内容进行身份测试.

Needless to say that it's a degenerate case, but it can happens and lead to hard to diagnose bugs. Note that when you have this case, you do have quite a few other things that breaks, like identity testing anything from mymodule.

此外,我不确定使用对象而不是模块会提高安全性

Also, I am not sure how would using object instead of module increase security

不是.

我只是问,如果这不是一个坏习惯,也许有人这样做并发现了一些问题.这可能不是一个流行的模式

And I am just asking, if that's not a bad practice, maybe someone did this and found some problems. This is probably not a popular pattern

好吧,恰恰相反,您经常会发现有关将模块用作单例的建议,而不是仅使用具有静态方法,类方法和类属性的类(在Python中实现单例的另一种方法).当您的示例确实具有状态时,这通常涉及用作状态空间的无状态类,但这并没有多大实际意义.

Well, quite on the contrary you'll often find advises on using modules as singletons instead of using classes with only staticmethods, classmethods and class attributes (another way of implementing a singleton in Python). This most often concerns stateless classes used as namespaces while your example does have a state, but this doesn't make much practical difference.

现在您将无法获得所有不错的面向对象功能,例如计算属性,继承,魔术方法等,但是我想您已经了解了.

Now what you won't get are all the nice OO features like computed attributes, inheritance, magicmethods etc, but I assume you already understood this.

就我而言,根据上下文,我宁愿使用一个普通的类,但仅将该类的一个实例作为模块的API公开,即:

As far as I'm concerned, depending on the context, I might rather use a plain class but only expose one single instance of the class as the module's API ie:

# 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()

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

but that's only when I have special concerns about the class (implementation reuse, proper testability, other special features requiring a class etc).

这篇关于在Python中将模块作为单例使用-可以吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆