class Klass:
def __init__(self, **kwargs):
self.func(variable=True, **kwargs)
def func(self, variable=True, **kwargs):
print(variable)
if __name__ == '__main__':
Klass(variable=False)
I was wondering why I am getting TypeError: func() got multiple values for keyword argument 'variable'.
I am thinking it should print False because I override the default value of variable to False and pass kwargs along the way.
You can't pass the same argument twice, and variable=True, **kwargs does exactly that when kwargs contains a key for variable; in this case, you made the call effectively self.func(variable=True, variable=False) which is clearly wrong. Assuming you can't receive variable as a separate argument, e.g.:
def __init__(self, variable=True, **kwargs):
self.func(variable, **kwargs)
# On Python 3, you can easily keep variable keyword-only with:
def __init__(self, *, variable=True, **kwargs):
self.func(variable, **kwargs)
# while the Python 2 equivalent for keyword-only args is rather nastier:
def __init__(self, *positional_forbidden, variable=True, **kwargs):
if positional_forbidden:
raise TypeError("__init__ takes 1 positional argument but {} were given".format(len(positional_forbidden)+1))
self.func(variable, **kwargs)
then the other approach is to set the default in the kwargs dict itself:
def __init__(self, **kwargs):
kwargs.setdefault('variable', True) # Sets variable to True only if not passed by caller
self.func(**kwargs)
In Python 3.5, with PEP 448's additional unpacking generalizations, you could one-line this safely as:
def __init__(self, **kwargs):
self.func(**{'variable': True, **kwargs})
because repeated keys are legal when creating a new dict (only the last occurrence of a key is kept), so you can create a brand new dict with unique mappings, then immediately unpack it.
When you declare an object of class Klass,
Klass(variable=False)
the variable is parsed as an keyword argument (kwargs), which is a dict anyway. So inside the __init__ method, you can find the kwargs being like
{'variable': False'}
And in
self.func(variable=True, **kwargs)
the double asterisk implies to parse everything in a dict as keyword arguments. Technically this line is equal to
self.func(variable=True, **{'variable': False'})
and equal to
self.func(variable=True, variable=False)
And that's why you got a TypeError.
Here's is probably what you are looking for:
class Klass:
def __init__(self, **kwargs):
self.func(**kwargs)
def func(self, variable=True, **kwargs):
print(variable)
if __name__ == '__main__':
Klass(variable=False)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With