5

如果我有如下课程:

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)

4

3 回答 3

9
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显然不能使用)不会保留在内存中,因为它们仍然在字典本身中被引用。

于 2013-06-07T06:07:53.833 回答
5

您需要有一个全局对象字典,并通过工厂函数(或自定义__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。

于 2013-06-07T07:06:24.007 回答
2

如果需要比较两个对象是否包含相同的,可以实现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
于 2013-06-07T06:56:20.643 回答