Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using namedtuple._replace with a variable as a fieldname

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
like image 560
Peter Stewart Avatar asked Jan 28 '10 20:01

Peter Stewart


People also ask

Can you modify a Namedtuple?

Since a named tuple is a tuple, and tuples are immutable, it is impossible to change the value of a field. In this case, we have to use another private method _replace() to replace values of the field. The _replace() method will return a new named tuple.

Can you subclass Namedtuple?

Python's namedtuple() is a factory function available in collections . It allows you to create tuple subclasses with named fields. You can access the values in a given named tuple using the dot notation and the field names, like in obj. attr .

What's the advantage of using Namedtuple instead of tuple?

Tuples are immutable, whether named or not. namedtuple only makes the access more convenient, by using names instead of indices. You can only use valid identifiers for namedtuple , it doesn't perform any hashing — it generates a new type instead.

Can you pickle a Namedtuple?

@Antimony: pickle handles namedtuple classes just fine; classes defined in a function local namespace not so much.


2 Answers

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!

like image 189
Jochen Ritzel Avatar answered Sep 22 '22 08:09

Jochen Ritzel


>>> 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
like image 33
SilentGhost Avatar answered Sep 23 '22 08:09

SilentGhost