[英]Python class instances unique by some property
Suppose I want to create instances of my class freely, but if I instantiate with the same argument, I want to get the same unique instance representing that argument. 假设我想自由地创建我的类的实例,但是如果我使用相同的参数进行实例化,我想获得表示该参数的相同唯一实例。 For example: 例如:
a = MyClass('Instance 1');
b = MyClass('Instance 2');
c = MyClass('Instance 1');
I would want a == c
to be True
, based on the unique identifier I passed in. 根据我传入的唯一标识符,我希望a == c
为True
。
Note: 注意:
(1) I'm not talking about manipulating the equality operator-- I want a
to really be the same instance as c
. (1)我不是在谈论操纵相等运算符 - 我想要a
真正与c
相同的实例。
(2) This is intended as library code, so uniqueness has to be enforced -- we can't just count on users doing the right thing (whatever that is). (2)这是作为库代码,因此必须强制执行 - 我们不能只指望用户做正确的事情(无论是什么)。
Is there a canonical way of achieving this? 是否有规范的方法来实现这一目标? I run into this pattern all the time, but I usually see solutions involving shadow classes, meant for only internal instantiation. 我一直遇到这种模式,但我经常看到涉及阴影类的解决方案,仅用于内部实例化。 I think I have a cleaner solution, but it does involve a get() method, and I'm wondering if I can do better. 我想我有一个更清洁的解决方案,但它确实涉及一个get()方法,我想知道我是否可以做得更好。
I'd use a metaclass. 我用的是元类。 This solution avoids calling __init__()
too many times: 此解决方案避免多次调用__init__()
:
class CachedInstance(type):
_instances = {}
def __call__(cls, *args):
index = cls, args
if index not in cls._instances:
cls._instances[index] = super(CachedInstance, cls).__call__(*args)
return cls._instances[index]
class MyClass(metaclass=CachedInstance):
def __init__(self, name):
self.name = name
a = MyClass('Instance 1');
b = MyClass('Instance 2');
c = MyClass('Instance 1');
assert a is c
assert a is not b
Reference and detailed explanation: https://stackoverflow.com/a/6798042/8747 参考和详细说明: https : //stackoverflow.com/a/6798042/8747
This can be done (assuming that args
are all hashable) 这可以做到(假设args
都可以清洗)
class MyClass:
instances = {}
def __new__(cls, *args):
if args in cls.instances:
return cls.instances[args]
self = super().__new__(cls)
cls.instances[args] = self
return self
a = MyClass('hello')
b = MyClass('hello')
c = MyClass('world')
a is b and a == b and a is not c and a != c # True
is
is the python operator that shows two objects are the same instance. is
是python运算符,它显示两个对象是同一个实例。 ==
falls back to is
on objects where it is not overidden. ==
回落到is
在哪里它不overidden对象。
As pointed out in the comments, this can be a bit troubling if you have an __init__
with side effects. 正如评论中指出的那样,如果你有__init__
有副作用,这可能会有点麻烦。 Here's an implementation that avoids that: 这是一个避免这种情况的实现:
class Coord:
num_unique_instances = 0
_instances = {}
def __new__(cls, x, y):
if (x, y) in cls._instances:
return cls._instances[x, y]
self = super().__new__(cls)
# __init__ logic goes here -- will only run once
self.x = x
self.y = y
cls.num_unique_instances += 1
# __init__ logic ends here
cls._instances[x, y] = self
return self
# no __init__ method
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.