How to make two objects the same identifiers in python?

If I have a class as shown below:

class Point(object): def __init__(self, x, y): self.x = x self.y = y 

And they have 2 objects:

 a = Point(1,2) b = Point(1,2) 

How to change the Point class to make id(a) == id(b) ?

+4
source share
3 answers
 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) ox = x oy = 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 

If you need a really simple class like Point , always consider 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 

I used the function next to namedtuple because it is a simpler IMO, but you can easily represent it as a class if necessary:

 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)) 

As @PetrViktorin pointed out in his answer, you should consider using weakref.WeakValueDictionary so that remote class instances (apparently don't work with namedtuple ) do not remain in memory since they are still referenced in the dictionary itself.

+8
source

You need to have a global dictionary of objects and get them through the factory function (or custom __new__ , see other answers). Also, consider using WeakValueDictionary so that you do not WeakValueDictionary memory with objects that are no longer needed.

 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)) 

Note that namedtuple will not work with WeakValueDictionary.

+5
source

If you need to compare whether your two objects have the same values, you can implement the 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 
+2
source

Source: https://habr.com/ru/post/1484973/


All Articles