Python function to fill a list based on index number I wrote this function to fill a list with object based on the desired index they should have.

Here the func:

def fill(lst, index, add, fillvalue=None):                                        
    '''Fills a list with the add value based on desired index'''                       
    '''Let the value in place if present'''                                                            
    for n in range(index):                                                        
        try:                                                                      
            if lst[n]:                                                            
                pass                                                              
        except Exception:                                                         
            lst.append(fillvalue)                                                 
    try:                                                                          
        if lst[index]:                                                            
            pass                                                                  
        else:                                                                     
            lst[index]=add                                                        
    except Exception:                                                             
        if index==len(lst):                                                       
            #This if check probably not mandatory                                               
            lst.append(add)                                                       
    return lst


edit: here's an usage example that would for example happen in a for loop

&gt;&gt;&gt; my_list = [1, 7, 14]
&gt;&gt;&gt; fill(my_list, 5, 6)
[1, 7, 14, None, None, 6]
&gt;&gt;&gt; fill(my_list, 6, 12)
[1, 7, 14, None, None, 6, 12]
&gt;&gt;&gt; fill(my_list, 3, 25)
[1, 7, 14, 25, None, 6, 12]
&gt;&gt;&gt; fill(my_list, 4, 18)
[1, 7, 14, 25, 18, 6, 12]


Note:

&gt;&gt;&gt; my_list = [1, 7, 14]
&gt;&gt;&gt; fill(my_list, 1, 6)
#returns the list not modified, my_list[1] is already taken
[1, 7, 14]


It works good for my purpose (matrix generating). My matrixes are generated with many "for loops" passes, because the data I convert to is unordered. This is why the "None" elements are important in order to fill them out on a subsequent loop pass.

My questions are:


I'm wondering if I made everything as simple as possible? Or if there
were a lib, that would do the same job?
For now the matrixes aren't so long but I guess, if I go further
in my development, they will become big (1000+ lines). Should
I somehow better use itertools?
I also somehow thought of first using a dict {index: value} and
convert it to a list when filled up. Would it be better practice?


Edit: Now that I pasted the code in here I notice the arg name "add" is blued. My Vim-editor didn't told me that... Is it a name already taken by the python core?
if lst[n] is not sufficient to determine if the value at index n is None, 0 will also not pass the test. Use if lst[n] is not None or if lst[n] is None, depending on which one you want.
The whole first loop is just trying to determine if you need to extend the list, but you could just do that:

lst.extend([fill_value] * (index - len(lst) + 1))


If the list is already long enough this does nothing, as a list multiplied by an integer smaller than one is the empty list, and extending with an empty list does nothing. It even works when you use negative indices.
This also guarantees that the index exists, so you don't need the try..except anymore. But if you use try and except, always try to catch the narrowest exception possible. This way you make sure you don't catch an unexpected exception. In this case it would be an IndexError instead of the more generic Exception.
The convention in Python is for functions to only do one of two things: either do not mutate the inputs and return a new output or mutate (some of) the input and return None (potentially implicitly). Your function falls into the second category.


With these changes your function could be a lot shorter:

def fill(lst, index, value, fill_value=None):
    """Place the `value` at index `index`,
    but only if the value already there is `None`.
    Extends the list with `fill_value`, if necessary.
    """
    # No-op if list long enough or index negative
    lst.extend([fill_value] * (index - len(lst) + 1))
    if lst[index] is None:
        lst[index] = value

my_list = [1, 7, 14]
# my_list = [1, 7, 14]
fill(my_list, 5, 6)
# my_list = [1, 7, 14, None, None, 6]
fill(my_list, 6, 12)
# my_list = [1, 7, 14, None, None, 6, 12]
fill(my_list, 3, 25)
# my_list = [1, 7, 14, 25, None, 6, 12]
fill(my_list, 4, 18)
# my_list = [1, 7, 14, 25, 18, 6, 12]


Note that you will not directly see the result anymore in an interactive session, since the list is no longer returned. But that's a feature, not a bug, as mentioned above.

Of course, if you need to do this multiple times directly after each other, you might want to define a function that needs to extend only once:

def fill_multiple(lst, indices, values, fill_value=None):
    lst.extend([fill_value] * (max(indices) - len(lst) + 1))
    for index, value in zip(indices, values):
        if lst[index] is None:
            lst[index] = value


Then you can use e.g a dictionary:

my_list = [1, 7, 14]
updates = {5: 6, 6: 12, 3: 25, 4: 18}
fill_multiple(my_list, updates.keys(), updates.values())
# my_list = [1, 7, 14, 25, 18, 6, 12]


I kept the indices and values separate so you can also just pass lists or anything else, not just a mapping. Depending on your usecase you might want to pass the dictionary to the function instead.