diff --git a/Objects/abstract.c b/Objects/abstract.c index 4891622a722..33991a81cb2 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1805,6 +1805,20 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) else if (PyType_Check(cls)) { retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls); } + else if (PyTuple_Check(cls)) { + /* Not a general sequence -- that opens up the road to + recursion and stack overflow. */ + int i, n; + + n = PyTuple_GET_SIZE(cls); + for (i = 0; i < n; i++) { + retval = PyObject_IsInstance( + inst, PyTuple_GET_ITEM(cls, i)); + if (retval != 0) + break; + } + return retval; + } else if (!PyInstance_Check(inst)) { if (__class__ == NULL) { __class__ = PyString_FromString("__class__"); @@ -1827,7 +1841,8 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) if (retval < 0) { PyErr_SetString(PyExc_TypeError, - "isinstance() arg 2 must be a class or type"); + "isinstance() arg 2 must be a class or type " + "or tuple of those"); } return retval; } diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 64afb1ba226..8390b7b80b9 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1641,10 +1641,12 @@ builtin_isinstance(PyObject *self, PyObject *args) } static char isinstance_doc[] = -"isinstance(object, class-or-type) -> Boolean\n\ +"isinstance(object, class-or-type-or-tuple) -> Boolean\n\ \n\ Return whether an object is an instance of a class or of a subclass thereof.\n\ -With a type as second argument, return whether that is the object's type."; +With a type as second argument, return whether that is the object's type.\n\ +The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for\n\ +isinstance(x, A) or isinstance(x, B) or ... (etc.)."; static PyObject *