1👍
You can use **kwargs
to capture and pass through all keyword arguments that you don’t specify directly. kwargs
can be anything, but convention is to use that name. It would look as follows:
def __init__(self, mandatarg1, ckwarg1=cdefault1, **kwargs)
# do something
super(MyCustomCharField, self).__init__(**kwargs)
# do something else
Due to the double asteriks **
, all keyword arguments that are not specifically defined will be packed in a dict
object called kwargs
. By passing **kwargs
to the call to super, these values are unpacked again before the super’s __init__
function is called with these keyword arguments.
E.g. you can call the following:
field1 = MyCustomCharField(mandatvalue1, max_length=255, ckwarg1 = cvalue1)
kwargs
will then look like this:
kwargs = {'max_length': 255}
And python will handle the call to super as if you had called:
super(MyCustomCharField, self).__init__(max_length=255)
The same can be done for positional arguments with a single asteriks, convention is to do this with *args
. args
will be a tuple of the positional arguments, consistent with the order in which the arguments were passed. *args
and **kwargs
have to be the last arguments defined in a function definition. You should be careful with *args
, though: always remember that in a function definition there is no difference in positional arguments and keyword arguments. So if you were to extend the MultiValueField
class, and you want to pass the fields as a positional argument, you have to treat every single argument in you subclass’s __init__
method as a positional argument. So:
class MyCustomMultiValueField(forms.MultiValueField):
def __init__(customarg1, customarg2=None, *args, **kwargs):
# do something
super(MyCustomMultiValueField, self).__init__(*args, **kwargs)
# this won't work, as now customargs2 is (BooleanField(), DateField()), instead of fields
MyCustomMultiValueField(1, (BooleanField(), DateField()))
# you can still pass fields as a keyword argument
MyCustomMultiValueField(1, fields=(BooleanField(), DateField()))
If you only want to specify keyword arguments, or if you want to specify positional arguments after the super’s positional arguments, a common way to do that is to only specify *args
and **kwargs
as the arguments:
def __init__(self, *args, **kwargs):
keywordarg1 = kwargs.pop('keyword1', None)
mandatorykeywordarg2 = kwargs.pop('keyword2')
if len(args) == 2:
# because tuples are immutable
args = list(args)
positionalargumentafterfields = args.pop(1)
super(MyCustomMultiValueField, self).__init__(*args, **kwargs)
# *args also works with a list
A common use-case for this is when you want to specify extra arguments, while some other code relies on the positional arguments of the base class to create your subclass. Django models and forms are examples where you’d want to do this to prevent breaking the code.
Documentation on arguments in function definitions.