Reputation: 1711
Is it possible to have a namedtuple
inside another namedtuple
?
For example:
from collections import namedtuple
Position = namedtuple('Position', 'x y')
Token = namedtuple('Token', ['key', 'value', Position])
which gives a "ValueError: Type names and field names must be valid identifiers"
Also, I am curious if there is a more Pythonic approach to build such a nested container?
Upvotes: 21
Views: 14469
Reputation: 4537
Here a general function to transform a nested dictionary to a nested namedtuple
from collections import namedtuple
def dict2namedtuple(name, d):
values, keys = [], []
for k in d:
keys.append(k)
v = d[k]
if isinstance(v, dict):
values.append(dict2namedtuple(k, v))
else:
values.append(v)
T = namedtuple(name, keys)
return T(*values)
def namedtuple2dict(nt):
d = {}
for k in nt._fields:
v = getattr(nt, k)
try:
d[k] = namedtuple2dict(v)
except AttributeError:
d[k] = v
return d
test_dict = {'a': 1, 'b': 2, 'c': {'d': 3, 'e': 4}}
nt = dict2namedtuple('test', d=test_dict)
dc = namedtuple2dict(nt)
assert dc == test_dict
print('namedtuple', nt)
print('dict', dc)
EDIT:
I added a function for the inverse problem namedtuple2dict
. In my experience namedtuple._asidct()
works fine, but @Chev_603 mentioned some problems.
Upvotes: 1
Reputation: 23233
You are mixing up two concepts - structure of namedtuple
, and values assigned to them. Structure requires list of unique names. Values may be anything, including another namedtuple
.
from collections import namedtuple
Position = namedtuple('Position', 'x y')
Token = namedtuple('Token', ['key', 'value', 'position'])
t = Token('ABC', 'DEF', Position(1, 2))
assert t.position.x == 1
Upvotes: 42