How do I define a function with optional arguments?
Question:
I have a Python function which takes several arguments. Some of these arguments could be omitted in some scenarios.
def some_function (self, a, b, c, d = None, e = None, f = None, g = None, h = None):
#code
The arguments d
through h
are strings which each have different meanings. It is important that I can choose which optional parameters to pass in any combination. For example, (a, b, C, d, e)
, or (a, b, C, g, h)
, or (a, b, C, d, e, f
, or all of them (these are my choices).
It would be great if I could overload the function – but I read that Python does not support overloading. I tried to insert some of the required int arguments in the list – and got an argument mismatch error.
Right now I am sending empty strings in place of the first few missing arguments as placeholders. I would like to be able to call a function just using actual values.
Is there any way to do this? Could I pass a list instead of the argument list?
Right now the prototype using ctypes looks something like:
_fdll.some_function.argtypes = [c_void_p, c_char_p, c_int, c_char_p, c_char_p, c_char_p, c_char_p, c_char_p]
Answers:
Try calling it like: obj.some_function( '1', 2, '3', g="foo", h="bar" )
. After the required positional arguments, you can specify specific optional arguments by name.
Just use the *args
parameter, which allows you to pass as many arguments as you want after your a,b,c
. You would have to add some logic to map args
->c,d,e,f
but its a “way” of overloading.
def myfunc(a,b, *args, **kwargs):
for ar in args:
print ar
myfunc(a,b,c,d,e,f)
And it will print values of c,d,e,f
Similarly you could use the kwargs
argument and then you could name your parameters.
def myfunc(a,b, *args, **kwargs):
c = kwargs.get('c', None)
d = kwargs.get('d', None)
#etc
myfunc(a,b, c='nick', d='dog', ...)
And then kwargs
would have a dictionary of all the parameters that are key valued after a,b
It is very easy just do this
def foo(a = None):
print(a)
Instead of None you can type anything that should be in place if there was no argument for example if you will not write the value of the parameter like this foo()
then it will print None because no argument is given and if you will GIVE it an argument like foo("hello world")
then it will print hello world
… oh well I just forgot to tell y’all that these types of parameters i.e optional parameters, need to be behind all the other parameters. This means that, let’s take the previous function and add another parameter b
def foo(a = None, b):
print(a)
Now if you’ll execute your python file it is going to raise an exception saying that Non-default arguments follow default arguments
,
SyntaxError: non-default argument follows default argument
so you gotta put the optional or non-default argument after the arguments which are required
which means
def foo (a, b=None): ... #This one is right
def foo(b=None, a): ... #and this isn't
Check this:
from typing import Optional
def foo(a: str, b: Optional[str] = None) -> str or None:
pass
Required parameters first, optional parameters after. Optional parameters always with a =None
.
Easy and fast example:
def example_function(param1, param2, param3=None, param4=None):
pass
# Doesn't work, param2 missing
example_function("hello")
# Works
example_function("hello", "bye")
# Works. Both the same
example_function("hello", "bye", "hey")
example_function("hello", "bye", param3="hey")
# Works. Both the same
example_function("hello", "bye", "hey", "foo")
example_function("hello", "bye", param3="hey", param4="foo")
To get a better sense of what’s possible when passing parameters it’s really helpful to refer to the various options: positional-or-keyword (arg
or arg="default_value"
), positional-only (before /,
in the parameter list), keyword-only (after *,
in the parameter list), var-positional (typically *args
) or var-keyword (typically **kwargs
). See the Python documentation for an excellent summary; the various other answers to the question make use of most of these variations.
Since you always have parameters a, b, c in your example and you appear to call them in a positional manner, you could make this more explicit by adding /,
,
def some_function (self, a, b, c, /, d = None, e = None, f = None, g = None, h = None):
#code
To make Avión’s answer work for vector argument inputs;
def test(M,v=None):
try:
if (v==None).all() == False:
print('argument passed')
return M + v
except:
print('no argument passed')
return M
Where M is some matrix and v some vector. Both test(M) and test(M,v) produce errors when I attempted to use if statements without using ‘try/ except’ statements.
As mentioned by cem, upgrading to python 3.10 would allow the union (x|y) (or the Optional[…])functionality which might open some doors for alternative methods, but I’m using Anaconda spyder so I think I have to wait for a new release to use python 3.10.
I have a Python function which takes several arguments. Some of these arguments could be omitted in some scenarios.
def some_function (self, a, b, c, d = None, e = None, f = None, g = None, h = None):
#code
The arguments d
through h
are strings which each have different meanings. It is important that I can choose which optional parameters to pass in any combination. For example, (a, b, C, d, e)
, or (a, b, C, g, h)
, or (a, b, C, d, e, f
, or all of them (these are my choices).
It would be great if I could overload the function – but I read that Python does not support overloading. I tried to insert some of the required int arguments in the list – and got an argument mismatch error.
Right now I am sending empty strings in place of the first few missing arguments as placeholders. I would like to be able to call a function just using actual values.
Is there any way to do this? Could I pass a list instead of the argument list?
Right now the prototype using ctypes looks something like:
_fdll.some_function.argtypes = [c_void_p, c_char_p, c_int, c_char_p, c_char_p, c_char_p, c_char_p, c_char_p]
Try calling it like: obj.some_function( '1', 2, '3', g="foo", h="bar" )
. After the required positional arguments, you can specify specific optional arguments by name.
Just use the *args
parameter, which allows you to pass as many arguments as you want after your a,b,c
. You would have to add some logic to map args
->c,d,e,f
but its a “way” of overloading.
def myfunc(a,b, *args, **kwargs):
for ar in args:
print ar
myfunc(a,b,c,d,e,f)
And it will print values of c,d,e,f
Similarly you could use the kwargs
argument and then you could name your parameters.
def myfunc(a,b, *args, **kwargs):
c = kwargs.get('c', None)
d = kwargs.get('d', None)
#etc
myfunc(a,b, c='nick', d='dog', ...)
And then kwargs
would have a dictionary of all the parameters that are key valued after a,b
It is very easy just do this
def foo(a = None):
print(a)
Instead of None you can type anything that should be in place if there was no argument for example if you will not write the value of the parameter like this foo()
then it will print None because no argument is given and if you will GIVE it an argument like foo("hello world")
then it will print hello world
… oh well I just forgot to tell y’all that these types of parameters i.e optional parameters, need to be behind all the other parameters. This means that, let’s take the previous function and add another parameter b
def foo(a = None, b):
print(a)
Now if you’ll execute your python file it is going to raise an exception saying that Non-default arguments follow default arguments
,
SyntaxError: non-default argument follows default argument
so you gotta put the optional or non-default argument after the arguments which are required
which means
def foo (a, b=None): ... #This one is right
def foo(b=None, a): ... #and this isn't
Check this:
from typing import Optional
def foo(a: str, b: Optional[str] = None) -> str or None:
pass
Required parameters first, optional parameters after. Optional parameters always with a =None
.
Easy and fast example:
def example_function(param1, param2, param3=None, param4=None):
pass
# Doesn't work, param2 missing
example_function("hello")
# Works
example_function("hello", "bye")
# Works. Both the same
example_function("hello", "bye", "hey")
example_function("hello", "bye", param3="hey")
# Works. Both the same
example_function("hello", "bye", "hey", "foo")
example_function("hello", "bye", param3="hey", param4="foo")
To get a better sense of what’s possible when passing parameters it’s really helpful to refer to the various options: positional-or-keyword (arg
or arg="default_value"
), positional-only (before /,
in the parameter list), keyword-only (after *,
in the parameter list), var-positional (typically *args
) or var-keyword (typically **kwargs
). See the Python documentation for an excellent summary; the various other answers to the question make use of most of these variations.
Since you always have parameters a, b, c in your example and you appear to call them in a positional manner, you could make this more explicit by adding /,
,
def some_function (self, a, b, c, /, d = None, e = None, f = None, g = None, h = None):
#code
To make Avión’s answer work for vector argument inputs;
def test(M,v=None):
try:
if (v==None).all() == False:
print('argument passed')
return M + v
except:
print('no argument passed')
return M
Where M is some matrix and v some vector. Both test(M) and test(M,v) produce errors when I attempted to use if statements without using ‘try/ except’ statements.
As mentioned by cem, upgrading to python 3.10 would allow the union (x|y) (or the Optional[…])functionality which might open some doors for alternative methods, but I’m using Anaconda spyder so I think I have to wait for a new release to use python 3.10.