繁体   English   中英

如何在 Python 中使用任意数量的关键字参数制作单例对象?

[英]How to make a singleton object with an arbitrary number of keyword arguments in Python?

我正在使用任意数量的关键字参数制作单例。 在调试类时,执行后显示的异常与调试跟踪的发展方式不匹配。

我使用的实现与我在这个网站和这个问题中发现的非常相似。

我尝试使用/* ,因为在官方文档中提到了一些特殊情况,但是没有用。

class A:
    class B:
        def __init__(self, *, arg1, arg2, arg3, arg4='default'):
            self.arg1 = arg1
            self.arg2 = arg2
            self.arg3 = arg3
            self.arg4 = arg4

    _singleton_instance = None

    def __init__(self, **args):
        if not A._singleton_instance:
            _singleton_instance = A.B(**args)

    def __getattribute__(self, name):
        getattr(self._instance, name)


A(arg1=1, arg2=2, arg3=3)
A.arg1

执行后的异常说:

AttributeError: type object 'A' has no attribute 'arg1'

仅在调试时出现的异常说:

RecursionError('maximum recursion depth exceeded',)

在 Python 3 中,您可以使用类似这样的元类来缓存具有各种不同参数集的A对象。

但是,如果传入的任何参数不可散列,这将失败。

import inspect


class Singleton(type):
    def __call__(cls, *args, **kwargs):
        # Compute a cache key based on the arguments passed in and applying
        # any defaults from the original __init__ signature
        ar = inspect.signature(cls.__init__).bind_partial(*args, **kwargs)
        ar.apply_defaults()
        key = frozenset(ar.arguments.items())

        # Initialize the cache if it doesn't exist yet
        if not hasattr(cls, "_singleton_cache"):
            cls._singleton_cache = {}

        # If the key is in the cache, return it
        cache = cls._singleton_cache
        if key in cache:
            return cache[key]

        # Otherwise initialize a new object, save it and return it
        cache[key] = obj = super().__call__(*args, **kwargs)
        return obj


class A(metaclass=Singleton):
    def __init__(self, *, arg1, arg2, arg3, arg4="default"):
        self.arg1 = arg1
        self.arg2 = arg2
        self.arg3 = arg3
        self.arg4 = arg4


a = A(arg1=1, arg2=2, arg3=3)
b = A(arg1=1, arg2=2, arg3=3)
print(a is b)

编辑:如果你真的,真的想要一个忽略任何新参数集的单例元类,那么你去......

class VerySingleton(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_singleton_cache"):
            # Initialize the new object
            cls._singleton_cache = super().__call__(*args, **kwargs)
        return cls._singleton_cache


class A(metaclass=VerySingleton):
    def __init__(self, *, arg1, arg2, arg3, arg4="default"):
        self.arg1 = arg1
        self.arg2 = arg2
        self.arg3 = arg3
        self.arg4 = arg4


a = A(arg1=1, arg2=2, arg3=3)
b = A(arg1=1, arg2=2, arg3=0)
print(a is b)
print(a.arg3)
print(b.arg3)

这打印出来

True
3
3

– 无论b是否使用arg3=0构造,它都会被丢弃并使用旧实例,如果你问我,这完全违反直觉。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM