[Python-ideas] List assignment - extended slicing inconsistency

Alexander Heger python at 2sn.net
Thu Feb 22 17:18:36 EST 2018


​What little documentation I could find, providing a stride on the
assignment target for a list is supposed to trigger 'advanced slicing'
causing element-wise replacement - and hence requiring that the source
iterable has the appropriate number of elements.

>>> a = [0,1,2,3]
>>> a[::2] = [4,5]
>>> a
[4, 1, 5, 3]
>>> a[::2] = [4,5,6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: attempt to assign sequence of size 3 to extended slice of size 2

This is in contrast to regular slicing (*without* a stride), allowing to
replace a *range* by another sequence of arbitrary length.

>>> a = [0,1,2,3]
>>> a[:3] = [4]
>>> a
[4, 3]

Issue
=====
When, however, a stride of `1` is specified, advanced slicing is not
triggered.

>>> a = [0,1,2,3]
>>> a[:3:1] = [4]
>>> a
[4, 3]

If advanced slicing had been triggered, there should have been a ValueError
instead.

Expected behaviour:

>>> a = [0,1,2,3]
>>> a[:3:1] = [4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: attempt to assign sequence of size 1 to extended slice of size 3

I think that is an inconsistency in the language that should be fixed.

Why do we need this?
====================
One may want this as extra check as well so that list does not change
size.  Depending on implementation, it may come with performance benefits
as well.

One could, though, argue that you still get the same result if you do all
correctly

>>> a = [0,1,2,3]
>>> a[:3:1] = [4,5,6]
>>> a
[4, 5, 6, 3]

But I disagree that there should be no error when it is wrong.
*Strides that are not None should always trigger advanced slicing.*

Other Data Types
================
This change should also be applied to bytearray, etc., though see below.

Concerns
========
It may break some code that uses advanced slicing and expects regular
slicing to occur?  These cases should be rare, and the error message should
be clear enough to allow fixes? I assume these cases should be
exceptionally rare.

If the implementation relies on `slice.indices(len(seq))[2] == 1` to
determine about advance slicing or not, that would require some
refactoring.  If it is only `slice.stride in (1, None)` then this could
easily replaced by checking against None.

Will there be issues with syntax consistency with other data types, in
particular outside the core library?
- I always found that the dynamic behaviour of lists w/r non-advanced
slicing to be somewhat peculiar in the first place, though, undeniably, it
can be immensely useful.
- Most external data types with fixed memory such as numpy do not have this
dynamic flexibility, and the behavior of regular slicing on assignment is
the same as regular slicing.  The proposed change would increase
consistency with these other data types.

More surprises
==============
>>> import array
>>> a[1::2] = a[3:3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: attempt to assign sequence of size 0 to extended slice of size 2

whereas

>>> a = [1,2,3,4,5]
>>> a[1::2] = a[3:3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: attempt to assign sequence of size 0 to extended slice of size 2

>>> a = bytearray(b'12345')
>>> a[1::2] = a[3:3]
>>> a
bytearray(b'135')

but numpy

>>> import numpy as np
>>> a = np.array([1,2,3,4,5])
>>> a[1::2] = a[3:3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not broadcast input array from shape (0) into shape (2)

and

>>> import numpy as np
>>> a[1:2] = a[3:3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not broadcast input array from shape (0) into shape (1)

The latter two as expected.  memoryview behaves the same.

Issue 2
=======
Whereas NumPy is know to behave differently as a data type with fixed
memory layout, and is not part of the standard library anyway, the
difference in behaviour between lists and arrays I find disconcerting.
This should be resolved to a consistent behaviour.

Proposal 2
==========
Arrays and bytearrays should should adopt the same advanced slicing
behaviour I suggest for lists.

Concerns 2
==========
This has the potential for a lot more side effects in existing code, but as
before in most cases error message should be triggered.

Summary
=======
I find it it not acceptable as a good language design that there is a large
range of behaviour  on slicing in assignment target for the different
native (and standard library) data type of seemingly similar kind, and that
users have to figure out for each data type by testing - or at the very
least remember if documented - how it behaves on slicing in assignment
targets.  There should be a consistent behaviour at the very least, ideally
even one with a clear user interface as suggested for lists.

-Alexander
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180223/76774239/attachment.html>


More information about the Python-ideas mailing list