0

Is it possible to create NamedTuple inside NamedTuple like this?

from typing import NamedTuple, List, Optional
class BabyData(NamedTuple):
    name: str
    age: int
    body_measurement: Optional[NamedTuple('height': List, 'weight': List)] = None

Thanks!

eng2019
  • 953
  • 10
  • 26
  • Type annotations don't "create" anything. They are a formal documentation. – Klaus D. Jan 10 '21 at 08:31
  • Since you already have the code, you should be able to answer this yourself. Did it work? If yes, what's your question? If no, please expand it to a [mcve] including the error, and clarify why creating the type independently does not work for you. – MisterMiyagi Jan 10 '21 at 09:15

2 Answers2

4

You might want to use dataclasses for this use case instead:

from typing import Optional
from dataclasses import dataclass


@dataclass
class Measurements:

    height: list
    weight: list


@dataclass
class Baby:

    name: str
    age: int
    body: Optional[Measurements] = None

You can also have classes reference themselves:

from __future__ import annotations

from typing import Optional
from dataclasses import dataclass


@dataclass
class Person:

    name: str
    age: int
    parent: Optional[Person] = None
foxyblue
  • 2,859
  • 2
  • 21
  • 29
1

The example provided outputs an error at run time.

body_measurement: Optional[NamedTuple('height': List, 'weight': List)] = None
                                                  ^
SyntaxError: invalid syntax

To fix it you need

from typing import NamedTuple, List, Optional

class BabyData(NamedTuple):
    name: str
    age: int
    body_measurement: Optional[
        NamedTuple("BodyMeasurement", [("height", List), ("weight", List)])
    ] = None

if __name__ == "__main__":
    baby = BabyData(
        name="john", age=1, body_measurement={"height": [50, 51], "weight": [3, 3.5]}
    )
    print(baby)

# BabyData(name='john', age=1, body_measurement={'height': [50, 51], 'weight': [3, 3.5]})

In fact you try to mix two ways of defining NamedTuple. As per the documentation.

class Employee(NamedTuple):
    name: str
    id: int
# This is equivalent to:

Employee = collections.namedtuple('Employee', ['name', 'id'])

You should also consider using dataclasses, see the foxyblue's answer.

Romain
  • 19,910
  • 6
  • 56
  • 65