nums = []
vals = nums
vals.append(1)
the result shows nums and vals are of same length but
nums = []
vals = nums[:]
vals.append(1)
this shows vals is longer than num
nums = []
vals = nums
vals.append(1)
the result shows nums and vals are of same length but
nums = []
vals = nums[:]
vals.append(1)
this shows vals is longer than num
 
    
    With:
nums = []
vals = nums
vals.append(1)
You have 2 references pointing the same list in memory.
With:
nums = []
vals = nums[:]
vals.append(1)
You have 2 distinct lists in memory: the vals is a copy of the nums list (which is empty).
Writing vals = nums[:] is the same as writing vals = list(nums): you create a new list (with the same items inside).
 
    
    nums = []
vals = nums[:]
vals.append(1)
In second case you are creating new list vals from nums. Both the list will point out to separate memory location and hence changes made on vals list will not made any impact on nums list.
nums = []
vals = nums
vals.append(1)
Whereas in first case you are copying list nums to vals and both vals and nums are pointing out to same heap storage location. So changes made to vals will automatically affects to nums.
For more you can read the article- https://docs.python.org/3/library/copy.html
 
    
    Using [:] you creating a new list containing the same values as nums, but that new list is not the same object as nums. That's why in your second example vales is longer than nums: it is not the same object.
initial = []
a = initial
b = initial[:]
assert a is initial
assert b is not initial
More precisely, as stated in the documentation, indexing with [:] is equivalent to copy the list:
initial = []
# these are equivalent
a = initial[:]
b = initial.copy()
assert a is not initial
assert b is not initial
