检查 PyObjects C 类型

Posted

技术标签:

【中文标题】检查 PyObjects C 类型【英文标题】:Checking A PyObjects C Type 【发布时间】:2011-05-23 22:41:15 【问题描述】:

我正在使用 Python 3.2 和 C++。

我需要提取当前存储在 PyObject 中的 C 类型。 我检查了文档并用谷歌搜索了它,似乎没有其他人需要这样做。

所以我有一个 PyObject 并试图提取 C 值。我有需要从对象中实际提取值的函数列表,但我首先需要知道的是存储在对象本身中的内容以调用正确的函数。

以防万一这有助于理解这里是我正在尝试的一些示例代码。

//Variable is a custom variant type to allow for generic functionality.
Variable ExtractArgument( PyObject * arg )

  Variable value;
  PyObject* result;
  //now here is the problem, I need to know which Python function to call in order to
  //extract the correct type;
  value = PyLong_FromLong( arg );
  //or 
  value = PyFloat_FromDouble( arg )
  //ect.
  return value;

希望我能有一些看起来像这样的东西

Variable ExtractArgument( PyObject * arg )

  Variable value;
  PyObject* result;
  //PyType is not the actual variable to that holds the type_macro, GetType should be
  //replaced by the function I am trying to find 
  PyType type = GetType( arg ); 
  switch( type )
   
    case T_INT: value = static_cast<int>(PyLong_FromLong( arg  )); 
      break;
    case T_FLOAT: value = static_cast<float>(PyFloat_FromDouble( arg  ));
      break;
    case T_DOUBLE: value = PyDouble_FromDouble( arg );
      break;
    //ect.
  
  return value;
 

对不起,如果这个问题太长或信息太多。第一次发帖,不想留下任何可能有帮助的东西。 感谢您在此问题上提供的任何帮助或见解。

【问题讨论】:

【参考方案1】:

Python 对象没有 C 类型,它们有 Python 类型。例如,整数可以是 C long 或 long 整数。您可以使用 PyInt_Check(obj)PyList_Check(obj) 等来检查类型。如果返回 true,那么您知道您拥有该类型的对象。

请注意,PyLong_FromLong 等则相反。他们获取一个 C 值并将其转换为 PyObject*。因此,您正在向后使用它们。我想你的意思是PyInt_AsLong

【讨论】:

到目前为止,这似乎是我必须尝试的最佳选择。我“可能”会遇到一些类型冲突,因为 python 没有存储我需要的所有类型,所以我很可能会结合检查 C++ 函数期望的类型来执行此操作。 您是否正在为 C++ 函数编写 Python 包装器?听起来你正在重新发明 SWIG。 我正在创建一个简单易用的 python 包装器,它为我的游戏引擎创建我称之为 Bindable 的对象。它的作用是获取类的元数据并循环遍历此信息并创建所有成员函数包装器,从而允许我们的游戏设计师使用 python 脚本使用我们的 C++ 定义的对象编写游戏玩法。 SWIG 和 Boost::Python 之类的问题在于它们是外部程序,需要事先创建文件,然后再编译程序。对我们来说,这是运行时完成的。编译的唯一变化是添加一行代码来构造类。 *Boost 的问题在于它是编译时间和模板地狱。我们喜欢我们的游戏引擎在大约 4 秒内编译并且几乎没有外部依赖,除了 DirectX 和 Fmod 之类的东西。【参考方案2】:

这不是 Python 类型的工作原理;它们不会一对一地映射到 C 类型。没有 Python C/API 函数可以告诉您特定值适合哪种 C 类型。但是,有诸如 PyFloat_Check()PyInt_Check() 之类的函数可以检查类型(并考虑子类)。还指定了 PyArg_ParseTuple()(及其变体)的说明符,告诉 Python 适当地转换传入的参数。

通常使用的是后者;使用PyArg_ParseTuple() 解码传递给 C 函数的参数,如果您需要以不同的方式传递不同的类型,请将它们作为不同的参数(通常作为命名参数)传递。目前尚不清楚该方法是否适合您。第二个最常见的做法是尝试使用不同的函数转换参数先不进行类型检查,然后在转换函数失败时简单地尝试另一个转换函数。显式类型检查通常是最不常见的替代方法。

【讨论】:

是的,正如我所说,对于 PyArg_ParseTuple() 和不同的类型,您需要一些方法来预先区分预期的类型。这实际上是 Python 中一个非常常见的主题。也许您想更改您的类以实际存储预期的 C 类型以及 PyObject 值。否则,您会遇到问题,例如 int 1 不是代码中 float 参数的有效值,但在其他任何地方都很好。 好吧,从亚当所说的看来,我将进行类型检查,如 PyInt_Check、PyFloat_Check 等。然后在从这个语句中得到真或假之后,检查我正在使用的变量的元类型(它定义了诸如 int、unsigned、float、double 等的东西)。随后是适当的 python 调用,例如 PyInt_AsLong、PyFloat_AsDouble 等。以及合适的演员阵容。 是的,这也是我描述的事情之一,它也有缺点(就像我描述的那样。) 好吧,我实际上并没有调用转换并看到它失败了,我调用的是你和亚当指出的函数,然后使用我的元数据调用适当的转换,因为元数据是传递给我的类的构造函数包含诸如第一个参数是双精度还是整数等信息。所以这确实没有太大的缺点,因为对于我们存储的内容,我最多有 4 次类型检查,其中一次检查元数据,然后是一次强制转换(在运行时完成)以及我们使用 python 不是性能密集型的。 我并不是说存在性能问题。我的意思是,例如,当整数 1 在您的特定用例中不被视为有效的浮点值时,这通常会让人感到困惑,而几乎所有的 Python 代码都根本不在乎。

以上是关于检查 PyObjects C 类型的主要内容,如果未能解决你的问题,请参考以下文章

我应该对这个块中的任何 PyObjects 使用 Py_INCREF 吗?我也正确 Py_DECREFing 我的对象吗?

来自python字符串的C char数组

从python字符串中提取的C字符数组

『Python CoolBook』C扩展库_其六_从C语言中调用Python代码

检查 PyObject 是不是为 None

如何检查 PyObject 是不是为列表?