Python Singleton设计模式跟踪应用程序统计信息

时间:2015-10-09 04:21:55

标签: python singleton

我有一个Python应用程序,可以执行任务的工作流程。这些任务中的每一个都可能位于自己的模块中。完成所有任务的列表后,应用程序将关闭。在它关闭之前,我想从每个任务中收集相关的统计数据。

我在考虑使用单例模式提供一个位置来存储所有这些数据,以便我可以在最后检索它。每个任务都将导入singleton stats-tracking类,创建一个实例(该类的常见单个实例)并使用它来存储任何数据。

在我的情况下,我想要一个包来存储每个任务的数据。我一直听说单身人士很糟糕。我想获得有关使用单例设计模式或任何其他建议的输入。

1 个答案:

答案 0 :(得分:2)

单身是否是"坏"或不似乎是品味问题。当然他们有自己的位置,单身主题的任何变化都适合你。

"博格模式" (格言不那么多,而且很少见," StatelessProxy"或者#34; Monostate")自从Alex Martelli聪明的ActiveState食谱{{3 }}。它与Singleton的不同之处在于允许类的多个不同对象,所有对象都共享公共数据。相反,Singleton模式确保只创建一个类的一个实例。

可以在此stackoverflow帖子中找到关于Borg vs Singleton问题的讨论:Singleton? We don't need no stinkin' singleton: the Borg design pattern。由于缺少_init_default_register方法,帖子顶部的实现可能令人费解,其目的是仅创建和初始化公共数据属性。供参考和比较,这里是完整的实现(在Python 3中),它们都创建了一个数据属性(一个名为data的dict):

在Python中实现Singleton的标准方法是使用元类;

class Singleton(type):
    def __init__(cls, *args, **kwargs):
        cls.__instance = None
        super().__init__(*args, **kwargs)

    def __call__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__call__(*args, **kwargs)
        return cls.__instance

您可以通过为其提供此元类来使您的统计跟踪类成为单例:

class StatsTrackerSingleton(metaclass=Singleton):
    def __init__(self):
        self.data = {}

    # ... methods to update data, summarize it, etc. ...

Borg模式实现起来更简单,因为它没有使用元类,可能更灵活:

class StatsTrackerBorg():
    __shared_data = {'data':{}}
    # RHS guarantees a common dict named `data`

    def __init__(self):
        """Make every instance use StatsTrackerBorg.__shared_data
        for its attribute dict."""
        self.__dict__ = self.__shared_data

    # ... methods to update data, summarize it, etc. ...

使用上面实现的两种模式,您可以使用公共字典data,您可以使用点运算符简单地获取和设置共享属性。例如,使用Borg类:

>>> a = StatsTrackerBorg()
>>> b = StatsTrackerBorg()
>>> a is b          # would be True for StatsTrackerSingleton
False
>>> vars(a) is vars(b)
True

>>> vars(a)
{'data': {}}
>>> a.data['running_time'] = 10000
>>> b.bar = 10
>>> vars(a)
{'data': {'running_time': 10000}, 'bar': 10}

>>> b.foo = 'y'
>>> a.foo
'y'

两种模式之间的一个值得注意的差异:一个" Borg' ed"的子类。 class与超类共享相同的公共状态,并且仍然可以添加其实例可访问的更多共享状态,而Singleton类的每个子类获得其自己的唯一实例,因此它自己的公共状态与超类的不相交。对于某些预期的应用程序,其中一种行为可能显然比另一种行为更合适。