The list approach is:
In [122]: alist=[1,3,5]
In [123]: for i,j in zip([1,3],[2,4]):
...: alist[i:i] = [j]
...:
In [124]: alist
Out[124]: [1, 2, 3, 4, 5]
np.insert is a complex function taking different approaches depending on the indices input. But in a case like this is uses a boolean mask approach:
In [126]: arr = np.array([1,3,5])
In [127]: res = np.zeros(5, int) # 5 is len(arr)+len([2,4])
In [128]: mask = res.astype(bool)
In [129]: mask[[1,3]] = True
In [130]: mask
Out[130]: array([False, True, False, True, False])
In [131]: res[mask] = [2,4]
In [132]: res[~mask] = arr
In [133]: res
Out[133]: array([1, 2, 3, 4, 5])
mask defines where the new values are supposed to go, and ~mask where the originals go.
insert assumes the indices are given relative to the source array, not the target. To do this same thing, it has to be given [1,2], in other words after arr[1] and arr[2]. insert would adjust [1,2] to [1,3] to use the above masking approach. @Divakar's answer takes your [1,3] and converts it to the [1,2] that insert expects. He in effect is compensating for the offset that insert normally adds.
If we used [1,2] (indices relative to the source list), the list iteration that I used above is wrong. It doesn't account for the fact that the list grows after inserting the 2:
In [134]: alist=[1,3,5]
In [135]: for i,j in zip([1,2],[2,4]):
...: alist[i:i] = [j]
In [136]: alist
Out[136]: [1, 2, 4, 3, 5]
To compensate for that, a common trick is to insert in reverse order:
In [137]: alist=[1,3,5]
In [138]: for i,j in zip([1,2][::-1],[2,4][::-1]):
...: alist[i:i] = [j]
In [139]: alist
Out[139]: [1, 2, 3, 4, 5]
insertput the2afteroriginal[1], and4afteroriginal[3]. You in contrast want them to be at theresult[1]andresult[3]slots.indicesalready factors in the growth.