Paulo Moura
Paulo Moura

Reputation: 23

Create new variables according length list

I've a follow list below. I'd like to transfer each item from list to different variables individually without to know its length

For example, consider the following list:

list1 = ['item1', 'item2', 'item3', 'item4']

The result expected is:

var1 = 'item1'
var2 = 'item2'
var3 = 'item3'
var4 = 'item4'

The real objective is avoid "out of range" error. Because I won't know the list length, and it can vary.

In another moment, for example, the list could be:

list1 = ['item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7']

In this case, the result expected would be:

var1 = 'item1'
var2 = 'item2'
var3 = 'item3'
var4 = 'item4'
var5 = 'item5'
var6 = 'item6'
var7 = 'item7'

Let me give you a real case. My script connect to a firewall and execute the following command:

nameif = net_connect.send_command("show nameif")

MM1MDA-VRJRAE-SM01/act# show nameif
Interface                Name                     Security
Management0/0            mgmt                      99
TenGigabitEthernet1/7    dmzncl                    75
Port-channel1.279        dmz3                      80
Port-channel1.291        dmz5                      50
Port-channel1.293        dmz4                      70
Port-channel1.295        dmzvdi                    60
Port-channel1.2021       dmzvdi1                   60

The output from this command can vary, depending how many interfaces there is on device. There are cases that it can have 3 interfaces, 4 interfaces or much more... So, I filter to a list:

nameif_entry = nameif.split()

After I remove other information that it doesn't matter:

del nameif_entry[0:4]

nameif_edited = nameif_entry[::3]

print (nameif_edited)

['mgmt', 'dmzncl', 'dmz3', 'dmz5', 'dmz4', 'dmzvdi', 'dmzvdi1']

After I run the following lines and send to many lists as below:

int_0 = net_connect.send_command("show route %s %s" %(nameif_edited[0],src_ip))

int_1 = net_connect.send_command("show route %s %s" %(nameif_edited[1],src_ip))

int_2 = net_connect.send_command("show route %s %s" %(nameif_edited[2],src_ip))

int_3 = net_connect.send_command("show route %s %s" %(nameif_edited[3],src_ip))

int_4 = net_connect.send_command("show route %s %s" %(nameif_edited[4],src_ip))

int_5 = net_connect.send_command("show route %s %s" %(nameif_edited[5],src_ip))

int_6 = net_connect.send_command("show route %s %s" %(nameif_edited[6],src_ip))

int_7 = net_connect.send_command("show route %s %s" %(nameif_edited[7],src_ip))

int_8 = net_connect.send_command("show route %s %s" %(nameif_edited[8],src_ip))

int_9 = net_connect.send_command("show route %s %s" %(nameif_edited[9],src_ip))

int_10 = net_connect.send_command("show route %s %s" %(nameif_edited[10], src_ip))

So it's here where the problem occurs. I receive a following error:

int_7 = net_connect.send_command("show route %s %s" %(nameif_edited[7], src_ip)) IndexError: list index out of range

Upvotes: 1

Views: 105

Answers (1)

Patrick Artner
Patrick Artner

Reputation: 51683

If you do not know how long the list is beforehand, how do you plan to put enough variables into your source code to hold them?

Generally speaking if you have a list

list1 = ['item1', 'item2', 'item3', 'item4']

and you want to do something with each element, you would do:

for elem in list1:
    print(elem)  # this prints each element on a new line

You do not need an index at all (80+% of the time). If you need the index as well, use enumerate():

for index,elem in enumerate(list1):
    print(index, elem)    

Output:

0 item1
1 item2
2 item3
3 item4

If you have an upper bound for your elements and "harmless" defaults you can cheat a bit:

a,b,c,d,e,f,g,h,i,k, *_ = list1 + [""]* 11  

In this case the letters will be filled with the elements of list1 and any "non-present" element will take one of the empty strings. *_ will consume the rest of the list.

This only works for small ranges though - f.e. if you get 3-8 strings, and want to have "" for any that is not provided. I might use that if I need several of those strings together at once and not after one another.

Example:

list1 = ['item1', 'item2', 'item3','item4']
a,b,c,d,e,f,g,h,i,k, *_ = list1 + [""]* 11    # extract into 11 vars

for elem in [a,b,c,d,e,f,g,h,i,k,_]:    # stuff all of them back into a list to print
    print(elem)                         # using less code - lists are cool

Output:

item1  # a
item2  # b
item3  # c
item4  # d
       # e
       # f
       # g
       # h
       # i
       # k
['', '', '', '', '']  # _

Doku:


Example for using the list decomposition (and a smarter way to do it - there almost always is a better way then resorting to the "cheaty" list decomposition with default values).

Task: calculate f(x) = k_0 + k_1*x +k_2*x**2 + ... for up to x**5 from a user inputted list, that has 1 to 6 elements:

def calc_f(my_coeff, x):
    # padd list with enough 0 (neutral in our case) to avoid indexerrors
    """Using decomposition"""
    padded_list =  my_coeff + [0] * 6
    # extract into vars
    a,b,c,d,e,f,*_ = padded_list
    return a + b*x +c*x**2 + d*x**3 + e*x**4 + f*x**5  

def calc_f_loop_1(my_coeff,x):
    """Using simple loop and manual sum"""
    s = 0
    idx = 0
    # basic approach without enumerate
    for elem in my_coeff:
        s += elem*x**idx
        idx+=1
    return s

def calc_f_loop_2(my_coeff,x):
    """Using better loop, still manual sum"""
    s = 0
    for idx, elem in enumerate(my_coeff):
        s += elem*x**idx
        idx+=1
    return s

all of those work ... but this is smarter (and more conceise):

calc_f_smarter = lambda l,x: sum( pl*x**idx for idx,pl in enumerate(l) )

Test:

list1 = [5, 3, 3, 4] # variable input - max. 6 numbers
for method, f in (
          ("calc_f",calc_f),
          ("calc_f_loop_1",calc_f_loop_1),
          ("calc_f_loop_2",calc_f_loop_2),
          ("calc_f_smarter",calc_f_smarter)):

    print(f"{method:<15}:", [f(list1,x) for x in range(-5,5)])

Outputs:

calc_f         : [-435, -215, -85, -21, 1, 5, 15, 55, 149, 321]
calc_f_loop_1  : [-435, -215, -85, -21, 1, 5, 15, 55, 149, 321]
calc_f_loop_2  : [-435, -215, -85, -21, 1, 5, 15, 55, 149, 321]
calc_f_smarter : [-435, -215, -85, -21, 1, 5, 15, 55, 149, 321]

Upvotes: 2

Related Questions