In Python you may have a function definition:
def info(object, spacing=10, collapse=1)
which could be called in any of the following ways:
info(odbchelper)
info(odbchelper, 12)
info(odbchelper, collapse=0)
info(spacing=15, object=odbchelper)
thanks to Python's allowing of any-order arguments, so long as they're named.
The problem we're having is as some of our larger functions grow, people might be adding parameters between spacing
and collapse
, meaning that the wrong values may be going to parameters that aren't named. In addition sometimes it's not always clear as to what needs to go in. We're after a way to force people to name certain parameters - not just a coding standard, but ideally a flag or pydev plugin?
so that in the above 4 examples, only the last would pass the check as all the parameters are named.
Odds are we'll only turn it on for certain functions, but any suggestions as to how to implement this - or if it's even possible would be appreciated.
A solution for this is to enforce using keyword arguments. This is possible to do in Python 2 by specifying a keyword argument dictionary, typically called **kwargs . However, in Python 3, there is a simple way to enforce it! By adding a * in the function arguments, we force all succeeding arguments to be named.
Parameters are the input variables bounded by parentheses when defining a function, whereas arguments are the values assigned to these parameters when passed into a function (or method) during a function call.
5 Types of Arguments in Python Function Definition:positional arguments. arbitrary positional arguments. arbitrary keyword arguments.
Python allows function arguments to have default values. If the function is called without the argument, the argument gets its default value.
In Python 3 - Yes, you can specify *
in the argument list.
From docs:
Parameters after “*” or “*identifier” are keyword-only parameters and may only be passed used keyword arguments.
>>> def foo(pos, *, forcenamed):
... print(pos, forcenamed)
...
>>> foo(pos=10, forcenamed=20)
10 20
>>> foo(10, forcenamed=20)
10 20
>>> foo(10, 20)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 1 positional argument (2 given)
This can also be combined with **kwargs
:
def foo(pos, *, forcenamed, **kwargs):
To complete example:
def foo(pos, *, forcenamed ):
print(pos, forcenamed)
foo(pos=10, forcenamed=20)
foo(10, forcenamed=20)
# basically you always have to give the value!
foo(10)
output:
Traceback (most recent call last):
File "/Users/brando/anaconda3/envs/metalearning/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3444, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-12-ab74191b3e9e>", line 7, in <module>
foo(10)
TypeError: foo() missing 1 required keyword-only argument: 'forcenamed'
So you are forced to always give the value. If you don't call it you don't have to do anything else named argument forced.
You can force people to use keyword arguments in Python3 by defining a function in the following way.
def foo(*, arg0="default0", arg1="default1", arg2="default2"):
pass
By making the first argument a positional argument with no name you force everyone who calls the function to use the keyword arguments which is what I think you were asking about. In Python2 the only way to do this is to define a function like this
def foo(**kwargs):
pass
That'll force the caller to use kwargs but this isn't that great of a solution as you'd then have to put a check to only accept the argument that you need.
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