以下のようなクラスがある場合:
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
より単純な IMO であるため、関数を一緒に使用しました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__
、他の回答を参照) を介してそれらを取得する必要があります。さらに、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 では機能しないことに注意してください。