0

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)])
Haydon Berrow
  • 485
  • 2
  • 6
  • 14
  • Brilliant and thank you! I had to alter the reference to Cell within the code and this now works – Haydon Berrow Jan 27 '18 at 14:09
  • I would have done, but I see no "Post your answer here", perhaps because it was marked as duplicate, and I can't post code into the comments. – Haydon Berrow Jan 27 '18 at 14:34
  • Of course, I missed that, sorry. Well, if the solution also answers one of the duplicate questions, then you could post it there. But please only do that if your solution is significantly different from the already existing answer. By the way, you wrote: "Thank you to the person who did." If this it not your solution, then please make sure that you provide proper attribution. – honk Jan 27 '18 at 14:48
  • I was thanking the (anonymous) person who wrote "This question already has an answer here:" at the top, for recognising that memoisation was a solution; I hadn't. This may have been poke, I can't tell. The other posts are details of memoisation which aren't aswers to my question. – Haydon Berrow Jan 27 '18 at 14:53
  • Yes, poke close this question as duplicate. You can see that from the yellow banner below your question. I guess you adapted an answer from one of the linked duplicates. The author of each answer is always shown below the corresponding answer. – honk Jan 27 '18 at 15:02
  • Thank you to poke for recognising that memoisation provides a solution to my problem – Haydon Berrow Jan 27 '18 at 15:09

0 Answers0