How to pass all arguments from __init__ to super class

12,584

You are almost there:

class ZipArchive(zipfile.ZipFile):
    def __init__(self, *args, **kwargs):
        """
        Constructor with some extra params:

        * verbose: be verbose about what we do. Defaults to True.

        For other params see: zipfile.ZipFile
        """
        self.verbose = kwargs.pop('verbose', True)

        # zipfile.ZipFile is an old-style class, cannot use super() here:
        zipfile.ZipFile.__init__(self, *args, **kwargs)

Python 2 is a little persnickety and funny about mixing *args, **kwargs and additional named keyword arguments; your best bet is to not add additional explicit keyword arguments and just take them from kwargs instead.

The dict.pop() method removes the key from the dictionary, if present, returning the associated value, or the default we specified if missing. This means that we do not pass verbose on to the super class. Use kwargs.get('verbose', True) if you just want to check if the paramater has been set without removing it.

Share:
12,584
Nux
Author by

Nux

I like JavaScript just for fun and rapid creation of code that is usable for me and can be usable for others. I also speak other programming languages ;-). As for me on Stacks - I ask hard questions, but I really appreciate even when someone gives me clues on how to get to the answer :-].

Updated on June 03, 2022

Comments

  • Nux
    Nux about 2 years

    IS there any magic I can use in Python to to effectively use super constructor by just adding some extra arguments?

    Ideally I'd like to use something like:

    class ZipArchive(zipfile.ZipFile):
        def __init__(self, verbose=True, **kwargs):
            """
            Constructor with some extra params.
    
            For other params see: zipfile.ZipFile
            """
            self.verbose = verbose
            super(ZipArchive, self).__init__(**kwargs)
    

    And then be able to use the original constructor arguments mixed with some extra stuff from my class. Like so:

    zip = ZipArchive('test.zip', 'w')
    zip = ZipArchive('test.zip', 'w', verbose=False)
    

    I'm using Python 2.6, but if the magic can only be achieved in higher version of Python then I'm interested too.

    EDIT: I should probably mention that above doesn't work. The error is: TypeError: __init__() takes at most 2 arguments (3 given)

  • glglgl
    glglgl about 11 years
    Or self.verbose = kwargs.pop('verbose', verbosedefaultvalue)
  • Martijn Pieters
    Martijn Pieters about 11 years
    @glglgl: indeed, much beter, I forgot pop() takes a default.
  • Ber
    Ber about 11 years
    You may also want to consider self.verbose = kwargs.get('verbose', verbosedefaultvalue) in case you want to look at args that also do the the super class method.
  • Martijn Pieters
    Martijn Pieters about 11 years
    @Ber: There, made that more explicit.
  • Nux
    Nux about 11 years
    That does seem to work in terms of params, but I'm getting TypeError: super() argument 1 must be type, not classobj. And so to my knowledge I cannot inherit from zipfile.ZipFile and use super as the original class is an old style class :-(. At least on Python 2.6.6. But thanks I'll use this in some other case.
  • Martijn Pieters
    Martijn Pieters about 11 years
    @Nux: Then zipfile.ZipFile.__init__(self, *args, **kwargs) will work; same principle applies.
  • Nux
    Nux about 11 years
    Thanks! I forgot about passing self and though it just won't work.