簡體   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