Mario Figueiredo wrote: > On Thu, 12 Mar 2015 16:31:12 +1100, Steven D'Aprano > <steve+comp.lang.pyt...@pearwood.info> wrote: > >>Mario Figueiredo wrote: >> >> >>If this is supposed to be a singleton, you can't create more instances. >>The point of a singleton that there is only one instance (or perhaps a >>small number, two or three say). Why do you need two different ways to >>create instances if you only have one instance? >> > > The map is instantiated from the contents of a saved map file on the > main application. > > A different application, a map editor, needs to also instantiate an > object of the class Map. But in this case the map needs to either be > empty (if the user wants to create a new map), or loaded from the > saved map file (if the user wants to edit an existing map).
An empty map is just a special case of an existing map, one with no features added. I would have a loadfile() method which takes a filename on disk, opens the file and passes the contents (or the open file object) to another method, load() to do the actual work: class Map: def __new__(cls, width, height, fill, treasure=None): # Include additional args as needed. map = super().__new__.(cls) map.width = width map.height = height map.fill = fill map.treasure = treasure return map @classmethod def loadfile(cls, filename): with open(filename, 'r') as f: map = cls.load(f) return map @classmethod def load(cls, f): # validate and parse file contents # extract width, height, fill, etc. map = cls(width, height, fill, treasure) return map To get an empty map, you pass the load method a file-like object that contains whatever an empty map data file will contain. That could literally be an external file, if you so choose, or you could simply read it from a global constant or even an embedded string/bytes object: @classmethod def new(cls): """Return a new empty map.""" emptymap = b"blah blah blah width=100 height=100 fill=1" f = io.StringIO(emptymap) return cls.load(f) This, naturally, assumes that your map format is simple enough and small enough that an empty map can be embedded into your code. If an empty map is 4MB on disk, you probably don't want to do this :-) Alternatively, set the default arguments to the __new__ constructor to be whatever values an empty map uses: def __new__(cls, width=100, height=100, fill=1, treasure=None): ... and now your "create empty map" command just calls Map() with no arguments. >>> I added the following method to the class definition, above: >>> >>> @classmethod >>> def generate(cls, width, height, fill=terrain[6]): >>> if Map._instance is None: >>> Map._instance = super(Map, cls).__new__(cls) >>> else: >>> raise Exception('Cannot generate an instance of Map.') >>> >>> Map._instance.author = None >>> Map._instance.name = None >> >>Since this method modifies the singleton instance in place, it doesn't >>generate a new instance. It shouldn't be called generate(). > > No sure what you mean. That method either creates a new instance or > raises an exception. It doesn't modify an instance in-place. My mistake, I was confused. You're right, if the instance already exists, it raises an exception. >>> Map._instance.description = None >>> # etc... >>> self.cells = [Cell(fill)] * width * height >>> return Map._instance >> >>That's not your actual code, since the indentation is wrong. > > Map._instance.description = None > # etc... > self.cells = [Cell(fill)] * width * height > return Map._instance What's "self"? That's a classmethod, it's not usual to have a self local variable. -- Steven -- https://mail.python.org/mailman/listinfo/python-list