If I have a class like below:
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)
成立?If I have a class like below:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
同时有两个对象:
a = Point(1,2)
b = Point(1,2)
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
一起,因为在我看来它更简单,但是如果需要的话,你可以很容易地将它表示为一个类:
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__
,我一直在使用 __init__
的方法。现在我知道为什么它失败了。 - Ashwini Chaudhary__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))
>>> 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