Search code examples
pythonkeyword-argument

Conditional assignment of class variable in Python


How can I conditionally set an attribute in the __init__ of a class, from a **kwargs parameter?

I know that I can do:

default = 1

class foo():
    def __init__(self, X=None, Y=None):
        self.X = X if X else default  
        self.Y = Y if Y else default

F = foo()
f = foo(X=2, Y=3)

but I want to make this work with a variable-keyword parameter (**kwargs), in order to understand them properly.

These attempts did not work:

default = 1

class foo():
    def __init__(self, **kwargs):
        self.X = default or kwargs['X'] 
        self.Y = default or kwargs['Y']

F = foo()
f = foo(X=2, Y=3)

This way, only the default value is used even if other values are provided. If the order is switched (kwargs['X'] or default etc.), the code raises a KeyError if the keyword arguments are not provided.

default = 1

class foo():
    def __init__(self, **kwargs):
        self.X = value if kwargs["X"] is None else kwargs["X"]
        self.Y = value if kwargs["Y"] is None else kwargs["Y"]

F = foo()
f = foo(X=2, Y=3)

This still raises a KeyError for missing keyword arguments.


Solution

  • class foo():
        def __init__(self, **kwargs):
            self.X =  kwargs.get('X', value) # get() take key_name, default value this opetions 
            self.Y = kwargs.get('Y', value)
    
    
    # or use normal params with default value 
    class foo():
        # change dict to  any type
        def __init__(self, x = None, y = None):
            self.X =  x or value
            self.Y = y or value 
    
    
    # or better use Keyword Argument with default value if you have x y only 
    
    class foo():
        # change dict to  any type
        def __init__(self, x: dict = None, y: dict = None):
            self.X =  x or value
            self.Y = y or value 
    
    

    you need also know when should use **kwargs

    There are two common cases:

    First: You are wrapping another function which takes a number of keyword argument, but you are just going to pass them along:

    def my_wrapper(a, b, **kwargs):
        do_something_first(a, b)
        the_real_function(**kwargs)
    

    Second: You are willing to accept any keyword argument, for example, to set attributes on an object:

    class OpenEndedObject:
        def __init__(self, **kwargs):
            for k, v in kwargs.items():
                setattr(self, k, v)
    
    foo = OpenEndedObject(a=1, foo='bar')
    assert foo.a == 1
    assert foo.foo == 'bar'
    

    read this if you need know more

    Why use **kwargs in python? What are some real world advantages over using named arguments?