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:<
As other answers say, changing function signatures is a bad idea. Either add new parameters to the end, or fix every caller if arguments are inserted.
If you still want to do it, use a function decorator and the inspect.getargspec function. It would be used something like this:
@require_named_args
def info(object, spacing=10, collapse=1):
....
Implementation of require_named_args
is left as an exercise for the reader.
I would not bother. It will be slow every time the function is called, and you will get better results from writing code more carefully.
The python3 keyword-only arguments (*
) can be simulated in python2.x with **kwargs
Consider the following python3 code:
def f(pos_arg, *, no_default, has_default='default'):
print(pos_arg, no_default, has_default)
and its behaviour:
>>> f(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 3 were given
>>> f(1, no_default='hi')
1 hi default
>>> f(1, no_default='hi', has_default='hello')
1 hi hello
>>> f(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() missing 1 required keyword-only argument: 'no_default'
>>> f(1, no_default=1, wat='wat')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() got an unexpected keyword argument 'wat'
This can be simulated using the following, note I've taken the liberty of switching TypeError
to KeyError
in the "required named argument" case, it wouldn't be too much work to make that the same exception type as well
def f(pos_arg, **kwargs):
no_default = kwargs.pop('no_default')
has_default = kwargs.pop('has_default', 'default')
if kwargs:
raise TypeError('unexpected keyword argument(s) {}'.format(', '.join(sorted(kwargs))))
print(pos_arg, no_default, has_default)
And behaviour:
>>> f(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes exactly 1 argument (3 given)
>>> f(1, no_default='hi')
(1, 'hi', 'default')
>>> f(1, no_default='hi', has_default='hello')
(1, 'hi', 'hello')
>>> f(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
KeyError: 'no_default'
>>> f(1, no_default=1, wat='wat')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in f
TypeError: unexpected keyword argument(s) wat
The recipe works equally as well in python3.x, but should be avoided if you are python3.x only
You could declare your functions as receiving **args
only. That would mandate keyword arguments but you'd have some extra work to make sure only valid names are passed in.
def foo(**args):
print args
foo(1,2) # Raises TypeError: foo() takes exactly 0 arguments (2 given)
foo(hello = 1, goodbye = 2) # Works fine.
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.
You could use the **
operator:
def info(**kwargs):
this way people are forced to use named parameters.
def cheeseshop(kind, *arguments, **keywords):
in python if use *args that means you can pass n-number of positional arguments for this parameter - which will be accessed as a tuple inside the function.
And if use **kw that means its keyword arguments, that can be access as dict - you can pass n-number of kw args, and if you want to restrict that user must enter the sequence and arguments in order then don't use * and ** - (its pythonic way to provide generic solutions for big architectures...)
if you want to restrict your function with default values then you can check inside it
def info(object, spacing, collapse)
spacing = 10 if spacing is None else spacing
collapse = 1 if collapse is None else collapse