【问题标题】:Python : Argument based SingletonPython:基于参数的单例
【发布时间】:2016-12-26 07:32:12
【问题描述】:

我正在关注这个link 并尝试创建一个单例类。但是,考虑参数(在启动类时传递),如果参数相同,则返回相同的对象。

因此,我不想将类名/类引用存储为dict 键,而是将传递的参数作为键存储在dict 中。但是,也可能存在不可散列的参数(如dictset 本身)。

存储类参数和类对象映射的最佳方式是什么?这样我就可以返回一个与参数对应的对象。

还是谢谢。


EDIT-1: 多一点解释。假设有如下类

class A:
    __metaclass__ == Singleton
    def __init__(arg1, arg2):
        pass

现在,A(1,2) 应该总是返回相同的对象。但是,它应该不同于A(3,4)

我认为,参数在很大程度上定义了类的功能。假设班级是否要建立redis 连接。我可能想创建 2 个以 diff redis hosts 作为参数的单例对象,但底层的类/代码可能很常见。

【问题讨论】:

  • 如果有frozendict 就好了,因为有frozenset...。我的意思是至少有一个实现,但它不在标准库中。无论如何,如果你不介意依赖,试试这个:pypi.python.org/pypi/frozendict
  • 也许我错了,但在我看来,您实际上希望记忆相同的类实例,例如 int('1') is int('1'),计算结果为 True。对我来说,单例意味着该类只有一个实例,例如None obejct,它是NoneType 的唯一实例。
  • 好吧,我仍然认为这不再是单例模式,但没关系。假设你有l1 = [1, 2]l2 = [1, 2],所以l1 is l2Falsel1 == l2True。你想让A(l1, 'foo') 返回与A(l2, 'foo') 相同的实例吗?当一个不可散列的参数改变时,A 的单例实例会发生什么,例如由A(...)的调用者@
  • 是的,在l1 = [1, 2]l2 = [1, 2] 的情况下,我希望A(l1, 'foo') 返回与A(l2, 'foo') 相同的实例,因为即使对象可能不同,基础值也是相同的。如果更改了不可散列的参数,则假设它是经过深思熟虑的并且需要单独的实例。
  • 好的,我会发布答案。

标签: python dictionary arguments singleton hashable


【解决方案1】:

正如 theheadofabroom 和我在 cmets 中已经提到的那样,在依赖非散列值(例如缓存或记忆)时存在一些可能性。因此,如果您仍然想这样做,以下示例不会隐藏 __new____init__ 方法中的记忆。 (自记忆类会很危险,因为记忆标准可能会被您无法控制的代码所欺骗)。

相反,我提供了函数memoize,它返回一个类的记忆工厂函数。由于没有通用的方法来区分不可散列的参数,如果它们会产生一个与已经存在的实例等效的实例,则必须显式地提供记忆语义。这是通过将keyfunc 函数传递给memoize 来实现的。 keyfunc 采用与类的 __init__ 方法相同的参数,并返回一个可散列键,其相等关系 (__eq__) 确定记忆。

memoization 的正确使用是使用代码的责任(提供合理的keyfunc 并使用工厂),因为要memoized 的类没有被修改,仍然可以正常实例化。

def memoize(cls, keyfunc):
    memoized_instances = {}

    def factory(*args, **kwargs):
        key = keyfunc(*args, **kwargs)
        if key in memoized_instances:
            return memoized_instances[key]

        instance = cls(*args, **kwargs)
        memoized_instances[key] = instance
        return instance

    return factory


class MemoTest1(object):
    def __init__(self, value):
        self.value = value

factory1 = memoize(MemoTest1, lambda value : value)

class MemoTest2(MemoTest1):
    def __init__(self, value, foo):
        MemoTest1.__init__(self, value)
        self.foo = foo

factory2 = memoize(MemoTest2, lambda value, foo : (value, frozenset(foo)))

m11 = factory1('test')
m12 = factory1('test')
assert m11 is m12

m21 = factory2('test', [1, 2])

lst = [1, 2]
m22 = factory2('test', lst)

lst.append(3)
m23 = factory2('test', lst)

assert m21 is m22
assert m21 is not m23  

我只将MemoTest2 包含为MemoTest1 的子类,以表明使用常规类继承没有任何魔力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 2018-01-03
    • 2013-04-16
    • 2016-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多