Search code examples
pythonpython-3.xinheritanceattributeerror

Python 3 inheritance AttributeError. How to solve it?


I've been reading a lot about Python inheritance, but I can't understand how to use it in the right way. I learnt about how inheritance works using Java, so I guess that's why I'm a little confused.

Here is my super class:

class MongoData:
    def __init__(self, db_name, coll_name):
        self.__config = configparser.ConfigParser()
        self.__config.read('conf.ini')
        self.__connect = self.__config.get('mongo', 'connect')
        self.__client = MongoClient(self.__connect)
        self.__db_name = db_name
        self.__coll_name = coll_name
        self.__db = None
        self.__coll = None

        if self.__db_name in self.__client.database_names(): # If DB already exists
            print('DB exist')
            self.__db = self.__client[self.__db_name]
            if self.__coll_name in self.__db.collection_names(): # If collection already exists
                print('Collection exists')
                self.__coll = self.__db[self.__coll_name]

            else: # If collection does not exist, create it
                self.__db = self.__db_name
                self.__coll = self.__db[self.__coll_name]
                print(self.__db.collection_names())

        else: # If DB does not exist, create it
            print('Creating database...')
            self.__db = self.__client[self.__db_name]
            self.__coll = self.__db[self.__coll_name]
            #print(self.__db.collection_names())
            print("Database {} and collection {} successfully created.".format(self.__db_name, self.__coll_name))

    def writeDB(self, wdict):
        """Method to implement"""
        raise NotImplementedError

As you can see, I have a big init and I would like to inherit it in my subclass. Also I have a abstract method to be implemented in the subclass.

And here is the code of my subclass:

class AttackDB(MongoData):
    __metaclass__  = abc.ABCMeta

    def __init__(self, db_name, coll_name):
        MongoData.__init__(self, db_name, coll_name)

    @abc.abstractmethod
    def writeDB(self, wdict):
        doc_id = self.__coll.insert_one(attack).inserted_id
        print("Attack with id {} was inserted in the DB.".format(dic_id))

As I supposed, I get a AttributeError

AttributeError: 'AttackDB' object has no attribute '_AttackDB__coll'

My question is, what can I do no to rewrite the hole init?

Thank you.

Edit: How about in the super class returning self.__db and self.__coll? It works for me, but I'm not sure if it is a "good" solution.


Solution

  • Welcome to Python, Elena!

    As you have noticed already, Python is a bit different on handling inheritance than other languages. What you found is called a name mangling because of the nature of python.

    So if you write:

    class MongoData:
        def __init__(self, db_name, coll_name):
            self.__config = configparser.ConfigParser()
    

    What you get in child is variable called _MongoData__config, not the self.__config (remember _AttackDB__coll there? ) which might confuse you a bit, however as you understand better how Python works things finally starting to make sense.

    Best practices for one language does not always work for others, so advice here is either use a different naming or use a composition over inheritance. Even Mixin pattern might be dangerous to some degree.

    Hope that answers your question.