62

I was having trouble implementing namedtuple._replace(), so I copied the code right off of the documentation:

Point = namedtuple('Point', 'x,y')

p = Point(x=11, y=22)

p._replace(x=33)

print p

and I got:

Point(x=11, y=22)

instead of:

Point(x=33, y=22)

as is shown in the doc.

I'm using Python 2.6 on Windows 7

What's going on?

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Peter Stewart
  • 2,857
  • 6
  • 28
  • 30
  • 8
    This works the same way as str.replace() does. Both strings and named tuples are immutable, so their replacement methods produce *new* values while leaving the old value unchanged. The solution to your problem is to save the new result to a variable. – Raymond Hettinger Jul 04 '14 at 01:50
  • Great question if for no other reason than that everybody wanting to "modify" a namedtuple is going to trip over this at some point. – mbarkhau Dec 05 '14 at 14:39

5 Answers5

123

Yes it does, it works exactly as documented.

._replace returns a new namedtuple, it does not modify the original, so you need to write this:

p = p._replace(x=33)

See here: somenamedtuple._replace(kwargs) for more information.

Lesmana
  • 25,663
  • 9
  • 82
  • 87
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • 5
    Good thing to note from the documentation: I was wary of using an underscore-prefixed method since that's typically done to indicate [the method is private](https://docs.python.org/3.8/tutorial/classes.html#private-variables). However in this case it's done to avoid conflicts with the `namedtuple`'s fields (which might include something called `replace`), so this is safe to use. There's an `._asdict()` method which works similarly. – Chris Vandevelde Jun 26 '20 at 21:19
21

A tuple is immutable. _replace() returns a new tuple with your modifications:

p = p._replace(x=33)
Max Shawabkeh
  • 37,799
  • 10
  • 82
  • 91
12

namedtuple._replace() returns a new tuple; the original is unchanged.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
6

It looks to me as if namedtuple is immutable, like its forebear, tuple.

>>> from collections import namedtuple
>>> Point = namedtuple('Point', 'x,y')
>>>
>>> p = Point(x=11, y=22)
>>>
>>> p._replace(x=33)
Point(x=33, y=22)
>>> print(p)
Point(x=11, y=22)
>>> p = p._replace(x=33)
>>> print(p)
Point(x=33, y=22)

NamedTuple._replace returns a new NamedTuple of the same type but with values changed.

hughdbrown
  • 47,733
  • 20
  • 85
  • 108
1

But YES, you are right: in the 'official' documentation, they forgot to assign the replaced tuple to a variable: https://docs.python.org/3/library/collections.html?highlight=collections#collections.namedtuple

p._replace(x=33)

instead of

p1 = p._replace(x33)
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
AVP
  • 11
  • 1
  • 1
    The official documentation shows that when you run `p._replace(x=33)` on the interactive Python prompt, it outputs the new tuple to screen. They didn't forget anything, this is perfectly fine interactive use. The next line shows a more complex bit of code where the return value is assigned to something. – joanis Oct 29 '21 at 13:20