如何将Python布尔对象转换为C int(或C ++ boolean)(Python C API)

时间:2016-10-09 21:00:19

标签: python c python-c-api

我有一个变量PyObject,我知道它是一个Python bool。它可以是TrueFalse(例如Py_TruePy_False)。现在我想以某种方式将其转换为C ++。

使用字符串执行此操作并不困难,有一个辅助函数 - PyBytes_AsString将python字符串转换为C字符串。现在我需要像boolean那样的东西(或者因为C中没有bool而是int。)

或者如果没有转换,也许某些功能可以与true或false进行比较?像int PyBool_IsTrue(PyObject*)

这样的东西

以下是一些示例代码,可以更轻松地理解我需要的内容:

#include <Python.h>

int main()
{
    /* here I create Python boolean with value of True */
    PyObject *b = Py_RETURN_TRUE;
    /* now that I have it I would like to turn in into C type so that I can determine if it's True or False */
    /* something like */
    if (PyBool_IsTrue(b))
    { /* it's true! */ }
    else
    { /* it's false */ }
    return 0;
}

这显然不起作用,因为没有像PyBool_IsTrue这样的功能:(我该怎么做?

Python标题的片段(boolobject.h):

/* Boolean object interface */

#ifndef Py_BOOLOBJECT_H
#define Py_BOOLOBJECT_H
#ifdef __cplusplus
extern "C" {
#endif


PyAPI_DATA(PyTypeObject) PyBool_Type;

#define PyBool_Check(x) (Py_TYPE(x) == &PyBool_Type)

/* Py_False and Py_True are the only two bools in existence.
Don't forget to apply Py_INCREF() when returning either!!! */

/* Don't use these directly */
PyAPI_DATA(struct _longobject) _Py_FalseStruct, _Py_TrueStruct;

/* Use these macros */
#define Py_False ((PyObject *) &_Py_FalseStruct)
#define Py_True ((PyObject *) &_Py_TrueStruct)

/* Macros for returning Py_True or Py_False, respectively */
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False

/* Function to return a bool from a C long */
PyAPI_FUNC(PyObject *) PyBool_FromLong(long);

#ifdef __cplusplus
}
#endif
#endif /* !Py_BOOLOBJECT_H */

2 个答案:

答案 0 :(得分:7)

每个 Python对象都可以使用PyObject_IsTrue评估其真实性,您应优先使用它来指导PyTrue / PyFalse单例检查,除非您绝对肯定地知道对象是PyBool

用法是:

int truthy = PyObject_IsTrue(someobj);
if (truthy == -1) return APPROPRIATEERRORRETURN;

if (truthy)
{ /* it's true! */ }
else
{ /* it's false */ }

如果你知道它肯定是一个bool,你可以测试someobj == Py_True,或者使用PyNumber_AsSsize_t来转换任何逻辑整数类型(任何实现__index__的内容,而bool是一个int的子类,因此它在逻辑上也是一个整数)到签名的size_t值(如果__index__返回的数字不符合签名的size_t,它将返回-1,异常设置)。

一般不做someobj == Py_True的原因是因为它就像在Python层做if someobj is True:一样。当someobj1或非空str时,如果Pythonic代码很少关注TrueFalse,则会将其视为false而是“真实性”和“虚假性”。

另外,这个:

PyObject *b = Py_RETURN_TRUE;

是错误的。这将增加PyTrue并返回它;后续代码都不会执行。你想要:

PyObject *b = Py_True;

借用参考文献,添加后续内容:

Py_INCREF(b);
如果你打算稍后返回它,那么

使它成为一个拥有的引用(因为它是一个不会消失的单例,使用借用的引用是正常的,除非你知道它将在DECREF稍后进行,例如因为你把它归还并将所有权转给了一个不知道它是借来的参考的来电者。

答案 1 :(得分:-1)

答案是在Python标题中,但可能并不明显。

Python标头在这里声明了2个有点静态的对象,有几个宏:

/* Don't use these directly */
PyAPI_DATA(struct _longobject) _Py_FalseStruct, _Py_TrueStruct;

/* Use these macros */
#define Py_False ((PyObject *) &_Py_FalseStruct)
#define Py_True ((PyObject *) &_Py_TrueStruct)

/* Macros for returning Py_True or Py_False, respectively */
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False

似乎TrueFalse实际上都是Python对象,而Python中TrueFalse的所有值实际上都引用了这两个全局{ {1}}和Py_True个对象。使用Py_False返回此类对象时,引用计数会递增。

这意味着指向值Py_RETURN_TRUE的PyObject的每个C指针实际上指向相同的内存地址。因此,检查Py_True是真还是假是如此简单:

PyObject

使用/* here I create Python boolean with value of True */ PyObject *b = Py_True; Py_INCREF(b); /* now we compare the address of pointer with address of Py_True */ if (b == Py_True) { /* it's true! */ } else { /* it's false */ } 来验证相关对象是否为Python布尔值通常是个好主意。