Like @morhc mentiond, you're not changing your array x because x.reshape returns a new array instead of modifying the existing one. Some numpy methods allow an inplace parameter, but reshape is not one of them.
Mutability is a somewhat related, but more general concept.
A mutable object is one that can be changed after it has been created and stored in memory. Immutable objects, once created, cannot be changed; if you want to modify an immutable object, you have to create a new one. For example, lists in python are mutable: You can add or remove elements, and the list remains stored at the same place in memory. A string however is immutable: If you take the string "foobar" and call its replace method to replace some characters, then the modified string that you get as a result is a new object stored in a different place in memory.
You can use the id built-in function in python to check at what memory address an object is stored. So, to demonstrate:
test_list = []
id(test_list)
>>> 1696610990848 # memory address of the empty list object we just created
test_list.append(1)
id(test_list)
>>> 1696610990848 # the list with one item added to it is still the same object
test_str = "foobar"
id(test_str)
>>> 1696611256816 # memory address of the string object we just created
test_str = test_str.replace("b", "x")
id(test_str)
>>> 1696611251312 # the replace method returned a new object
In fact, numpy arrays are in principle mutable:
test_arr = np.zeros(4)
id(test_arr)
>>> 1696611361200
test_arr[0] = 1
id(test_arr)
>>> 1696611361200 # after changing an entry in the array, it's still the same object
I suppose that reshaping an object in-place would be too difficult, so instead a new one is created.
Note also that making an assignment like test_arr2 = test_arr does not make a copy; instead, test_arr2 points to the same object in memory. If you truly want to make a new copy, you should use test_arr.copy().