MFB
MFB

Reputation: 19807

Inheriting Python Class args from Super

I want to inherit the collection arg from the Base class. How?

class Base(object):
    def __init__(self, collection=None, classname=None):
        self.__collection__ = collection or self.__class__.__name__

class Thing(Base):
    def __init__(self, **kwargs):
        super(Thing, self).__init__()
        self.__dict__.update(kwargs)


t = Thing(collection='foobar')
t.__collection__

>>> 'Thing'

:(

Upvotes: 0

Views: 177

Answers (4)

Bakuriu
Bakuriu

Reputation: 101979

Do not use double underscores at the beginning of an instance variable, and avoid using them at the beginning and at the end, because double underscore has a special meaning in python.

If an instance variable's identifier starts with a double underscore it is "name mangled" to avoid clashes in the namespaces of the subclasses, and thus self.__collections actually becomes self._Base__collections. Double underscore at the beginning and end of an instance variable identifier are reserved for special methods and special names(e.g. __add__ or __class__).

Instance variables should either start with a letter(e.g. collections) or a single underscore to denote that they are private(e.g. _collections)

Anyway, in your example you are setting a collection attribute which does not exist. If you named the attribute self.collection in the Base class it would work correctly.

To make clear:

>>> class Base(object):
...     def __init__(self, collection=None):
...             self.__collection__ = collection or self.__class__.__name__
... 
>>> class Thing(Base):
...     def __init__(self, **kwargs):
...             super(Thing, self).__init__()
...             self.__dict__.update(kwargs)
... 
>>> t = Thing(collection=3)   __dict__.update creates a new instance attribute
>>> t.__collection__
'Thing'
>>> t.collection   # here it is
3
>>> t = Thing(**{'__collection__': 7})   #UGLY! Do not do this!!!
>>> t.__collection__
7

Upvotes: 0

Ehtesh Choudhury
Ehtesh Choudhury

Reputation: 7790

I don't usually use super(). I instead call the __init__ function directly. Something like:

class Base(object):
    def __init__(self, collection=None, classname=None):
        self.__collection__ = collection or self.__class__.__name__

class Thing(Base):
    def __init__(self, **kwargs):
        #super(Thing, self).__init__()
        Base.__init__(self, **kwargs)
        #self.__dict__.update(kwargs)


t = Thing(collection='foobar')
print(t.__collection__)

Should yield what you want.

Upvotes: 1

BrenBarn
BrenBarn

Reputation: 251408

Are you looking for super(Thing, self).__init__(**kwargs)? This will pass the keyword arguments along to the superclass __init__.

Upvotes: 0

Andrei Sosnin
Andrei Sosnin

Reputation: 730

You just need to 'forward' the kwargs to your base class' __init__() method:

class Thing(Base):
    def __init__(self, **kwargs):
        super(Thing, self).__init__(**kwargs)
        self.__dict__.update(kwargs)

t = Thing(collection='foobar')
assert t.__collection__ == 'foobar'
assert t.__dict__.get('collection') == 'foobar'

You were simply calling Base.__init__() with default arguments.

Upvotes: 0

Related Questions