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
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:
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.