Reputation: 23
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
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