21

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?

2 Answers 2

42

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
Sign up to request clarification or add additional context in comments.

2 Comments

Silly me! Thanks for the explanation and the accompanied code. So, is that nested namedtuple considered a good practice? Do you know of any alternatives?
It's perfectly fine data structure with another data structure nested inside it. If it's correct for problem you're solving, why not? You just have to keep in mind that it's a data structure, not a class. For complex objects you're usually better with creating a class with appropriate methods.
1

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.

4 Comments

I'd like to see how it is done in reverse, ie nested namedtuples to dictionaries
there exists already a function: nnt._asdict()
Yes, but it does not work recursively in every case.
I added the inverse function, let me know if this does not work in your cases.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.