python / python/cpython

Assigning to a slice of a list with a step of -1 should permit assigning a different number of items

Open
#138,357 9 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

interpreter-core type-feature
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

Feature or enhancement

Proposal:

(Note: this behavior is so old, I'd be surprised if genuinely nobody had ever suggested it before. So I give it a 30% chance it's actually a bad idea for some reason I've missed. Nevertheless--let's give it a go.)

In Python, you can assign to a slice of a list. The right hand side must be an iterable, and the values it yields replace the corresponding elements of the list:

>>> l = [1, 2, 3, 4, 5]
>>> l[1:4] = 'abc'
>>> l
[1, 'a', 'b', 'c', 5]

For a non-extended slice, where step is either None or 1, the number of items yielded by the iterable and the length of the slice don't need to agree. The list object will happily replace the sliced elements with all the elements of the iterable:

>>> l = [1, 2, 3, 4, 5]
>>> l[1:4] = 'abcdef'
>>> l
[1, 'a', 'b', 'c', 'd', 'e', 'f', 5]

You can also assign to an extended slice, defined as any slice with a step != 1:

>>> l = [1, 2, 3, 4, 5]
>>> l[0:5:2] = 'abc'
>>> l
['a', 2, 'b', 4, 'c']

But when step is != 1, the number of elements yielded by the iterable and the length of the slice must agree:

>>> l = [1, 2, 3, 4, 5]
>>> l[0:5:2] = 'abcdef'
ValueError: attempt to assign sequence of size 6 to extended slice of size 3

If you assign to a slice with a negative step, it actually assigns the values in reverse:

>>> l = [1, 2, 3, 4, 5]
>>> l[3:0:-1] = 'abc'
>>> l
[1, 'c', 'b', 'a', 5]

But a step of -1 means this is an "extended" slice, so the list object requires the size of the iterable and the length of the slice to agree:

>>> l = [1, 2, 3, 4, 5]
>>> l[3:0:-1] = 'abcdef'
ValueError: attempt to assign sequence of size 6 to extended slice of size 3

I think this is a flaw. I claim that

>>> l = [1, 2, 3, 4, 5]
>>> l[1:4] = 'abcdef'

and

>>> l = [1, 2, 3, 4, 5]
>>> l[3:0:-1] = reversed('abcdef')

should produce identical results; they should both set l to [1, 'a', 'b', 'c', 'd', 'e', 'f', 5].

In summary: Python should permit assigning an iterable to a slice where the iterable and slice are of different magnitudes if step is 1 or -1.

Has this already been discussed elsewhere?

This is a minor feature, which does not need previous discussion elsewhere

Links to previous discussion of this feature:

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the positive- and negative-step slice-assignment examples in a Python interpreter and compare their current behavior. Investigate the list slice-assignment implementation and relevant tests, then verify that step -1 permits differing iterable and slice lengths while preserving the proposed result and existing extended-slice rules.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.