code base 5000
code base 5000

Reputation: 4102

How do I properly inherit from a base class using Super() (Python 2/3)?

I have two classes, one a base class and the second needs to inherit from the base class. My issue with with the proper use of super() in this case.

When I create my class TestService, it inherits from ServiceMap, so I was thinking the desired MRO should be: TestService -> ServiceMap -> OrderedDict.

Would this mean in my initializer of TestService I should call super(ServiceMap, self).__init__(value=value, kwargs=None)? Then initialize the rest of the TestService class? (Shown below). Or do I need to re-create the initializer from ServiceMap in every inherited class? I really don't want to re-create that code since there will be multiple types of Services inheriting from type ServiceMap.

Please provide some super() guidance!

Thanks

    from collections import OrderedDict
    from sys import version_info
    from inspect import ismethod
    import json
    import six
    import copy

    class ServiceMap(OrderedDict):
        _map = None
        #----------------------------------------------------------------------
        def __init__(self, value=None, **kwargs):
            """Initializer object"""
            self._map = OrderedDict()
            if value:
                if isinstance(value, dict):
                    for k,v in six.iteritems(value):
                        if isinstance(v, dict):
                            v = ServiceMap(value=v)
                        self._map[k] = v
                        del k,v
            if kwargs:
                for k,v in six.iteritems(kwargs):
                    self._map[k] = v
        #----------------------------------------------------------------------
        def items(self):
            return six.iteritems(self._map)
        #----------------------------------------------------------------------
        def iteritems(self):
            return six.iteritems(self._map)
        #----------------------------------------------------------------------
        def __iter__(self):
            return self._map.__iter__()
        #----------------------------------------------------------------------
        def next(self):
            return self._map.next()
        #----------------------------------------------------------------------
        def __setitem__(self, k, v):
            self._map[k] = v
        #----------------------------------------------------------------------
        def __getitem__(self, k):
            if k not in self._map:
                # if parameter k DNE, create a empty object as ServiceMap
                self[k] = ServiceMap()
            return self._map[k]
        #----------------------------------------------------------------------
        def __setattr__(self, k, v):
            if k == '_map':
                super(ServiceMap, self).__setattr__(k,v)
            else:
                self[k] = v
        #----------------------------------------------------------------------
        def __getattr__(self, k):
            if k == '_map':
                super(ServiceMap, self).__getattr__(k)
            else:
                return self[k]
        #----------------------------------------------------------------------
        def __delattr__(self, key):
            return self._map.__delitem__(key)
        #----------------------------------------------------------------------
        def __contains__(self, k):
            return self._map.__contains__(k)
        #----------------------------------------------------------------------
        def __str__(self):
            """represents the object as a string"""
            return json.dumps(self.as_dictionary())
        #----------------------------------------------------------------------
        def __repr__(self):
            return str(self)
        #----------------------------------------------------------------------
        def as_dictionary(self):
            """
            recursively iterate the object inorder to conver the ServiceMap object
            to a traditional dictionary type object."""
            vals = {}
            for k,v in self.items():
                if type(v) is ServiceMap:
                    vals[k] = v.as_dictionary()
                else:
                    vals[k] = v
                del k,v
            return vals
        #----------------------------------------------------------------------
        def values(self):
            return self._map.values()
        #----------------------------------------------------------------------
        def __cmp__(self, value):
            value = ServiceMap.compare(value)
            return self._map.__cmp__(value)
        #----------------------------------------------------------------------
        def __eq__(self, value):
            value = ServiceMap.compare(value)
            if not isinstance(value, dict):
                return False
            return self._map.__eq__(value)
        #----------------------------------------------------------------------
        def __ge__(self, value):
            value = ServiceMap.compare(value)
            return self._map.__ge__(value)
        #----------------------------------------------------------------------
        def __gt__(self, value):
            value = ServiceMap.compare(value)
            return self._map.__gt__(value)
        #----------------------------------------------------------------------
        def __le__(self, value):
            value = ServiceMap.compare(value)
            return self._map.__le__(value)
        #----------------------------------------------------------------------
        def __lt__(self, value):
            value = ServiceMap.compare(value)
            return self._map.__lt__(value)
        #----------------------------------------------------------------------
        def __ne__(self, value):
            value = ServiceMap.compare(value)
            return self._map.__ne__(value)
        #----------------------------------------------------------------------
        def __delitem__(self, key):
            return self._map.__delitem__(key)
        #----------------------------------------------------------------------
        def __len__(self):
            return self._map.__len__()
        #----------------------------------------------------------------------
        def clear(self):
            self._map.clear()
        #----------------------------------------------------------------------
        def copy(self):
            return copy.deepcopy(self)
        #----------------------------------------------------------------------
        def get(self, key, default=None):
            return self._map.get(key, default)
        #----------------------------------------------------------------------
        def has_key(self, key):
            return key in self._map
        #----------------------------------------------------------------------
        def iterkeys(self):
            return self._map.iterkeys()
        #----------------------------------------------------------------------
        def itervalues(self):
            return self._map.itervalues()
        #----------------------------------------------------------------------
        def keys(self):
            return self._map.keys()
        #----------------------------------------------------------------------
        def pop(self, key, default=None):
            return self._map.pop(key, default)
        #----------------------------------------------------------------------
        def popitem(self):
            return self._map.popitem()
        #----------------------------------------------------------------------
        def setdefault(self, key, default=None):
            self._map.setdefault(key, default)
        #----------------------------------------------------------------------
        def update(self, *args, **kwargs):
            if len(args) != 0:
                self._map.update(*args)
            self._map.update(kwargs)
        #----------------------------------------------------------------------
        def viewitems(self):
            return self._map.viewitems()
        #----------------------------------------------------------------------
        def viewkeys(self):
            return self._map.viewkeys()
        #----------------------------------------------------------------------
        def viewvalues(self):
            return self._map.viewvalues()
        #----------------------------------------------------------------------
        @classmethod
        def fromkeys(cls, seq, value=None):
            """
            creates a ServiceMap object from a set of keys with default values
            This allows the creation of template objects.
            """
            val = ServiceMap()
            val._map = OrderedDict.fromkeys(seq, value)
            return val
        #----------------------------------------------------------------------
        @classmethod
        def compare(self, value):
            if type(value) is ServiceMap:
                return value._map
            else:
                return value

    class TestService(ServiceMap):
        _con = None
        _url = None
        def __init__(self, url, connection, value=None):
            super(ServiceMap, self).__init__(value=value)
            self._url = None
            self._con = None

