Skip to content

Utils

Utility functions for singleton patterns, static variables, and hashing.

Utility functions for singleton patterns, static variables, and hashing.

SingletonMeta

Bases: type

Metaclass for singleton/multiton patterns with per-class locking.

Each class using this metaclass gets its own lock and instance store, so ClassA and ClassB do not contend with each other.

Attributes:

Name Type Description
_instance_lock

Per-class threading lock.

_instances

Per-class instance dictionary keyed by arguments.

Source code in shutils/utils.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
class SingletonMeta(type):
    """Metaclass for singleton/multiton patterns with per-class locking.

    Each class using this metaclass gets its own lock and instance store,
    so ClassA and ClassB do not contend with each other.

    Attributes:
        _instance_lock: Per-class threading lock.
        _instances: Per-class instance dictionary keyed by arguments.
    """

    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)
        cls._instance_lock = threading.Lock()
        cls._instances = {}

    def __call__(cls, *args, **kwargs):
        """Create or return the cached instance using double-checked locking."""
        ignore_args = getattr(cls, "_ignore_args", True)

        if ignore_args:
            key = "singleton_root"
        else:
            frozen_kwargs = frozenset(sorted(kwargs.items()))
            key = (args, frozen_kwargs)

        if key not in cls._instances:
            with cls._instance_lock:
                if key not in cls._instances:
                    instance = super().__call__(*args, **kwargs)
                    cls._instances[key] = instance

        return cls._instances[key]

__call__(*args, **kwargs)

Create or return the cached instance using double-checked locking.

Source code in shutils/utils.py
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
def __call__(cls, *args, **kwargs):
    """Create or return the cached instance using double-checked locking."""
    ignore_args = getattr(cls, "_ignore_args", True)

    if ignore_args:
        key = "singleton_root"
    else:
        frozen_kwargs = frozenset(sorted(kwargs.items()))
        key = (args, frozen_kwargs)

    if key not in cls._instances:
        with cls._instance_lock:
            if key not in cls._instances:
                instance = super().__call__(*args, **kwargs)
                cls._instances[key] = instance

    return cls._instances[key]

singleton(cls=None, *, ignore_args=True)

Decorator that turns a class into a singleton.

Supports both @singleton (no parentheses) and @singleton(ignore_args=False) (with parentheses).

Parameters:

Name Type Description Default
cls

The class to decorate. Automatically provided when used without parentheses.

None
ignore_args

If True, all calls return the same instance regardless of arguments. If False, instances are keyed by arguments.

True

Returns:

Type Description

The decorated class or a decorator function.

Source code in shutils/utils.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def singleton(cls=None, *, ignore_args=True):
    """Decorator that turns a class into a singleton.

    Supports both ``@singleton`` (no parentheses) and
    ``@singleton(ignore_args=False)`` (with parentheses).

    Args:
        cls: The class to decorate. Automatically provided when used without parentheses.
        ignore_args: If True, all calls return the same instance regardless of arguments.
            If False, instances are keyed by arguments.

    Returns:
        The decorated class or a decorator function.
    """

    def _singleton_wrapper(target_cls):
        _instances = {}
        _instance_lock = threading.Lock()

        @wraps(target_cls)
        def wrapper(*args, **kwargs):
            if ignore_args:
                key = target_cls
            else:
                frozen_kwargs = frozenset(sorted(kwargs.items()))
                key = (args, frozen_kwargs)

            if key not in _instances:
                with _instance_lock:
                    if key not in _instances:
                        _instances[key] = target_cls(*args, **kwargs)

            return _instances[key]

        return wrapper

    if cls is None:
        return _singleton_wrapper
    else:
        return _singleton_wrapper(cls)

static_vars(**kwargs)

定义函数内静态变量的修饰器

Source code in shutils/utils.py
 99
100
101
102
103
104
105
def static_vars(**kwargs):
    """定义函数内静态变量的修饰器"""
    def decorate(func):
        for k in kwargs:
            setattr(func, k, kwargs[k])
        return func
    return decorate