# A \_\_replace\_item\_\_ protocol to complement \_\_replace\_\_

**URL:** <https://discuss.python.org/t/a-replace-item-protocol-to-complement-replace/109281>\
**Category:** Ideas\
**Created:** [September 30, 2026, 11:23am UTC](https://discuss.python.org/t/a-replace-item-protocol-to-complement-replace/109281 "2026-09-30T11:23:07Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![degilroy](https://avatars.discourse-cdn.com/v4/letter/d/e99b99/32.png) [@degilroy](https://discuss.python.org/u/degilroy)\
**Post date:** [September 30, 2026, 11:23am UTC](https://discuss.python.org/t/a-replace-item-protocol-to-complement-replace/109281/1 "2026-09-30T11:23:07Z")

</div>

`copy.replace()` was introduced to centralize operations that create a copy of an object while replacing selected fields. Could Python benefit from a similar `copy.replace_item()` function for sequences and mappings? This would provide a shared mechanism for updating lists, tuples, (frozen) dicts, and third-party immutable mappings without modifying the original.

For example:

```python
l = [1, 2, 3]
f = frozendict({"a": 1, "b": 2})  

l2 = copy.replace_item(l, 0, 100) # [100, 2, 3]
f2 = copy.replace_item(f, "a", 100) # frozendict({"a": 100, "b": 2})

```

Built-in types such as `list`, `tuple`, `dict` and `frozendict` could support this operation, while custom types could implement a corresponding ` __replace_item__ (self, key, value)` method that returns an updated object of the same type.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [September 30, 2026, 11:33am UTC](https://discuss.python.org/t/a-replace-item-protocol-to-complement-replace/109281/2 "2026-09-30T11:33:25Z")

</div>

Try the pipe operator instead:

```python
>>> f = frozendict({"a": 1, "b": 2})
>>> f | {"a": 100}
frozendict({'a': 100, 'b': 2})

```

---

<div class="post-metadata">

**Author:** ![degilroy](https://avatars.discourse-cdn.com/v4/letter/d/e99b99/32.png) [@degilroy](https://discuss.python.org/u/degilroy)\
**Post date:** [September 30, 2026, 12:04pm UTC](https://discuss.python.org/t/a-replace-item-protocol-to-complement-replace/109281/3 "2026-09-30T12:04:59Z")

</div>

> [@Rosuav](#):
>
> Try the pipe operator instead:
> 
> ```python
> >>> f = frozendict({"a": 1, "b": 2})
> >>> f | {"a": 100}
> frozendict({'a': 100, 'b': 2})
> 
> ```

Sure, that works for mappings but not for sequences. My proposal is to give all “replace at a given index” operations a shared entrypoint.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [September 30, 2026, 12:12pm UTC](https://discuss.python.org/t/a-replace-item-protocol-to-complement-replace/109281/4 "2026-09-30T12:12:07Z")

</div>

Fair, but I’m not really seeing that “replace at given index” is as universal a concept as you’re implying. Is it a problem that you have the pipe operator for dictionaries and the `_replace` method for namedtuples? Are there situations where you need to operate generically on immutable maps and sequences, not knowing whether it’s a key or an index?

---

<div class="post-metadata">

**Author:** ![degilroy](https://avatars.discourse-cdn.com/v4/letter/d/e99b99/32.png) [@degilroy](https://discuss.python.org/u/degilroy)\
**Post date:** [September 30, 2026, 1:44pm UTC](https://discuss.python.org/t/a-replace-item-protocol-to-complement-replace/109281/5 "2026-09-30T13:44:49Z")

</div>

Namedtuples are a great example. You can copy/replace from a field name but not from an index position even though namedtuples are built to be used both ways. A shared item-replacement protocol would let callers express “return a copy with this item changed” using the same index that they already use to read it.

Where I would find this most useful is as a generic entrypoint to modify immutable containers and to modify mutable containers without worrying about modifying the original. Right now to perform this action on a tuple at say, index 1, you have to do

`updated = t[:1] + (new_value,) + t[2:]`

And the general form `t[:i] + (v,) + t[i+1:]` would be wrong for i = -1, requiring extra checks.

Whereas with list you can do

```python
new_list = l.copy()
new_list[1] = new_value 

```

These are very different mechanisms for essentially the same operation. Unless I am missing something, a generic replace\_item function would provide a shared way to perform both of these as copy.replace\_item(seq, 1, new\_value). Code written using this funciton would keeps working if a list is later changed to a tuple. The objects themselves implementing a replace\_item protocol could help centralize the logic and catch edge cases.

As for a different use case, a recursive function applying an override along a path through mixed sequences and mappings could use this operation at every step.

For example:

```python
def override(node, path, value):
    if not path:
        return value
    key, *rest = path
    return copy.replace_item(node, key, override(node[key], rest, value))

overrides = {
    ("servers", 0): "localhost", # nested sequence index
    ("timeouts", "connect"): 10, # mapping key
}
for path, value in overrides.items():
    config = override(config, path, value)

```

The config can be parsed JSON or frozen containers; the function doesn’t need to know. This could also be cheaper too than say a deepcopy followed by mutation because only the containers within the path would be copied.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [September 30, 2026, 2:09pm UTC](https://discuss.python.org/t/a-replace-item-protocol-to-complement-replace/109281/6 "2026-09-30T14:09:14Z")

</div>

> [@degilroy](#):
>
> As for a different use case, a recursive function applying an override along a path through mixed sequences and mappings could use this operation at every step.

Every time I’ve heard of someone wanting to do deep mutations of immutable structure trees, it’s been solving the wrong problem. If this really IS the right thing for your use-case, go ahead, but it’s not something that I would want to see in the stdlib.
