Kfir Cohen February 2016

Passing an optional argument in a function - python

I would like to create a function which can take either 1 or 2 arguments. Currently, I have a function which takes exactly 2 arguments through CMD:

def test(self,countName,optionalArg):
        if countName == "lowest":
           #something
        if optionalArg == "furthest:
           #something
        else:
           #something else

if __name__ == '__main__':
        countName = sys.argv[1]
        optionalArg = sys.argv[2]

        temp = len(sys.argv)
        for i in xrange(1,temp):

            sys.argv.pop()

I would then run:

python filename.py lowest furthest

Using this means that passing the second arg is a must. If I try to run my script just by passing one arg, it encounters an error (as expected). My question is, how do you create an optional argument, which could either be passed or not, depending on the situation?

For example:

python filename.py lowest

In this situation, I expect the program to perform the "#something else" script, as nothing was passed and it is different than "furthest".

Please do not write the code for me, I am here to learn :)

Answers


bruno desthuilliers February 2016

This is explained in the FineManual(tm): https://docs.python.org/2/tutorial/controlflow.html#more-on-defining-functions

Note that in Python, the expression defining the default value for an optional argument is eval'd ony once when the def statement is executed (which is at first import for a top-level function), which can lead to unexpected behaviours (cf "Least Astonishment" in Python: The Mutable Default Argument).

Also, the "default value" has to be an expression, not a statement, so you cannot do any error handling here. wrt/ your case with trying to use sys.argv[2] as a default value, it's wrong for at least two reasons:

  1. as you already noticed, it breaks if len(sys.argv) < 3
  2. it makes your function dependent on sys.argv, so you cannot reuse it in a different context

The right solution here is to handle all user input (sys.argv or whatever) in the "entry point" code (the __main__ section) - your function should know nothing about where the arguments values came from (sys.argv, an HTTP request, a text file or whatever).

So to make a long story short: use either a hardcoded value (if it makes sense) or a "sentinel" value (None is a good candidate) as default value for your optional argument, and do all the user inputs parsing in the __main__ section (or even better in a main() function called from the __main__ section so you don't pollute the module's namespace with irrelevant variables):

def func(arg, optarg=None):
    #code here


def main(*args):
    #parse args
    #call func with the right args

if __name__ == "__main__":
    import sys 
    main(*sys.argv 


Dharmik February 2016

You can write your function by providing default argument value to the argument you want to ignore like optionalArg=None(whatever you want) by doing this you can call the function with single argument.


k4ppa February 2016

A very, VERY ugly way is to use exceptions for check if the parameter is defined:

import sys

if __name__ == '__main__':
    arg = sys.argv[1]

    try:
        optionalArg = sys.argv[2]
    except IndexError:
        optionalArg = ""
    else:
        print "sure, it was defined."

I advise you not to use it, because you should never be in a situation where you don't know if a variable is defined or not, there are better ways to handle this, but in some cases (not yours) can be usefull, I add it only for this reason.


Device February 2016

Something like this? kinda code sorry :D

def function(value, opt = ""):
  print("Value: " + value)
  if not opt == "":
    print("Optional: " + opt)


Supahupe February 2016

You can pass a dictionary. Or a default value which is None if you not explicitly initialize it when calling the function.


Maxim Panfilov February 2016

Variant:

def somefunc(*args, **kwargs):
   if 'optional_arg' in kwargs:
       print kwargs['optional_arg']


Pouria Hadjibagheri February 2016

You can use *args to pass any number of arguments and receive them as a list, or use **kwargs to send keyword arguments and receive them as a dictionary.

Here is an example for *args:

def test(count_name, *args):

    if count_name == "lowest":    
        print('count_name received.')  

    if args and args[-1] == "furthest":    
        print('2nd arg received.')    

    else:    
        print('No second arg given.')    

    return None


if __name__ == '__main__':
    count_name = 'lowest'
    optional_arg = 'furthest'

    print('Test 1:')
    test(count_name, optional_arg)
    # Displays:
    # Test 1:
    # count_name received.
    # 2nd arg received.

    print('\n\nTest 2:')
    test(count_name)
    # Test 2:
    # count_name received.
    # No second arg given.

This is how you pass optional arguments, not by defining a default value for a variable, which initialises the variable in the memory.

Post Status

Asked in February 2016
Viewed 1,111 times
Voted 10
Answered 7 times

Search




Leave an answer