你想通过改变实例创建方式来实现单例、缓存或其他类似的特性。
如果你想自定义这个步骤,你可以定义一个元类并自己实现 call() 方法。

1. 假设你不想任何人创建这个类的实例

  1. class NoInstances(type):
  2. def __call__(self, *args, **kwargs):
  3. raise TypeError("Can't instantuate directly")
  4. class Spam(metaclass=NoInstances):
  5. @staticmethod
  6. def grok(x):
  7. print('Spam.grok')
  8. Spam.grok(42)
  9. # Spam.grok
  10. s = Spam()
  11. # TypeError: Can't instantuate directly

2. 假如你想实现单例模式 [链接]

  1. class Singleton(type):
  2. def __init__(self, *args, **kwargs):
  3. self.__instance = None
  4. super().__init__(*args, **kwargs)
  5. def __call__(self, *args, **kwargs):
  6. if self.__instance is None:
  7. self.__instance = super().__call__(*args, **kwargs)
  8. return self.__instance
  9. else:
  10. return self.__instance
  11. class Spam(metaclass=Singleton):
  12. def __init__(self):
  13. print('Creating Spam')
  14. a = Spam()
  15. b = Spam()
  16. print(a is b)
  17. # True
  18. c = Spam()
  19. print(a is c)
  20. # True

3. 元类实现缓存实例

  1. import weakref
  2. class Cached(type):
  3. def __init__(self, *args, **kwargs):
  4. super().__init__(*args, **kwargs)
  5. self.__cache = weakref.WeakValueDictionary()
  6. def __call__(self, *args):
  7. if args in self.__cache:
  8. return self.__cache[args]
  9. else:
  10. obj = super().__call__(*args)
  11. self.__cache[args] = obj
  12. return obj
  13. class Spam(metaclass=Cached):
  14. def __init__(self, name):
  15. print('Creating Spam({!r})'.format(name))
  16. self.name = name
  17. a = Spam('Guido')
  18. # Creating Spam('Guido')
  19. b = Spam('Diana')
  20. # Creating Spam('Diana')
  21. c = Spam('Guido')
  22. # Cached
  23. print(a is b)
  24. # False
  25. print(a is c)
  26. # True