copy.replace

One spelling for what used to be namedtuple._replace, dataclasses.replace and datetime.replace. It simply calls type(obj).__replace__(obj, **changes) — types without that method get a TypeError.

copy functionPython 3.13+Live demo
Common call
moved = copy.replace(point, x=10)
Returns
a new object of the same type
Replaces
p._replace(...), dataclasses.replace(...), dt.replace(...)
Watch out
Not for list, dict, tuple: TypeError
copy.replace(objobj — An instance whose class defines __replace__: a namedtuple, a dataclass, date/datetime/time, SimpleNamespace … Positional only.type: object · required, /, **changes)
→ same type as obj

Demo

Live evaluation
Point(x, y) with x replaced. The original is unchanged — named tuples are immutable.
Try:
Inputs
xintx
yinty
nxintnew x
Code
import copy
from collections import namedtuple
Point = namedtuple('Point', 'x y')
p = Point(1, 2)
(p, copy.replace(p, x=5))
Result
(Point(x=1, y=2), Point(x=5, y=2))

Each call returns a NEW object and leaves the original as it was: (Point(x=1, y=2), Point(x=5, y=2)). For the named tuple an unknown field gives TypeError: Got unexpected field names: ['z'] — the message comes from namedtuple._replace. A dataclass reports unknown names differently, as an unexpected keyword argument of __init__.

Parameters

NameTypeRequiredDescription
objobjectyesAn instance whose class defines __replace__: a namedtuple, a dataclass, date/datetime/time, SimpleNamespace … Positional only.
**changesanynofield=value pairs. Unknown names raise TypeError (the exact message comes from the type).

Return value

same type as obj — A new object with the given fields replaced; obj is unchanged.

Common patterns

Update an immutable config
Frozen dataclasses stay frozen; you derive new versions.
import copy
test_config = copy.replace(prod_config, debug=True, db_url="sqlite://")
Support copy.replace in your own class
Define __replace__(self, /, **changes) and return a new instance.
class Money:
    def __init__(self, amount, currency):
        self.amount, self.currency = amount, currency
    def __replace__(self, /, **changes):
        return Money(changes.get("amount", self.amount), changes.get("currency", self.currency))
Code for 3.12 and earlier
Fall back to the type-specific spellings.
import dataclasses
p2 = p._replace(x=5)                      # namedtuple
item2 = dataclasses.replace(item, qty=3)   # dataclass

Examples

1. Named tuple
import copy from collections import namedtuple Point = namedtuple('Point', 'x y') copy.replace(Point(1, 2), y=9)
Returns
Point(x=1, y=9)
2. Same as _replace
import copy from collections import namedtuple Point = namedtuple('Point', 'x y') p = Point(1, 2) copy.replace(p, x=3) == p._replace(x=3)
Returns
True
3. datetime
import copy, datetime copy.replace(datetime.date(2026, 10, 4), year=2027)
Returns
datetime.date(2027, 10, 4)
4. SimpleNamespace
import copy from types import SimpleNamespace copy.replace(SimpleNamespace(a=1, b=2), a=5)
Returns
namespace(a=5, b=2)
5. Unchanged fields are shared, not copied
import copy from dataclasses import dataclass, field @dataclass class Cart: owner: str items: list = field(default_factory=list) c = Cart("ann") c2 = copy.replace(c, owner="bob") c2.items is c.items
Returns
True
6. Lists are not supported
import copy copy.replace([1, 2])
Returns
TypeError: replace() does not support list objects
7. Changes must be keywords
import copy from collections import namedtuple Point = namedtuple('Point', 'x y') copy.replace(Point(1, 2), 5)
Returns
TypeError: replace() takes 1 positional argument but 2 were given

Pitfalls

1. Assigning to a frozen dataclass
Frozen instances refuse attribute assignment. Make a modified copy instead.
item.qty = 3
from dataclasses import dataclass
@dataclass(frozen=True)
class Item:
    name: str
    qty: int = 1
item = Item("pen")
item.qty = 3
dataclasses.FrozenInstanceError: cannot assign to field 'qty'
copy.replace
import copy
from dataclasses import dataclass
@dataclass(frozen=True)
class Item:
    name: str
    qty: int = 1
item = Item("pen")
copy.replace(item, qty=3)
Item(name='pen', qty=3)
2. Using it on plain containers
copy.replace only works on types with __replace__. Tuples, lists and dicts have none — build the new value directly.
a dict
import copy
copy.replace({'a': 1}, a=2)
TypeError: replace() does not support dict objects
dict merge
{'a': 1} | {'a': 2}
{'a': 2}

When to use

Use it
  • Deriving modified versions of immutable records (namedtuple, frozen dataclass)
  • Generic code that should work for any type with __replace__
Reach for something else
  • Python 3.12 or older → _replace() / dataclasses.replace()
  • Mutable objects you may change in place → just assign the attribute
  • Plain dicts → {**d, "key": value} or d | {...}

Notes

CPython impl
copy.replace in Lib/copy.py: looks up obj.__class__.__replace__ and calls it with **changes; TypeError "replace() does not support <type> objects" when it is missing
Shallow
Unchanged fields are reused as they are — the new object shares them with the old one
Versions
copy.replace and the __replace__ protocol are new in 3.13

FAQ

It returns a new object of the same type with the given fields changed, by calling the type’s __replace__ method. Named tuples, dataclasses, date/datetime/time and SimpleNamespace support it out of the box.