Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the length of a parameter array as the default value of another parameter of the same function

This is my first time asking a question in SO, so if I'm somehow not doing it properly don't hesitate to edit it or ask me to modify it.

I think my question is kind of general, so I'm quite surprised for not having found any previous one related to this topic. If I missed it and this question is duplicated, I'll be very grateful if you could provide a link to where it was already answered.

Imagine I need to implement a function with (at least) three parameters: an array a, a start index and an end index. If not provided, the start parameter should refer to the first position of the array (start = 0), while the end parameter should be set to the last position (end = len(a) - 1). Obviously, the definition:

def function(a, start = 0, end = (len(a) - 1)):
    #do_something
    pass

does not work, leading to an exception (NameError: name 'a' is not defined). There are some workarounds, such as using end = -1 or end = None, and conditionally assign it to len(a) - 1 if needed inside the body of the function:

def function(a, start = 0, end = -1):
    end = end if end != -1 else (len(a) -1)
    #do_something

but I have the feeling that there should be a more "pythonic" way of dealing with such situations, not only with the length of an array but with any parameter whose default value is a function of another (non optional) parameter. How would you deal with a situation like that? Is the conditional assignment the best option?

Thanks!

like image 562
Francisco Rodríguez Algarra Avatar asked Jan 09 '23 00:01

Francisco Rodríguez Algarra


1 Answers

Using a sentinel value such as None is typical:

def func(a, start=0, end=None):
    if end is None:
        end = # whatever
    # do stuff

However, for your actual use case, there's already a builtin way to do this that fits in with the way Python does start/stop/step - which makes your function provide a consistent interface as to the way builtins/other libraries work:

def func(a, *args):
    slc = slice(*args)
    for el in a[slc]:
        print(el)

See https://docs.python.org/2/library/functions.html#slice


If you only want to support start/end in that order, then (note that None effectively means until len(a) when used as end or 0 when used as start):

def func(a, start=0, end=None):
    return a[start:end]
like image 157
Jon Clements Avatar answered Jan 16 '23 21:01

Jon Clements