Why was p[:] designed to work differently in these two situations?

后端 未结 6 1331
感动是毒
感动是毒 2021-02-01 12:42
p = [1,2,3]
print(p) # [1, 2, 3]

q=p[:]  # supposed to do a shallow copy
q[0]=11
print(q) #[11, 2, 3] 
print(p) #[1, 2, 3] 
# above confirms that q is not p, and is a d         


        
6条回答
  •  误落风尘
    2021-02-01 13:20

    Historical reasons, mainly.

    In early versions of Python, iterators and generators weren't really a thing. Most ways of working with sequences just returned lists: range(), for example, returned a fully-constructed list containing the numbers.

    So it made sense for slices, when used on the right-hand side of an expression, to return a list. a[i:j:s] returned a new list containing selected elements from a. And so a[:] on the right-hand side of an assignment would return a new list containing all the elements of a, that is, a shallow copy: this was perfectly consistent at the time.

    On the other hand, brackets on the left side of an expression always modified the original list: that was the precedent set by a[i] = d, and that precedent was followed by del a[i], and then by del a[i:j].

    Time passed, and copying values and instantiating new lists all over the place was seen as unnecessary and expensive. Nowadays, range() returns a generator that produces each number only as it's requested, and iterating over a slice could potentially work the same way—but the idiom of copy = original[:] is too well-entrenched as a historical artifact.

    In Numpy, by the way, this isn't the case: ref = original[:] will make a reference rather than a shallow copy, which is consistent with how del and assignment to arrays work.

    >>> a = np.array([1,2,3,4])
    >>> b = a[:]
    >>> a[1] = 7
    >>> b
    array([1, 7, 3, 4])
    

    Python 4, if it ever happens, may follow suit. It is, as you've observed, much more consistent with other behavior.

提交回复
热议问题