如果我有如下课程:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
有两个对象:
a = Point(1,2)
b = Point(1,2)
如何修改类Point以使id(a) == id(b)
?
答案 0 :(得分:8)
class Point(object):
__cache = {}
def __new__(cls, x, y):
if (x, y) in Point.__cache:
return Point.__cache[(x, y)]
else:
o = object.__new__(cls)
o.x = x
o.y = y
Point.__cache[(x, y)] = o
return o
>>> Point(1, 2)
<__main__.Point object at 0xb6f5d24c>
>>> id(Point(1, 2)) == id(Point(1,2))
True
当您需要一个非常简单的类Point
时,请始终考虑collections.namedtuple
from collections import namedtuple
def Point(x, y, _Point=namedtuple('Point', 'x y'), _cache={}):
return _cache.setdefault((x, y), _Point(x, y))
>>> Point(1, 2)
Point(x=1, y=2)
>>> id(Point(1, 2)) == id(Point(1, 2))
True
我在namedtuple
旁边使用了一个函数,因为它更简单的IMO,但如果需要,您可以轻松地将其表示为一个类:
class Point(namedtuple('Point', 'x y')):
__cache = {}
def __new__(cls, x, y):
return Point.__cache.setdefault((x, y),
super(cls, Point).__new__(cls, x, y))
正如@PetrViktorin在他的answer中所指出的,您应该考虑使用weakref.WeakValueDictionary
这样删除的类实例(显然不能与namedtuple
一起使用)不要留在因为它们仍然在字典本身中被引用。
答案 1 :(得分:5)
您需要拥有对象的全局字典,并通过工厂函数(或自定义__new__
)获取它们,请参阅其他答案)。另外,请考虑使用WeakValueDictionary
,以免不必要地使用不再需要的对象填充内存。
from weakref import WeakValueDictionary
class _Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
# Cache of Point objects the program currently uses
_points = WeakValueDictionary()
def Point(x, y):
"""Create a Point object"""
# Note that this is a function (a "factory function")
# You can also override Point.__new__ instead
try:
return _points[x, y]
except KeyError:
_points[x, y] = point = _Point(x, y)
return point
if __name__ == '__main__':
# A basic demo
print Point(1, 2)
print id(Point(1, 2))
print Point(2, 3) == Point(2, 3)
pt_2_3 = Point(2, 3)
# The Point(1, 2) we created earlier is not needed any more.
# In current CPython, it will have been been garbage collected by now
# (but note that Python makes no guarantees about when objects are deleted)
# If we create a new Point(1, 2), it should get a different id
print id(Point(1, 2))
请注意,namedtuple不适用于WeakValueDictionary。
答案 2 :(得分:2)
如果您需要比较两个对象是否包含相同的值,您可以实现eq operator:
>>> class Point(object):
... def __init__(self, x, y):
... self.x = x
... self.y = y
... def __eq__(self, other):
... return self.x == other.x and self.y == other.y
...
>>> a = Point(1,2)
>>> b = Point(1,2)
>>> a == b
True
>>> b = Point(2,2)
>>> a == b
False