The background is that I have Cells associated with a coordinate system and I want to create them on the fly. Each point will have a unique Cell if it has one but there will be many points that do not. It would be much easier to code and use if I could just say Cell() and I automatically get the pre-existing one if it exists and a new one it if doesn't.
I could use a factory-constructor like this
class Cell():
lookup = {}
index = -1 # index is a one-up counter to distinguish objects
def __init__(self,coord):
Cell.index += 1
self.index = Cell.index
self.coord = coord
Cell.lookup[coord] = self
def __repr__(self):
return "{}<{}>".format(self.__class__.__name__,self.index,self.coord)
@classmethod
def factory(self,coord):
try:
return Cell.lookup[coord]
except KeyError:
return Cell(coord)
# This creates four different Cells
print([Cell(i) for i in (0,1,0,1)])
# but this creates only two
print([Cell.factory(10+i) for i in (0,1,0,1)])
but I think it's unaesthetic and there is the danger that I might accidentally use the Cell constructor directly.
I could hide Cell as a different class
class _Cell():
lookup = {}
index = -1
def __init__(self,coord):
_Cell.index += 1
self.index = _Cell.index
self.coord = coord
_Cell.lookup[coord] = self
def __repr__(self):
return "{}<{}>".format(self.__class__.__name__,self.index,self.coord)
@classmethod
def factory(self,coord):
try:
return _Cell.lookup[coord]
except KeyError:
return _Cell(coord)
def Cell(coord):
return _Cell.factory(coord)
# This creates only two different Cells
print([Cell(i) for i in (0,1,0,1)])
but now I'm not creating objects of type Cell. Is there a way of making the constructor I want aesthetic and safer?
Post Edit .. I had not recognised this as an application for memoisation. Thank you to the person who did. This code works
_memoized = {}
def memoize(f):
"""
A special-case memoizer
"""
def memoized(*args):
key = (*args,)
if key not in _memoized:
_memoized[key] = f(*args)
return _memoized[key]
return memoized
@memoize
class Cell():
index = -1
def __init__(self,coord):
self.__class__.index += 1
self.index = self.__class__.index
self.coord = coord
def __repr__(self):
return "{}<{}>".format(self.__class__.__name__,self.index,self.coord)
# This creates only two different Cells
print([Cell(i) for i in (0,1,0,1)])