如果我有如下课程:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
并有 2 个对象:
a = Point(1,2)
b = Point(1,2)
我如何修改类 Point 来制作id(a) == id(b)
?
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 在他的回答中指出的那样,您应该考虑使用weakref.WeakValueDictionary
如此删除的类实例(namedtuple
显然不能使用)不会保留在内存中,因为它们仍然在字典本身中被引用。
您需要有一个全局对象字典,并通过工厂函数(或自定义__new__
,请参阅其他答案)获取它们。此外,考虑使用 aWeakValueDictionary
这样您就不会不必要地用不再需要的对象填充内存。
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。
如果需要比较两个对象是否包含相同的值,可以实现eq运算符:
>>> 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