48

How do I check if an object is an instance of a Named tuple?

Georgy
  • 6,348
  • 7
  • 46
  • 58
Sridhar Ratnakumar
  • 68,948
  • 61
  • 139
  • 172
  • Do you need to know absolutely, or is a heuristic okay? If the latter, you can check e.g. obj._asdict.__doc__ == 'Return a new OrderedDict which maps field names to their values' (possibly other factors too). – Matthew Flaschen Jan 30 '10 at 04:18
  • 1
    Absolutely, of course. But since I'd be using this "check" in an `assert` statement only (I am writing an extention to namedtuples .. which mixin asserts that it is used with a namedtuple as its sibling base class), heuristic check may also be fine. I think it is worth adding your `__doc__` check to Alex's code below. – Sridhar Ratnakumar Jan 30 '10 at 04:26
  • 4
    FWIW, this is filed as a "bug" (not sure I agree with that): http://bugs.python.org/issue7796 – mechanical_meat Jan 30 '10 at 04:32

7 Answers7

50

Calling the function collections.namedtuple gives you a new type that's a subclass of tuple (and no other classes) with a member named _fields that's a tuple whose items are all strings. So you could check for each and every one of these things:

def isnamedtupleinstance(x):
    t = type(x)
    b = t.__bases__
    if len(b) != 1 or b[0] != tuple: return False
    f = getattr(t, '_fields', None)
    if not isinstance(f, tuple): return False
    return all(type(n)==str for n in f)

it IS possible to get a false positive from this, but only if somebody's going out of their way to make a type that looks a lot like a named tuple but isn't one;-).

mac
  • 39,030
  • 21
  • 115
  • 128
Alex Martelli
  • 762,786
  • 156
  • 1,160
  • 1,345
  • Correct. I was also wondering why the generated type was not derived from a marker class `NamedTuple` whose definition would simply be `class NamedTuple(tuple): pass` .. just to make it easy for us to check if an object is a namedtuple or not. – Sridhar Ratnakumar Jan 30 '10 at 04:25
  • 2
    Why should the designers of namedtuple make it typecheckable, Sridhar? Typechecking is generally to be avoided in Python and in this case doesn't tell you anything at all useful—a namedtuple with `x` and `y` fields and one with `cost`, `price`, and `quantity` fields aren't going to be interchangeable. The only level to which they are interchangeable is that they are both tuples. Even in the use case of working with the classes generated by the namedtuple factory, they are just normal classes for good reason and can be used just like a similar hand-made class. – Mike Graham Jan 30 '10 at 21:20
  • @Mike: I am writing an extention to named tuples .. which mixin asserts that it is used with a named tuple as its sibling base class. So I only need it for asserting that the mixin is not misused with other types. – Sridhar Ratnakumar Jan 30 '10 at 21:32
  • 2
    @Srindhar: You don't really need to check that this is an instance of a class generated by namedtuple, you only need it to work with your mixin. A dumb user writing broken code can't be fixed by checks, and a smart user using your code will only be potentially hampered by them. (Also, since `assert`s aren't guaranteed to run, they are not the right tool for checking for something you need to check.) – Mike Graham Jan 30 '10 at 21:50
  • 1
    @Mike: The mixin does not *require* the check which is only needed for assertion. http://en.wikipedia.org/wiki/Assertion_(computing)#Assertions_in_design_by_contract – Sridhar Ratnakumar Jan 31 '10 at 01:56
  • 11
    @MikeGraham ancient post, but... one reason for typechecking a `namedtuple` is if you want to serialize/marshal an instance of it. Marshalling a `namedtuple` would be done much differently than a generic tuple, since you'd want to preserve the names somehow. – Russ Oct 12 '11 at 19:38
  • @Russ, I see what you mean, though I'm not certain I fully agree. The names of the field are part of the schema, not part of the data. You should know the names of the fields _a priori_ when dealing with namedtuples. If they're dynamic, you should probably be using a dict, not a namedtuple. (One might point out that nametuples have order. The simple, though wrongheaded, response to this is to point out collections.OrderedDict.) If you want to use an inferred schema rather than an explicit schema for your serialization, well, I think you're in for a world of hurt! Good luck! – Mike Graham Oct 13 '11 at 21:07
  • 6
    @MikeGraham For `json.dumps`. Or any other occasion where you want to do some operation differently. – jpmc26 Aug 11 '15 at 20:25
30

If you want to determine whether an object is an instance of a specific namedtuple, you can do this:

from collections import namedtuple

SomeThing = namedtuple('SomeThing', 'prop another_prop')
SomeOtherThing = namedtuple('SomeOtherThing', 'prop still_another_prop')

a = SomeThing(1, 2)

isinstance(a, SomeThing) # True
isinstance(a, SomeOtherThing) # False
MatrixManAtYrService
  • 5,337
  • 34
  • 46
  • 1
    Unless I'm missing something this appears to be the best and most concise answer. A namedtuple creates a new type and isinstance will check if something is that type. – Briford Wylie Feb 20 '18 at 17:08
  • 13
    This is different from the accepted answer -- this one checks for an instance of a *specific* namedtuple, while the accepted answer checks for an instance of *any* namedtuple. – minexew Sep 23 '18 at 20:05
4

If you need to check before calling namedtuple specific functions on it, then just call them and catch the exception instead. That's the preferred way to do it in python.

Tor Valamo
  • 30,859
  • 10
  • 70
  • 79
4

Improving on what Lutz posted:

def isinstance_namedtuple(x):                                                               
  return (isinstance(x, tuple) and                                                  
          isinstance(getattr(x, '__dict__', None), collections.Mapping) and         
          getattr(x, '_fields', None) is not None)                                  
jvdillon
  • 547
  • 5
  • 7
2

3.7+

def isinstance_namedtuple(obj) -> bool:
    return (
            isinstance(obj, tuple) and
            hasattr(obj, '_asdict') and
            hasattr(obj, '_fields')
    )

techkuz
  • 2,241
  • 3
  • 17
  • 45
1

I use

isinstance(x, tuple) and isinstance(x.__dict__, collections.abc.Mapping)

which to me appears to best reflect the dictionary aspect of the nature of named tuples. It appears robust against some conceivable future changes too and might also work with many third-party namedtuple-ish classes, if such things happen to exist.

Lutz Prechelt
  • 29,204
  • 6
  • 52
  • 79
0

IMO this might be the best solution for Python 3.6 and later.

You can set a custom __module__ when you instantiate your namedtuple, and check for it later

from collections import namedtuple

# module parameter added in python 3.6
namespace = namedtuple("namespace", "foo bar", module=__name__ + ".namespace")

then check for __module__

if getattr(x, "__module__", None) == "xxxx.namespace":

bformet
  • 10,157
  • 1
  • 20
  • 23