简体   繁体   English

在Python中将对象传递给C模块

[英]Passing an object to C module, in Python

I ran into a situation with pure python and C python module. 我遇到了纯python和C python模块的情况。 To summarize, how can I accept and manipulate python object in C module? 总结一下,我如何在C模块中接受和操作python对象? My python part will look like this. 我的python部分看起来像这样。


    #!/usr/bin/env python

    import os, sys
    from c_hello import *

    class Hello:
        busyHello = _sayhello_obj

    class Man:
        def __init__(self, name):
            self.name = name
        def getName(self):
            return self.name

    h = Hello()
    h.busyHello( Man("John") )

in C, two things need to be resolved. 在C中,需要解决两件事。 first, how can I receive object? 首先,我该如何接收物品? second, how can I call a method from the object? 第二,如何从对象中调用方法?


    static PyObject *
    _sayhello_obj(PyObject *self, PyObject *args)
    {
      PyObject *obj;
      // How can I fill obj?

      char s[1024];
      // How can I fill s, from obj.getName() ?

      printf("Hello, %s\n", s);
      return Py_None;
    }

To extract an argument from an invocation of your method, you need to look at the functions documented in Parsing arguments and building values , such as PyArg_ParseTuple . 要从方法的调用中提取参数,您需要查看解析参数和构建值中记录的函数,例如PyArg_ParseTuple (That's for if you're only taking positional args! There are others for positional-and-keyword args, etc.) (如果你只是采取位置args的话就是这样的!还有其他的位置和关键字args等等)

The object you get back from PyArg_ParseTuple doesn't have it's reference count increased. PyArg_ParseTuple返回的对象没有增加引用计数。 For simple C functions, you probably don't need to worry about this. 对于简单的C函数,您可能不需要担心这一点。 If you're interacting with other Python/C functions, or if you're releasing the global interpreter lock (ie. allowing threading), you need to think very carefully about object ownership. 如果您正在与其他Python / C函数交互,或者您正在发布全局解释器锁(即允许线程),则需要仔细考虑对象所有权。

static PyObject *
_sayhello_obj(PyObject *self, PyObject *args)
{
  PyObject *obj = NULL;
  // How can I fill obj?

  static char fmt_string = "O" // For "object"

  int parse_result = PyArg_ParseTuple(args, fmt_string, &obj);

  if(!parse_res)
  {
    // Don't worry about using PyErr_SetString, all the exception stuff should be
    // done in PyArg_ParseTuple()
    return NULL;
  }

  // Of course, at this point you need to do your own verification of whatever
  // constraints might be on your argument.

For calling a method on an object, you need to use either PyObject_CallMethod or PyObject_CallMethodObjArgs , depending on how you construct the argument list and method name. 要在对象上调用方法,您需要使用PyObject_CallMethodPyObject_CallMethodObjArgs ,具体取决于您构造参数列表和方法名称的方式。 And see my comment in the code about object ownership! 并在有关对象所有权的代码中查看我的评论!

Quick digression just to make sure you're not setting yourself up for a fall later: If you really are just getting the string out to print it, you're better off just getting the object reference and passing it to PyObject_Print . 快速离题只是为了确保你不会让自己陷入困境:如果你真的只是将字符串输出来打印它,你最好只是获取对象引用并将其传递给PyObject_Print Of course, maybe this is just for illustration, or you know better than I do what you want to do with the data ;) 当然,也许这只是为了说明,或者你比我更了解你想要做的数据;)

  char s[1024];
  // How can I fill s, from obj.getName() ?

  // Name of the method
  static char method_name = "getName";
  // No arguments? Score! We just need NULL here
  char method_fmt_string = NULL;

  PyObject *objname = PyObject_CallMethod(obj, obj_method, method_fmt_string);
  // This is really important! What we have here now is a Python object with a newly
  // incremented reference count! This means you own it, and are responsible for
  // decrementing the ref count when you're done. See below.

  // If there's a failure, we'll get NULL
  if(objname == NULL)
  {
    // Again, this should just propagate the exception information
    return NULL;
  }

Now there are a number of functions in the String/Bytes Objects section of the Concrete Objects Layer docs; 现在, 具体对象层文档的String / Bytes Objects部分中有许多函数; use whichever works best for you. 使用最适合你的方式。

But do not forget this bit: 不要忘记这一点:

  // Now that we're done with the object we obtained, decrement the reference count
  Py_XDECREF(objname);

  // You didn't mention whether you wanted to return a value from here, so let's just
  // return the "None" singleton.
  // Note: this macro includes the "return" statement!
  Py_RETURN_NONE;
}

Note the use of Py_RETURN_NONE there, and note that it's not return Py_RETURN_NONE ! 注意在那里使用Py_RETURN_NONE ,并注意它不会return Py_RETURN_NONE

PS. PS。 The structure of this code is dictated to a great extent by personal style (eg. early returns, static char format strings inside the function, initialisation to NULL ). 此代码的结构在很大程度上取决于个人风格(例如,早期返回,函数内部的static char格式字符串,初始化为NULL )。 Hopefully the important information is clear enough apart from stylistic conventions. 希望除了风格惯例之外,重要的信息是清晰的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM