Can someone explain me these silly questions?

In Lab 6 of Week 3 Course 1 (Logistic Gradient Descent)

Q1. Why is the dot used after the number?

w_tmp = np.array([2.,3.])
b_tmp = 1.

Q2. What does i:4d do here?

if i% math.ceil(num_iters / 10) == 0:
            print(f"Iteration {i:4d}: Cost {J_history[-1]}   ")

Q3. In previous labs we used m = X.shape[0] but in the compute_gradient_logistic function m,n = X.shape why didnt we use [0] here this time? aren’t we defining the shape to both?

Q4. Here we have defined that dj_dw = np.zeros((n,)) but why its put in parentheses and why is comma put after n? what difference does it make? How its different than let say dj_dw = np.zeros(n)

I know these question may be silly and dumb but I really want to clarify this before moving further. Sorry once again!.

Q1. try running print(type(1.)) and print(type(1))

Q2. i:4d converts i into a string that follow a format specified by 4d. Check out A.5 in this post for more info.

Q3. This is called “unpacking”. m,n = X.shape unpacks the two numbers on the R.H.S. to the variables on the L.H.S. in order. Try a,b,c = (1,2,3)

Q4. The comma makes it a tuple. For the difference, try and print them to see the difference.

try print(type(1), type((1)), type((1,)))

run a, b = (3, 2); print(a)
run a, b, c = (3, 2,); print(a)
run a = (3, 2,); print(a)

run them and try to understand the difference. Try to make more examples for yourself, think about what you should get from those examples, run them, see if their outcomes meet with your expectation. If you want to follow up on this, please share with me what examples you have tried, what you have expected, and how they are not as expected