Upvotes: 0

Views: 364

Answers (4)

Madlozoz
Madlozoz

Reputation: 367

The simple way to inherit with Python 3 is

class TestService(ServiceMap):

  def __init__(self, value=None, **kwargs):
    super().__init__(value, kwargs) #equivalent to ServiceMap.__init__(self,value, kwargs) 
    code_specific to this class()

This gives you a "proper" ServiceMap that you then complement

Upvotes: 1

snakecharmerb
snakecharmerb

Reputation: 55600

Use super when you are extending a method in a superclass, that is you want to run the superclass's method's code as well as that in the child class.

Your example code is not correct: you need to call super(TestService, self)__ init __ (value=value) to run the __ init __ method of the superclass, then you can continue to initialise the child class.

If you are not extending a method, there's no need for a super call, just don't define the method in the child class and the superclass code will run.

If you are overriding a method, define the method in the subclass but don't call super.

In Python3 you don't need to pass arguments to super, you can just call super().some_method(arg1, arg2)

(Edited to reflect Zondo's comment)

Upvotes: 0

zondo
zondo

Reputation: 20336

super() is given for its first argument the point at which you would like to get the parent class. Usually, that's the same class as the one you are currently defining, so that you will get the __init__ method of the parent of the class you are currently defining. In this case, you want to use super(TestService, self). Sometimes, you'll define a subclass of TestService and you don't define the __init__ method. That means that the TestService __init__ method will be used. Since TestService explicitly used TestService for super(), you will still be getting the correct parent __init__ method. If you used self.__class__, which may be tempting, that line will go into infinite recursion for a subclass.

Upvotes: 0

Mike Müller
Mike Müller

Reputation: 85432

You need to use:

class TestService(ServiceMap):
    def __init__(self, url, connection, value=None):
        super(TestService, self).__init__(value=value)

This calls the __init__() of the parent class, in your case ServiceMap and creates the desired mro.

Upvotes: 0

Related Questions