See documentation of :c:type:`PyVarObject` above.
+.. c:function:: int Py_Is(const PyObject *x, const PyObject *y)
+
+ Test if the *x* object is the *y* object, the same as ``x is y`` in Python.
+
+ .. versionadded:: 3.10
+
+
+.. c:function:: int Py_IsNone(const PyObject *x)
+
+ Test if an object is the ``None`` singleton,
+ the same as ``x is None`` in Python.
+
+ .. versionadded:: 3.10
+
+
+.. c:function:: int Py_IsTrue(const PyObject *x)
+
+ Test if an object is the ``True`` singleton,
+ the same as ``x is True`` in Python.
+
+ .. versionadded:: 3.10
+
+
+.. c:function:: int Py_IsFalse(const PyObject *x)
+
+ Test if an object is the ``False`` singleton,
+ the same as ``x is False`` in Python.
+
+ .. versionadded:: 3.10
+
+
.. c:function:: PyTypeObject* Py_TYPE(const PyObject *o)
Get the type of the Python object *o*.
Py_IncRef
Py_Initialize
Py_InitializeEx
+Py_Is
+Py_IsFalse
Py_IsInitialized
+Py_IsNone
+Py_IsTrue
Py_LeaveRecursiveCall
Py_Main
Py_MakePendingCalls
build (``Py_TRACE_REFS`` macro).
(Contributed by Victor Stinner in :issue:`43688`.)
+* Add the :c:func:`Py_Is(x, y) <Py_Is>` function to test if the *x* object is
+ the *y* object, the same as ``x is y`` in Python. Add also the
+ :c:func:`Py_IsNone`, :c:func:`Py_IsTrue`, :c:func:`Py_IsFalse` functions to
+ test if an object is, respectively, the ``None`` singleton, the ``True``
+ singleton or the ``False`` singleton.
+ (Contributed by Victor Stinner in :issue:`43753`.)
+
Porting to Python 3.10
----------------------
#define Py_False ((PyObject *) &_Py_FalseStruct)
#define Py_True ((PyObject *) &_Py_TrueStruct)
+// Test if an object is the True singleton, the same as "x is True" in Python.
+PyAPI_FUNC(int) Py_IsTrue(PyObject *x);
+#define Py_IsTrue(x) Py_Is((x), Py_True)
+
+// Test if an object is the False singleton, the same as "x is False" in Python.
+PyAPI_FUNC(int) Py_IsFalse(PyObject *x);
+#define Py_IsFalse(x) Py_Is((x), Py_False)
+
/* Macros for returning Py_True or Py_False, respectively */
#define Py_RETURN_TRUE return Py_NewRef(Py_True)
#define Py_RETURN_FALSE return Py_NewRef(Py_False)
#define _PyVarObject_CAST_CONST(op) ((const PyVarObject*)(op))
+// Test if the 'x' object is the 'y' object, the same as "x is y" in Python.
+PyAPI_FUNC(int) Py_Is(PyObject *x, PyObject *y);
+#define Py_Is(x, y) ((x) == (y))
+
+
static inline Py_ssize_t _Py_REFCNT(const PyObject *ob) {
return ob->ob_refcnt;
}
PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */
#define Py_None (&_Py_NoneStruct)
+// Test if an object is the None singleton, the same as "x is None" in Python.
+PyAPI_FUNC(int) Py_IsNone(PyObject *x);
+#define Py_IsNone(x) Py_Is((x), Py_None)
+
/* Macro for returning Py_None from a function */
#define Py_RETURN_NONE return Py_NewRef(Py_None)
--- /dev/null
+Add the :c:func:`Py_Is(x, y) <Py_Is>` function to test if the *x* object is the
+*y* object, the same as ``x is y`` in Python. Add also the :c:func:`Py_IsNone`,
+:c:func:`Py_IsTrue`, :c:func:`Py_IsFalse` functions to test if an object is,
+respectively, the ``None`` singleton, the ``True`` singleton or the ``False``
+singleton.
+Patch by Victor Stinner.
}
-// Test Py_NewRef() and Py_XNewRef() functions
+#define TEST_REFCOUNT() \
+ do { \
+ PyObject *obj = PyList_New(0); \
+ if (obj == NULL) { \
+ return NULL; \
+ } \
+ assert(Py_REFCNT(obj) == 1); \
+ \
+ /* test Py_NewRef() */ \
+ PyObject *ref = Py_NewRef(obj); \
+ assert(ref == obj); \
+ assert(Py_REFCNT(obj) == 2); \
+ Py_DECREF(ref); \
+ \
+ /* test Py_XNewRef() */ \
+ PyObject *xref = Py_XNewRef(obj); \
+ assert(xref == obj); \
+ assert(Py_REFCNT(obj) == 2); \
+ Py_DECREF(xref); \
+ \
+ assert(Py_XNewRef(NULL) == NULL); \
+ \
+ Py_DECREF(obj); \
+ Py_RETURN_NONE; \
+ } while (0) \
+
+
+// Test Py_NewRef() and Py_XNewRef() macros
static PyObject*
-test_refcount(PyObject *self, PyObject *Py_UNUSED(ignored))
+test_refcount_macros(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- PyObject *obj = PyList_New(0);
- if (obj == NULL) {
- return NULL;
- }
- assert(Py_REFCNT(obj) == 1);
+ TEST_REFCOUNT();
+}
+
+#undef Py_NewRef
+#undef Py_XNewRef
+
+// Test Py_NewRef() and Py_XNewRef() functions, after undefining macros.
+static PyObject*
+test_refcount_funcs(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ TEST_REFCOUNT();
+}
- // Test Py_NewRef()
- PyObject *ref = Py_NewRef(obj);
- assert(ref == obj);
- assert(Py_REFCNT(obj) == 2);
- Py_DECREF(ref);
- // Test Py_XNewRef()
- PyObject *xref = Py_XNewRef(obj);
- assert(xref == obj);
- assert(Py_REFCNT(obj) == 2);
- Py_DECREF(xref);
+// Test Py_Is() function
+#define TEST_PY_IS() \
+ do { \
+ PyObject *o_none = Py_None; \
+ PyObject *o_true = Py_True; \
+ PyObject *o_false = Py_False; \
+ PyObject *obj = PyList_New(0); \
+ if (obj == NULL) { \
+ return NULL; \
+ } \
+ \
+ /* test Py_Is() */ \
+ assert(Py_Is(obj, obj)); \
+ assert(!Py_Is(obj, o_none)); \
+ \
+ /* test Py_None */ \
+ assert(Py_Is(o_none, o_none)); \
+ assert(!Py_Is(obj, o_none)); \
+ \
+ /* test Py_True */ \
+ assert(Py_Is(o_true, o_true)); \
+ assert(!Py_Is(o_false, o_true)); \
+ assert(!Py_Is(obj, o_true)); \
+ \
+ /* test Py_False */ \
+ assert(Py_Is(o_false, o_false)); \
+ assert(!Py_Is(o_true, o_false)); \
+ assert(!Py_Is(obj, o_false)); \
+ \
+ Py_DECREF(obj); \
+ Py_RETURN_NONE; \
+ } while (0)
+
+// Test Py_Is() macro
+static PyObject*
+test_py_is_macros(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ TEST_PY_IS();
+}
- assert(Py_XNewRef(NULL) == NULL);
+#undef Py_Is
- Py_DECREF(obj);
- Py_RETURN_NONE;
+// Test Py_Is() function, after undefining its macro.
+static PyObject*
+test_py_is_funcs(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ TEST_PY_IS();
}
{"pynumber_tobase", pynumber_tobase, METH_VARARGS},
{"without_gc", without_gc, METH_O},
{"test_set_type_size", test_set_type_size, METH_NOARGS},
- {"test_refcount", test_refcount, METH_NOARGS},
+ {"test_refcount_macros", test_refcount_macros, METH_NOARGS},
+ {"test_refcount_funcs", test_refcount_funcs, METH_NOARGS},
+ {"test_py_is_macros", test_py_is_macros, METH_NOARGS},
+ {"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
{"fatal_error", test_fatal_error, METH_VARARGS,
PyDoc_STR("fatal_error(message, release_gil=False): call Py_FatalError(message)")},
{NULL, NULL} /* sentinel */
return _Py_XNewRef(obj);
}
+#undef Py_Is
+#undef Py_IsNone
+#undef Py_IsTrue
+#undef Py_IsFalse
+
+// Export Py_Is(), Py_IsNone(), Py_IsTrue(), Py_IsFalse() as regular functions
+// for the stable ABI.
+int Py_Is(PyObject *x, PyObject *y)
+{
+ return (x == y);
+}
+
+int Py_IsNone(PyObject *x)
+{
+ return Py_Is(x, Py_None);
+}
+
+int Py_IsTrue(PyObject *x)
+{
+ return Py_Is(x, Py_True);
+}
+
+int Py_IsFalse(PyObject *x)
+{
+ return Py_Is(x, Py_False);
+}
+
#ifdef __cplusplus
}
#endif
-
/* Execute compiled code */
/* XXX TO DO:
gen_status = PyIter_Send(receiver, v, &retval);
} else {
_Py_IDENTIFIER(send);
- if (v == Py_None && PyIter_Check(receiver)) {
+ if (Py_IsNone(v) && PyIter_Check(receiver)) {
retval = Py_TYPE(receiver)->tp_iternext(receiver);
}
else {
case TARGET(GEN_START): {
PyObject *none = POP();
Py_DECREF(none);
- if (none != Py_None) {
+ if (!Py_IsNone(none)) {
if (oparg > 2) {
_PyErr_SetString(tstate, PyExc_SystemError,
"Illegal kind for GEN_START");
case TARGET(IS_OP): {
PyObject *right = POP();
PyObject *left = TOP();
- int res = (left == right)^oparg;
+ int res = Py_Is(left, right) ^ oparg;
PyObject *b = res ? Py_True : Py_False;
Py_INCREF(b);
SET_TOP(b);
PREDICTED(POP_JUMP_IF_FALSE);
PyObject *cond = POP();
int err;
- if (cond == Py_True) {
+ if (Py_IsTrue(cond)) {
Py_DECREF(cond);
DISPATCH();
}
- if (cond == Py_False) {
+ if (Py_IsFalse(cond)) {
Py_DECREF(cond);
JUMPTO(oparg);
DISPATCH();
PREDICTED(POP_JUMP_IF_TRUE);
PyObject *cond = POP();
int err;
- if (cond == Py_False) {
+ if (Py_IsFalse(cond)) {
Py_DECREF(cond);
DISPATCH();
}
- if (cond == Py_True) {
+ if (Py_IsTrue(cond)) {
Py_DECREF(cond);
JUMPTO(oparg);
DISPATCH();
case TARGET(JUMP_IF_FALSE_OR_POP): {
PyObject *cond = TOP();
int err;
- if (cond == Py_True) {
+ if (Py_IsTrue(cond)) {
STACK_SHRINK(1);
Py_DECREF(cond);
DISPATCH();
}
- if (cond == Py_False) {
+ if (Py_IsFalse(cond)) {
JUMPTO(oparg);
DISPATCH();
}
case TARGET(JUMP_IF_TRUE_OR_POP): {
PyObject *cond = TOP();
int err;
- if (cond == Py_False) {
+ if (Py_IsFalse(cond)) {
STACK_SHRINK(1);
Py_DECREF(cond);
DISPATCH();
}
- if (cond == Py_True) {
+ if (Py_IsTrue(cond)) {
JUMPTO(oparg);
DISPATCH();
}
goto error;
}
PUSH(values_or_none);
- if (values_or_none == Py_None) {
+ if (Py_IsNone(values_or_none)) {
Py_INCREF(Py_False);
PUSH(Py_False);
DISPATCH();
exc = TOP();
val = SECOND();
tb = THIRD();
- assert(exc != Py_None);
+ assert(!Py_IsNone(exc));
assert(!PyLong_Check(exc));
exit_func = PEEK(7);
PyObject *stack[4] = {NULL, exc, val, tb};
type = exc_info->exc_type;
value = exc_info->exc_value;
tb = exc_info->exc_traceback;
- if (type == Py_None || type == NULL) {
+ if (Py_IsNone(type) || type == NULL) {
_PyErr_SetString(tstate, PyExc_RuntimeError,
"No active exception to reraise");
return 0;
else if (PyExceptionInstance_Check(cause)) {
fixed_cause = cause;
}
- else if (cause == Py_None) {
+ else if (Py_IsNone(cause)) {
Py_DECREF(cause);
fixed_cause = NULL;
}
_PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi)
{
PyThreadState *tstate = _PyThreadState_GET();
- if (v != Py_None) {
+ if (!Py_IsNone(v)) {
Py_ssize_t x;
if (_PyIndex_Check(v)) {
x = PyNumber_AsSsize_t(v, NULL);