What do * (single star) and / (slash) do as independent parameters?
Jan 9
In the following function definition, what do the * and / account for?
def func(self, param1, param2, /, param3, *, param4, param5):
print(param1, param2, param3, param4, param5)
NOTE: Not to mistake with the single|double asterisks in *args | **kwargs (solved here)
1 answer
Accepted answer · original discussion
Jan 9
The function parameter syntax (/) indicates the end of the positional only parameters, which must be specified positionally and can't be used as keyword arguments (New in Python 3.8).
Documentation specifies some of the use cases/benefits of positional-only parameters:
It allows pure Python functions to fully emulate behaviors of existing
Ccoded functions. For example, the built-inpow()function does not accept keyword arguments:def pow(x, y, z=None, /): "Emulate the built in pow() function" r = x ** y return r if z is None else r%zAnother use case is to preclude keyword arguments when the parameter name is not helpful. For example, the builtin
len()function has the signaturelen(obj, /). This precludes awkward calls such as:len(obj='hello') # The "obj" keyword argument impairs readabilityA further benefit of marking a parameter as positional-only is that it allows the parameter name to be changed in the future without risk of breaking client code. For example, in the statistics module, the parameter name dist may be changed in the future. This was made possible with the following function specification:
def quantiles(dist, /, *, n=4, method='exclusive') ...
Whereas * is used to force the caller to use named arguments. Django documentation contains a section which clearly explains a use case of named arguments:
Form fields no longer accept optional arguments as positional arguments
To help prevent runtime errors due to incorrect ordering of form field arguments, optional arguments of built-in form fields are no longer accepted as positional arguments. For example:
forms.IntegerField(25, 10)raises an exception and should be replaced with:
forms.IntegerField(max_value=25, min_value=10)
Suppose we have a method called func:
def func(self, param1, param2, /, param3, *, param4, param5):
print(param1, param2, param3, param4, param5)
It must called with
obj.func(10, 20, 30, param4=50, param5=60)
OR
obj.func(10, 20, param3=30, param4=50, param5=60)
That is,
param1,param2must be specified positionally.param3can be called either with positional or keyword argument.param4andparam5must be called with keyword argument.
Demo:
>>> class MyClass(object):
... def func(self, param1, param2, /, param3, *, param4, param5):
... return param1, param2, param3, param4, param5
...
>>> obj = MyClass()
>>>
>>> assert obj.func(10, 20, 30, param4=40, param5=50), obj.func(
... 10, 20, param3=30, param4=40, param5=50
... )
2 question comments
Use comments to ask for clarification. Post a solution as an answer.
Jan 9
Jan 9