mirror of https://github.com/python/cpython
bpo-43753: Add Py_Is() and Py_IsNone() functions (GH-25227)
Add the Py_Is(x, y) function to test if the 'x' object is the 'y' object, the same as "x is y" in Python. Add also the Py_IsNone(), Py_IsTrue(), Py_IsFalse() functions to test if an object is, respectively, the None singleton, the True singleton or the False singleton.
This commit is contained in:
parent
6e468cb16b
commit
09bbebea16
|
@ -62,6 +62,37 @@ the definition of all other Python objects.
|
|||
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*.
|
||||
|
|
|
@ -767,7 +767,11 @@ Py_HasFileSystemDefaultEncoding
|
|||
Py_IncRef
|
||||
Py_Initialize
|
||||
Py_InitializeEx
|
||||
Py_Is
|
||||
Py_IsFalse
|
||||
Py_IsInitialized
|
||||
Py_IsNone
|
||||
Py_IsTrue
|
||||
Py_LeaveRecursiveCall
|
||||
Py_Main
|
||||
Py_MakePendingCalls
|
||||
|
|
|
@ -1385,6 +1385,13 @@ New Features
|
|||
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
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -21,6 +21,14 @@ PyAPI_DATA(struct _longobject) _Py_FalseStruct, _Py_TrueStruct;
|
|||
#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)
|
||||
|
|
|
@ -122,6 +122,11 @@ typedef struct {
|
|||
#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;
|
||||
}
|
||||
|
@ -586,6 +591,10 @@ Don't forget to apply Py_INCREF() when returning this value!!!
|
|||
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)
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
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.
|
|
@ -5401,32 +5401,98 @@ test_set_type_size(PyObject *self, PyObject *Py_UNUSED(ignored))
|
|||
}
|
||||
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Test Py_NewRef()
|
||||
PyObject *ref = Py_NewRef(obj);
|
||||
assert(ref == obj);
|
||||
assert(Py_REFCNT(obj) == 2);
|
||||
Py_DECREF(ref);
|
||||
#undef Py_NewRef
|
||||
#undef Py_XNewRef
|
||||
|
||||
// Test Py_XNewRef()
|
||||
PyObject *xref = Py_XNewRef(obj);
|
||||
assert(xref == obj);
|
||||
assert(Py_REFCNT(obj) == 2);
|
||||
Py_DECREF(xref);
|
||||
// Test Py_NewRef() and Py_XNewRef() functions, after undefining macros.
|
||||
static PyObject*
|
||||
test_refcount_funcs(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_REFCOUNT();
|
||||
}
|
||||
|
||||
assert(Py_XNewRef(NULL) == NULL);
|
||||
|
||||
Py_DECREF(obj);
|
||||
Py_RETURN_NONE;
|
||||
// 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();
|
||||
}
|
||||
|
||||
#undef Py_Is
|
||||
|
||||
// Test Py_Is() function, after undefining its macro.
|
||||
static PyObject*
|
||||
test_py_is_funcs(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_PY_IS();
|
||||
}
|
||||
|
||||
|
||||
|
@ -5716,7 +5782,10 @@ static PyMethodDef TestMethods[] = {
|
|||
{"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 */
|
||||
|
|
|
@ -2279,6 +2279,33 @@ Py_XNewRef(PyObject *obj)
|
|||
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
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/* Execute compiled code */
|
||||
|
||||
/* XXX TO DO:
|
||||
|
@ -2570,7 +2569,7 @@ main_loop:
|
|||
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 {
|
||||
|
@ -2634,7 +2633,7 @@ main_loop:
|
|||
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");
|
||||
|
@ -3615,7 +3614,7 @@ main_loop:
|
|||
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);
|
||||
|
@ -3744,11 +3743,11 @@ main_loop:
|
|||
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();
|
||||
|
@ -3768,11 +3767,11 @@ main_loop:
|
|||
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();
|
||||
|
@ -3792,12 +3791,12 @@ main_loop:
|
|||
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();
|
||||
}
|
||||
|
@ -3816,12 +3815,12 @@ main_loop:
|
|||
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();
|
||||
}
|
||||
|
@ -3966,7 +3965,7 @@ main_loop:
|
|||
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();
|
||||
|
@ -4157,7 +4156,7 @@ main_loop:
|
|||
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};
|
||||
|
@ -5235,7 +5234,7 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause)
|
|||
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;
|
||||
|
@ -5293,7 +5292,7 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause)
|
|||
else if (PyExceptionInstance_Check(cause)) {
|
||||
fixed_cause = cause;
|
||||
}
|
||||
else if (cause == Py_None) {
|
||||
else if (Py_IsNone(cause)) {
|
||||
Py_DECREF(cause);
|
||||
fixed_cause = NULL;
|
||||
}
|
||||
|
@ -5987,7 +5986,7 @@ int
|
|||
_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);
|
||||
|
|
Loading…
Reference in New Issue