Python Namedtuple Defaults: Syntax and Behavior
python namedtuple defaults: Learn how to set default values on Python namedtuple fields using the defaults parameter, field_defaults, and alternative approaches.
When you create a namedtuple in Python, every field is required unless you provide defaults. The collections.namedtuple factory accepts a defaults parameter that assigns default values to the rightmost fields, so callers can omit those arguments. The behavior of python namedtuple defaults is straightforward once you understand the right-to-left alignment rule, how to inspect defaults at runtime, and the limitations compared with dataclasses.
The defaults Parameter
The defaults parameter was added to collections.namedtuple in Python 3.7. It accepts an iterable of values that are paired with the fields from right to left.
from collections import namedtuple Point = namedtuple("Point", ["x", "y"], defaults=[0, 0]) p = Point(5) print(p) # Point(x=5, y=0)
Here the defaults list contains two values, 0 and 0, which map to the fields y and x respectively. Because the mapping is right-to-left, y receives the first default and x receives the second. Calling Point(5) supplies a value for x only, and y falls back to its default.
The right-to-left pairing is the most important detail to remember. If you provide fewer defaults than fields, the leftmost fields remain required.
Person = namedtuple("Person", ["name", "age", "city"], defaults=["Unknown"]) p = Person("Alice", 30) print(p) # Person(name='Alice', age=30, city='Unknown')
In this example, only city has a default. The name and age fields must still be supplied by the caller. Attempting to construct Person("Alice") raises a TypeError because age is missing.
Inspecting Defaults with field_defaults
Every namedtuple class exposes a _fields attribute listing its field names. The defaults are stored separately in _field_defaults, a dictionary that maps field names to their default values.
print(Person._field_defaults) # {'city': 'Unknown'}
The _field_defaults dictionary contains only the fields that actually have defaults. Fields without defaults are absent from the dictionary. This is useful when you need to serialize a namedtuple instance or generate documentation dynamically.
Note that _field_defaults is a plain dictionary. Mutating it does not change the behavior of the class, because the defaults are captured at class creation time. If you need to change defaults after the class is defined, you must use a different mechanism.
Setting Defaults After Class Creation
If you are working with a namedtuple class that was defined without defaults, you can attach defaults by assigning to __new__.__defaults__. This works because namedtuple generates a __new__ method whose signature reflects the field order.
Vector = namedtuple("Vector", ["x", "y", "z"]) Vector.__new__.__defaults__ = (0, 0) v = Vector(1) print(v) # Vector(x=1, y=0, z=0)
The tuple assigned to __defaults__ is aligned with the rightmost parameters of __new__, which correspond to the rightmost fields. Assigning (0, 0) gives defaults to y and z, while x remains required.
This technique is rarely necessary in modern code because the defaults parameter covers the same need at definition time. It is still worth knowing when you encounter older codebases that predate Python 3.7 or when you are constructing a namedtuple dynamically from metadata.
Common Mistakes with Defaults
The most frequent mistake is assuming that defaults align left-to-right. Consider this definition:
Config = namedtuple("Config", ["host", "port", "debug"], defaults=["localhost", 8080])
A developer might expect host to default to "localhost" and port to 8080. In reality, debug receives "localhost" and port receives 8080. The host field remains required, and debug ends up with a string value instead of a boolean.
The second common mistake is mixing mutable default values. Like regular function defaults, namedtuple defaults are evaluated once at class creation time. If you use a mutable object such as a list or dictionary as a default, every instance shares the same object.
Item = namedtuple("Item", ["name", "tags"], defaults=[[]]) a = Item("apple") b = Item("banana") a.tags.append("fruit") print(b.tags) # ['fruit']
Both instances reference the same list, so mutating one affects the other. If you need a fresh container per instance, namedtuple is the wrong tool; a regular class or a dataclass with a field(default_factory=...) is more appropriate.
Namedtuple Defaults vs Dataclass Defaults
The dataclasses module, introduced in Python 3.7, offers a more flexible default mechanism. A dataclass supports both fixed default values and default_factory callables that produce a fresh object for each instance.
from dataclasses import dataclass, field @dataclass class Item: name: str tags: list = field(default_factory=list)
The default_factory solves the shared-mutable-default problem that namedtuple cannot address. Dataclasses also support per-field defaults without the right-to-left alignment rule, because each field declares its own default directly.
Namedtuple remains a reasonable choice when you need a lightweight, immutable, tuple-compatible record with positional access and hashing. Dataclasses provide more control over defaults, type annotations, and mutation behavior. The decision depends on whether tuple semantics matter to your code. If you rely on unpacking, indexing, or tuple equality, namedtuple preserves those behaviors. If you need per-field defaults with factory functions, dataclasses are the better fit.
Performance and Memory Considerations
Namedtuple instances are implemented as tuples, so they carry the same memory footprint as a tuple of the same length. Defaults do not change this: a default value is not stored per instance. When you omit a field, the default is filled in during construction, and the resulting tuple contains the resolved value.
This means defaults have no meaningful runtime cost beyond the normal construction path. The _field_defaults dictionary is a class-level attribute, not a per-instance attribute, so it does not add memory overhead to individual instances.
The tradeoff appears when you need mutable defaults or complex default logic. In those cases, the workaround code you would write around namedtuple defaults—such as a factory function that builds a fresh list—adds more maintenance burden than simply using a dataclass. For immutable records with simple scalar defaults, namedtuple is both concise and efficient.
When to Choose a Different Approach
If your fields are mostly required and only one or two trailing fields have simple defaults, python namedtuple defaults keeps the definition compact and readable. The right-to-left alignment is easy to manage when the defaulted fields are at the end of the field list.
If you have many fields with defaults scattered throughout the definition, or if you need mutable defaults, the alignment rule becomes a source of bugs. A dataclass expresses each field's default next to the field itself, which is easier to review and maintain. The same applies when you need to subclass the record and extend its fields with additional defaults; dataclass inheritance rules are more explicit than namedtuple's positional defaults.
For code that must remain compatible with Python 3.6 and earlier, the defaults parameter is unavailable. In that environment, the __new__.__defaults__ assignment is the standard workaround, or you can wrap the namedtuple in a factory function that fills in missing values before construction.