Передача объекта в модуль C, в Python

Я столкнулся с ситуацией с чистым модулем python и Cython. Подводя итог, как я могу принять и управлять объектом python в модуле C? Моя часть 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") )

в C, необходимо решить две вещи. во-первых, как я могу получить объект? во-вторых, как я могу вызвать метод из объекта?


    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;
    }

Ответ 1

Чтобы извлечь аргумент из вызова вашего метода, вам нужно посмотреть на функции, описанные в Разбор аргументов и значений зданий, например PyArg_ParseTuple. (Это, если вы только принимаете позиционные аргументы! Есть и другие аргументы с позиционным и ключевым словом и т.д.)

Объект, возвращаемый с PyArg_ParseTuple, не имеет увеличенного количества ссылок. Для простых функций C вам, вероятно, не нужно беспокоиться об этом. Если вы взаимодействуете с другими функциями 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.

Для вызова метода для объекта вам необходимо использовать PyObject_CallMethod или PyObject_CallMethodObjArgs, в зависимости от того, как вы создаете список аргументов и имя метода. И посмотрите мой комментарий в коде об объектной собственности!

Быстрое отступление просто для того, чтобы убедиться, что вы не настроитесь на падение позже. Если вы действительно хотите, чтобы строка была напечатана, вам лучше просто получить ссылку на объект и передать ее в PyObject_Print. Конечно, возможно, это просто для иллюстрации, или вы знаете лучше, чем я делаю то, что вы хотите делать с данными;)

  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 a failure, we'll get NULL
  if(objname == NULL)
  {
    // Again, this should just propagate the exception information
    return NULL;
  }

Теперь в разделе String/Bytes Objects существует ряд функций Concrete Objects Layer docs; используйте то, что лучше всего подходит вам.

Но не забывайте этот бит:

  // 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 just
  // return the "None" singleton.
  // Note: this macro includes the "return" statement!
  Py_RETURN_NONE;
}

Обратите внимание на использование Py_RETURN_NONE и обратите внимание, что это не return Py_RETURN_NONE!

PS. Структура этого кода в значительной степени продиктована личным стилем (например, ранними версиями, static char форматированием строк внутри функции, инициализацией до NULL). Надеюсь, важная информация достаточно ясна, кроме стилистических конвенций.