[英]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.