0
from collections import namedtuple

foo_a = namedtuple("foo_a", ["a1", "a2", "a3"])
foo_b = namedtuple("foo_b", ["b1", "b2", "b3"])

a = foo_a(1, 2, 3)
b = foo_b(4, 5, 6)

a + b        # -> (1, 2, 3, 4, 5, 6)
type(a + b)  # -> tuple

It seems that the add method of namedtuples will return a tuple, but I cannot find the documentation for this behavior. And this behavior seems strange to me.

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
sbwcwso
  • 15
  • 5
  • I’d think that property comes from being an iterable. You can add all iterables like list, set, string in a similar manner. What do you find confusing about this behavior? – Abhijit Sarkar Aug 08 '23 at 23:01
  • @AbhijitSarkar, but a list add a list will return a list, the same for string. And `set` doesn't support the `+` operation – sbwcwso Aug 08 '23 at 23:11
  • 1
    As documentation states, `namedtuple` returns a tuple subclass. This means it has to provide the functionality of a tuple. – Michael Butscher Aug 08 '23 at 23:19
  • @MichaelButscher Oh, I understand, thank your very much. It is very smooth to use subclass to understand my problem. – sbwcwso Aug 08 '23 at 23:23
  • `class A(list): pass ; A() + A()` will return a `list` not an instance of `A` unless you override the `__add__` method on it, the default behaviour is to use the behaviour of the parent class. In case of `namedtuple` the parent class is `tuple` and `tuple` has no idea about `foo_a` or `foo_b` or their attributes, it basically treats them as plain tuples. – Ashwini Chaudhary Aug 08 '23 at 23:25
  • @Abhijit Beside the point, but "iterable" is the wrong word. For example, generators are iterable but don't support addition. I think the right term would be "built-in sequences except `range`", which is a mouthful :p – wjandrea Aug 08 '23 at 23:26

1 Answers1

3

Python's namedtuples are carefully built so that they are subclasses of tuples - this means that they will behave just as tuples will in every possible opportunity. The most used of course, is the capability of getting its values by a numeric index rather than by named attribute: this is what makes them capable of being "drop in" replacements in places where formerly a tuple was needed just to tie unrelated values together.

The use of "+" to concatenate tuples, or a tuple to other iterable is well defined. On the other hand, concatenating the named attributes of a namedtuple not only does not make sense, as it would cause a name clash if the resulting entity would be a "double-length named tuple" with each field repeated twice.

Changing the behavior to add each field recursively, besides not necessarily making sense for most named tuples, would also break compatibility of named-tuples to tuples. As would simply raising a TypeError when trying to add a namedtuple to any other sequence: as a namedtuple is a tuple, the expected resulting object is also a tuple.

I don't think there is actually any surprise in this behavior when one takes these points into consideration.

jsbueno
  • 99,910
  • 10
  • 151
  • 209