__new__() does not return anything, on singletong pattern

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Mar 12 01:31:12 EDT 2015


Mario Figueiredo wrote:

> I'm fairly new to Python, so I don't know if the following is me
> abusing the programming language idioms, or simply a mistake of my IDE
> code inspection routine.
> 
> I have a singleton Map class which is defined like so:
> 
> class Map:
>     _instance = None
>     def __new__(cls):
>         if Map._instance is None:
>             Map._instance = super(Map, cls).__new__(cls)
>         return Map._instance

In Python 2, you need to inherit from object for __new__ to be called. In 
Python 3, it doesn't matter.

> def __init__(self, filename):
> # Instantiates from the contents of a binary file
> 
> I am now trying to add another way of constructing an instance of this
> class. (I need to be able to create a dirty empty instance that is
> going to be used by the separate map editor script).

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?


> 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(). In fact since 
this is a singleton, the method shouldn't exist at all. Just put the 
initialisation code in __new__, drop the __init__ and generate methods, and 
call Map(argument).


    def __new__(cls, width, height, fill=terrain[6]):
        if Map._instance is None:
            instance = Map._instance = super(Map, cls).__new__(cls)
            instance.author = None
            instance.name = None 
            instance.description = None
            instance.cells = [Cell(fill)] * width * height
        else:
            # Ignore the arguments. Why are you passing different arguments
            # to a singleton class? Bleh.
            instance = Map._instance
        return instance



>         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. What does your 
actual code look like? You are running PyCharm on one piece of code, then 
showing us *different* (edited) code. We cannot see what PyCharm sees, so 
how do we know why PyCharm says what it says?


> The following code runs just fine. But PyCharm flags the assignment
> with a warning telling me that generate() does not return anything and
> the I lose code completion on the mmap variable.
> 
> if __name__ == '__main__':
>     mmap = Map.generate(12, 24)
>     print(mmap.width, mmap.height, mmap.author)
> 
> I need to understand if this is just a glitch of the IDE or I am doing
> indeed something that is frowned upon and ended up caught in a
> misleading static analysis warning.


Probably.

-- 
Steve




More information about the Python-list mailing list