如何让两个对象在python中具有相同的id?

时间:2013-06-07 05:57:55

标签: python object identity

如果我有如下课程:

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)

3 个答案:

答案 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