Home > database >  How to detect invalid kwargs?
How to detect invalid kwargs?

Time:01-04

I'm trying to develop a mechanism to detect invalid kwargs that is robust to inheritance. I want to create a class with an init method that checks for unexpected kwargs, and I want to create another class that inherits from this first class with the same kwarg checking. This could go deeper than two layers, but I think getting it solved for two layers allows for further extrapolation. Here's my attempt:

class MyClass(object):
    def __init__(self, **kwargs):
        # possible kwargs and default values
        self._kwargs_def = {
            'a':1, 
            'b':2,
            'c':3,
            }
        self.a = kwargs.pop('a', self._kwargs_def['a'])
        self.b = kwargs.pop('b', self._kwargs_def['b'])
        self.c = kwargs.pop('c', self._kwargs_def['c'])

        assert len(kwargs) == 0, f"Invalid kwargs: {kwargs.keys()}"
        
class MyChildClass(MyClass):
    def __init__(self, **kwargs):
        super.__init__() # run once to generate _kwargs_def
        # repeat to override defaults with any appropriate kwargs
        super.__init__(**{key:val for key, val in kwargs.items() if key in super._kwargs_def})
    
        self._kwargs_def.update({'d':4, 'e':5})
        
        self.d = kwargs.pop('d', self._kwargs_def['d'])
        self.e = kwargs.pop('e', self._kwargs_def['e'])
        
        assert len(kwargs) == 0, f"Invalid kwargs: {kwargs.keys()}"
        
my_instance = MyClass(a=7) # works
# I need a way around this: TypeError: descriptor '__init__' of 'super' object needs an argument
my_child_instance = MyChildClass(e=37) # doesn't work but should???
my_instance = MyClass(z=7) # fails and should fail
my_child_instance = MyChildClass(z=37) # fails but for wrong reason

CodePudding user response:

You've made this harder than it needs to be. Note that I have no code at all in the derived class.

class MyClass(object):
    kwargs_def = {
        'a':1, 
        'b':2,
        'c':3,
    }
    def __init__(self, **kwargs):
        # possible kwargs and default values
        assert all(k in self.kwargs_def for k in kwargs), f"Invalid kwargs: {kwargs.keys()}"
        self.__dict__.update( self.kwargs_def )
        self.__dict__.update( kwargs )
        
class MyChildClass(MyClass):
    kwargs_def = MyClass.kwargs_def.copy()
    kwargs_def.update({
        'd':4,
        'e':5
    })
        
my_instance = MyClass(a=7) # works
my_child_instance = MyChildClass(e=37) # doesn't work but should???
my_instance = MyClass(z=7) # fails and should fail
my_child_instance = MyChildClass(z=37) # fails but for wrong reason

CodePudding user response:

Python already has checks for invalid keyword arguments. Just use the built-in mechanisms:

class MyClass:
    def __init__(self, *, a=1, b=2, c=3):
        self.a = a
        self.b = b
        self.c = c

class MyChildClass(MyClass):
    def __init__(self, *, d=4, e=5, **kwargs):
        super().__init__(**kwargs)
        self.d = d
        self.e = e

Any invalid keyword arguments will get rejected by MyClass.__init__. (Positional arguments will be rejected because these parameters are defined as keyword-only.)

  •  Tags:  
  • Related