How to make a class which disallows duplicate instances (returning an existing instance where possible)?
我有数据,每个条目都需要是一个类的实例。我希望在我的数据中会遇到许多重复的条目。我基本上想以一组所有唯一的条目结束(即丢弃任何重复项)。然而,实例化整个批并在事实发生后将它们放入一个集合不是最佳的,因为…
我认识到这基本上是同一个问题,但…
公认的答案实际上并不能解决问题。如果你让
另一个答案要求在需要新实例时调用类方法而不是调用类本身(例如:
是否可以重写
假设您有一种识别重复实例的方法和此类实例的映射,那么您有几个可行的选项:
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class QuasiSingleton: @classmethod def make_key(cls, *args, **kwargs): # Creates a hashable instance key from initialization parameters @classmethod def get_instance(cls, *args, **kwargs): key = cls.make_key(*args, **kwargs) if not hasattr(cls, 'instances'): cls.instances = {} if key in cls.instances: return cls.instances[key] # Only call __init__ as a last resort inst = cls(*args, **kwargs) cls.instances[key] = inst return inst |
我建议使用这个基类,特别是如果您的类在任何方面都是可变的。如果不明确说明一个实例可能是相同的,则不希望在另一个实例中显示对该实例的修改。执行EDOCX1[4]意味着每次都会得到不同的实例,或者至少您的实例是不可变的,您不在乎。
在元类中重新定义
1 2 3 4 5 6 7 8 9 10 11 12 13 | class QuasiSingletonMeta(type): def make_key(cls, *args, **kwargs): ... def __call__(cls, *args, **kwargs): key = cls.make_key(*args, **kwargs) if not hasattr(cls, 'instances'): cls.instances = {} if key in cls.instances: return cls.instances[key] inst = super().__call__(*args, **kwargs) cls.instances[key] = inst return inst |
这里,
在这两种情况下,基本缓存代码是相同的。主要区别在于如何从用户的角度获取新实例。使用像
注意,在上述两种情况下,调用
第三,混合动力选择是可能的。使用此选项,您将创建一个新实例,但从现有实例复制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class QuasiSingleton: @classmethod def make_key(cls, *args, **kwargs): ... def __new__(cls, *args, **kwargs): if 'cache' not in cls.__dict__: cls.cache = {} return super().__new__(cls, *args, **kwargs) def __init__(self, *args, **kwargs): key = self.make_key(*args, **kwargs) if key in self.cache: # Or more accurately type(self).instances data = self.cache[key] else: data = # Do lengthy computation # Initialize self with data object |
有了这个选项,如果需要的话,记得打电话给