For Python, think of a namespace as being implemented by a 2-column table listing names and addresses. Also, note that the assignment operator = causes the right side to be evaluated, represented in memory if not already represented, and then causes the variable on the left side of the assignment to be bound in the symbol table to the address of the representation. Working through your code one line at a time:
listA = [2, 3, 4]
causes 2, 3, and 4 to be represented in memory at particular addresses. Then the brackets cause a list object to be represented in memory, with an address for the class, an int for its length, and an array of addresses for its elements. Finally, the name listA is placed in the namespace table and bound to the address for that list object.
listB = listA
A second entry listB is made in the namespace table and bound to the same address for the list.
listA = [4, 5, 6]
creates representations of three ints and a list in memory and changes the address referenced by listA in the namespace table, binding it to the new list.
listB[0] = 'new'
causes the string 'new' to be represented in memory and then changes the list object bound to listB so that that list's first element now refers to the address of the string.
If listA hadn't been reassigned to a new object, it would still point to the same list and you would see the same change in the list's first element whether using the listA or listB token.
listA, so it is no longer pointing at the same value aslistB