Require Keyword Arguments |
July 13th, 2014 |
| python, tech |
def score(actual, predicted):
...
and you're worried
people accidentally call it with the arguments reversed. After all,
nothing looks surprising with:
score(model.predict(data), isRepaid)
We can have a culture where everyone writes in the keyword arguments,
as:
score(actual=isRepaid, predicted=model.predict(data))
This mostly solves the problem, but could we have Python check this
for us? Yes! PEP 3102 added
this to Python 3+:
def score(*, actual, predicted):
..
But what about the Python 2 series? You could rebuild Python with this patch applied, or you
could use a decorator that verifies there are no positional arguments
and then calls the original function:
def poscheck(f):
def checked_f(*args, **kwargs):
if args:
raise PositionalArgumentsError(f)
f(**kwargs)
return checked_f
@poscheck
def score(actual, predicted):
...
This is pretty good, but what about a case like this:
# Split s on newlines ('\n'), returning a list. These newlines
# are not normally retained, but if the optional keepends argument
# is True then they're kept.
def splitlines(s, keepends=False):
...
If someone calls splitlines as
splitlines(s, True) that's going to be pretty
confusing to a reader. You'd like to make sure writers always make it
clear what the boolean is about, so you have a house style where you
write splitlines(s, keepends=True). If you used
poscheck, though, that would require
splitlines(s=s, keepends=True) which is too
verbose. So, use poscheck_except instead:
@poscheck_except(1)
def splitlines(s, keepends=False):
...
This will require that after the first positional argument all other
arguments are given with keywords, if present.
The code is poscheck on
github.
Comment via: google plus, facebook, substack