Metaclass 控制類別建立過程。透過覆寫 __call__ 攔截實例化,可在類別層級實現 Singleton:首次建立實例後快取,後續呼叫回傳同一物件。
class Singleton(type):
def __call__(cls, *args, **kwargs):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__call__(*args, **kwargs)
return cls.instance
def __new__(cls, name, bases, dct):
print("Singleton __new__")
return type.__new__(cls, name, bases, dct)
def __init__(cls, name, bases, dct):
print("Singleton __init__")
super(Singleton, cls).__init__(name, bases, dct)
class Cache(object):
__metaclass__ = Singleton # Python 2
# Python 3: class Cache(metaclass=Singleton):
def __new__(cls, *args, **kwargs):
print("Cache __new__")
return object.__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
print("Cache __init__")
def __call__(self, *args, **kwargs):
print("Cache __call__")
print(Cache())
print(Cache())
Singleton __new__
Singleton __init__
Singleton __call__
Cache __new__
Cache __init__
<__main__.Cache object at 0x...>
Singleton __call__
<__main__.Cache object at 0x...> # 同一物件
Singleton.__call__ 攔截 Cache(),檢查 cls.instance。__new__/__init__ 僅在首次建立時執行。class Cache(metaclass=Singleton):。instance。instance = Cache() 直接匯入。@singleton 包裝類別。__new__ 覆寫 (不需 metaclass):
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
Metaclass 是 Python 進階元編程利器,Singleton 是其經典教學範例。