0

I recently started coding in Python and I have a question about the **kwargs parameter and class initialization.

In the case of the following class instantiation and init method, how do I know what is stored in **kwargs? In this case, 'net' is a python dictionary containing different keys. Are those keys loaded into the **kwargs parameter? Furthermore, if I try to print **kwargs in the init method it is not outputting any print to the python console, why is this? Am I not allowed to print inside the init method?

Thank you.

''' instantiation '''    
    sf = op.algorithms.StokesFlow(network=net, phase=water)


''' __init__ method of the StokesFlow class '''
    def __init__(self, settings={}, phase=None, **kwargs):
        def_set = {'phase': None,
                   'quantity': 'pore.pressure',
                   'conductance': 'throat.hydraulic_conductance',
                   'gui': {'setup':        {'phase': None,
                                            'quantity': '',
                                            'conductance': ''},
                           'set_rate_BC':  {'pores': None,
                                            'values': None},
                           'set_value_BC': {'pores': None,
                                            'values': None},
                           'set_source':   {'pores': None,
                                            'propname': ''}
                           }
                   }
        print("kwargs:", **kwargs)
        super().__init__(**kwargs)
        self.settings.update(def_set)
        self.settings.update(settings)
        if phase is not None:
            self.setup(phase=phase)
  • 4
    `print("kwargs:", kwargs)`. – ekhumoro Sep 26 '19 at 09:33
  • 3
    The whole point of using `**kwargs` is that this lets you ignore (and perhaps pass on) arguments you don't care about. For example, if you subclass another class and want to call its `__init__` you don't want to duplicate all the keyword arguments in your own function's definition because *(a)* [DRY principle](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) and *(b)* if they change you have to change your code, too, and you want to avoid that. – tripleee Sep 26 '19 at 09:40

1 Answers1

3

Some explanations:

kwargs is a dict. Kwargs catches named arguments that are not separately specified in the function signature. ** means the dict is being unpacked. (Explanation on unpacking is here)

You get nothing because you probably haven't passed anything to that function.

def fun1(**kwargs):
    print(kwargs)

fun1() -> prints {}

fun1(1) -> error, TypeError: fun1() takes 0 positional arguments but 1 was given

fun1(a=1) -> {'a': 1}

What happens when you do print(**kwargs) in there like you did in your code?

First example will not print anything (empty dictionary unpacks to nothing): print(**{}) == print().

Last example will break. Because print(**{'a': 1}) == print(a=1) and print doesn't like anything like that

h4z3
  • 5,265
  • 1
  • 15
  • 29
  • Thank you! If I print("kwargs: ", **kwargs) like in the code or print("kwargs: " kwargs) as suggested, it outputs nothing, but my script also doens't crash. I would expect that at least "kwargs: " would be printed if my script does not pass on any kwargs. – RikDevelops Sep 26 '19 at 10:06
  • 2
    @RikDevelops either you've not edited the right file, or you forgot to reload your module before testing (or to restart your app or whatever), or there's something wrapping the `__init__` that messes your kwargs. I suggest it's time to track code execution in the step debugger... – bruno desthuilliers Sep 26 '19 at 10:35