7

Can I reference a namedtuple fieldame using a variable?

from collections import namedtuple
import random 

Prize = namedtuple("Prize", ["left", "right"]) 

this_prize = Prize("FirstPrize", "SecondPrize")

if random.random() > .5:
    choice = "left"
else:
    choice = "right"
    
#retrieve the value of "left" or "right" depending on the choice
print "You won", getattr(this_prize,choice)
 
#replace the value of "left" or "right" depending on the choice
this_prize._replace(choice  = "Yay") #this doesn't work

print this_prize
bad_coder
  • 11,289
  • 20
  • 44
  • 72
Peter Stewart
  • 2,857
  • 6
  • 28
  • 30

2 Answers2

16

Tuples are immutable, and so are NamedTuples. They are not supposed to be changed!

this_prize._replace(choice = "Yay") calls _replace with the keyword argument "choice". It doesn't use choice as a variable and tries to replace a field by the name of choice.

this_prize._replace(**{choice : "Yay"} ) would use whatever choice is as the fieldname

_replace returns a new NamedTuple. You need to reasign it: this_prize = this_prize._replace(**{choice : "Yay"} )

Simply use a dict or write a normal class instead!

Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
  • I'm trying to optimize a data structure for speed. I was hoping I could use namedtuples, but I would have to change them in place. Perhaps I'll have to use something else. See: http://stackoverflow.com/questions/2127680/python-optimizing-or-at-least-getting-fresh-ideas-for-a-tree-generator – Peter Stewart Jan 28 '10 at 21:14
  • I had a case where I wouldn't alter most of the tuples, but only a few of them, so `_replace` is the way to go. This answer helped me a lot (more than the official doc). – JulienD Jan 02 '16 at 17:51
2
>>> choice = 'left'
>>> this_prize._replace(**{choice: 'Yay'})         # you need to assign this to this_prize if you want
Prize(left='Yay', right='SecondPrize')
>>> this_prize
Prize(left='FirstPrize', right='SecondPrize')         # doesn't modify this_prize in place
SilentGhost
  • 307,395
  • 66
  • 306
  • 293