ArnoBen
ArnoBen

Reputation: 115

Can't grasp : making a simple singleton in python (for a mongodb manager)

I have read the various main examples of singletons but I have trouble making what I want. My main inspiration here is this example :

class OnlyOne:
    class __OnlyOne:
        def __init__(self, arg):
            self.val = arg

        def __str__(self):
            return repr(self) + self.val
    instance = None
    def __init__(self, arg):
        if not OnlyOne.instance:
            OnlyOne.instance = OnlyOne.__OnlyOne(arg)
        else:
            OnlyOne.instance.val = arg
    def __getattr__(self, name):
        return getattr(self.instance, name)

But I don't need anything like getattr, here is my code so far:

class MongoManager:
    class __MongoManager:
        def __init__(self):
            # Initialise client
            self.client = pymongo.MongoClient('localhost', 27017)

    __instance = None

    def __init__(self):
        if not MongoManager.__instance:
            MongoManager.__instance = MongoManager.__MongoManager()

All I want is to get the variable client when I type MongoManager.client, but I get the error AttributeError: 'MongoManager' object has no attribute 'client'. I guess I could try with getattr and check something like if arg == "client" but it feels dirty, I'm sure there's a proper way to do that.

Upvotes: 1

Views: 3598

Answers (3)

Utkarsh Pandey
Utkarsh Pandey

Reputation: 1716

from pymongo import MongoClient

class MongoDB():
    _instance = None
    _connection = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super(MongoDB, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def get_connection(self):
        if self._connection is None:
            self._connection = MongoClient("mongodb://localhost:27017/")
        return self._connection

# Usage example
if __name__ == "__main__":
    db1 = MongoDB()
    db2 = MongoDB()

    print(db1.get_connection())  # Should print the same connection object
    print(db2.get_connection())  # Should print the same connection object
    print(db1 is db2)            # Should print True

Upvotes: 0

ArnoBen
ArnoBen

Reputation: 115

I managed to do exactly what I wanted. I didn't completely understand how __getattr__ worked so a bit more reading was necessary.

class MongoManager:
    class __MongoManager:
        def __init__(self):
            # Initialise mongo client
            self.client = pymongo.MongoClient('localhost', 27017)

    __instance = None

    def __init__(self):
        if not MongoManager.__instance:
            MongoManager.__instance = MongoManager.__MongoManager()

    def __getattr__(self, item):
        return getattr(self.__instance, item)

Now whenever I call MongoManager().client, I get the desired client.

Upvotes: 1

Pratik
Pratik

Reputation: 1399

Try this:

class MongoManager:
     __instance = None
     @staticmethod 
     def getInstance():
         if MongoManager.__instance == None:
             MongoManager()
         return MongoManager.__instance
     def __init__(self):
        if MongoManager.__instance != None:
            raise Exception("This class is a singleton!")
        else:
            MongoManager.__instance = pymongo.MongoClient('localhost', 27017)

You can get instance of this class by calling MongoManager.getInstance().

What we are doing here? We have a class variable __instance and when object of the class is created, we are initializing it. Now, when we call getInstance() this instance which is stored in __instance will get passed instead of creating new instance.

Upvotes: 5

Related Questions