You can use the zip() builtin function to iterate over two or more iterables simultaneously. In every iteration, you'll get a tuple with an item from each of the iterables. Here's an example:

>>> names = ['Joe', 'Mei', 'Rose', 'Ram']
>>> physics = [86, 91, 76, 80]
>>> maths = [77, 92, 81, 83]

>>> for n, p, m in zip(names, physics, maths):
...     print(f'{n:5}: {p},{m}')
... 
Joe  : 86,77
Mei  : 91,92
Rose : 76,81
Ram  : 80,83

Here are some examples using list comprehensions and generator expressions:

>>> p = [1, 3, 5]
>>> q = [3, 214, 53]

>>> [i + j for i, j in zip(p, q)]
[4, 217, 58]

# inner product
>>> sum(i * j for i, j in zip(p, q))
910

By default, zip() will silently stop when the shortest iterable is exhausted:

>>> fruits = ('apple', 'banana', 'fig', 'guava')
>>> qty = (100, 25, 42)

>>> for f, q in zip(fruits, qty):
...     print(f'{f:6}: {q}')
... 
apple : 100
banana: 25
fig   : 42

The strict keyword argument was added in the Python 3.10 version. When set to True, this will raise an exception if the iterables are not of the same length:

>>> for f, q in zip(fruits, qty, strict=True):
...     print(f'{f:6}: {q}')
... 
apple : 100
banana: 25
fig   : 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: zip() argument 2 is shorter than argument 1

info See also itertools.zip_longest() and stackoverflow: zipped Python generators with 2nd one being shorter.

Video demo:


info See also my 100 Page Python Intro ebook.