代码之家  ›  专栏  ›  技术社区  ›  Jason Baker

为什么这个C方法是分段的?

  •  1
  • Jason Baker  · 技术社区  · 14 年前

    class PList(object):
        def __init__(self, first, rest=None):
            self.first = first
            self.rest = rest
    
        def cons(self, item):
            return PList(item, self)
    

    这是我的代码:

    #include <Python.h>
    #include <structmember.h>
    
    static PyTypeObject PListType;
    
    typedef struct PListStruct{
      PyObject_HEAD
      PyObject *first;
      struct PListStruct *rest;
    } PList;
    
    static PyMemberDef plist_members[] = {
      {"first", T_OBJECT_EX, offsetof(PList, first), READONLY, "First element"},
      {"rest", T_OBJECT_EX, offsetof(PList, rest), READONLY, "Rest of the list"},
      {NULL}
    };
    
    static PyObject *
    PList_cons(PList *self, PyObject *arg)
    {
      PList *new_list = PyObject_CallFunctionObjArgs(&PListType, arg, self);
      Py_INCREF(new_list);
      return new_list;
    }
    
    static PyMethodDef plist_methods[] = {
      {"cons", (PyCFunction)PList_cons, METH_O, "Add an item to the list"},
      {NULL}
    };
    
    
    static void PList_dealloc(PList *self)
    {
      Py_XDECREF(self->first);
      Py_XDECREF(self->rest);
      self->ob_type->tp_free((PyObject*)self);
    }
    
    static int
    PList_init(PList *self, PyObject *args, PyObject *kwds)
    {
      PyObject *first=NULL, *rest=NULL, *tmp;
    
      static char *kwlist[] = {"first", "rest", NULL};
      if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist,
                                        &first, &rest))
        return -1;
    
      if (first){
        tmp = self->first;
        Py_INCREF(first);
        self->first = first;
        Py_XDECREF(tmp);
      }
    
      if (rest) {
        tmp = self->rest;
        Py_INCREF(rest);
        self->rest = rest;
        Py_XDECREF(tmp);
      }
      else {
        tmp = self->rest;
        Py_INCREF(Py_None);
        self->rest = Py_None;
        Py_XDECREF(tmp);
      }
    
      return 0;
    }
    
    static PyTypeObject PListType= {
        PyObject_HEAD_INIT(NULL)
        0,                         /*ob_size*/
        "pysistence.persistent_list.PList",             /*tp_name*/
        sizeof(PList), /*tp_basicsize*/
        0,                         /*tp_itemsize*/
        (destructor)PList_dealloc,                         /*tp_dealloc*/
        0,                         /*tp_print*/
        0,                         /*tp_getattr*/
        0,                         /*tp_setattr*/
        0,                         /*tp_compare*/
        0,                         /*tp_repr*/
        0,                         /*tp_as_number*/
        0,                         /*tp_as_sequence*/
        0,                         /*tp_as_mapping*/
        0,                         /*tp_hash */
        0,                         /*tp_call*/
        0,                         /*tp_str*/
        0,                         /*tp_getattro*/
        0,                         /*tp_setattro*/
        0,                         /*tp_as_buffer*/
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,        /*tp_flags*/
        "Persistent list",           /* tp_doc */
        0,                       /* tp_traverse */
        0,                       /* tp_clear */
        0,                       /* tp_richcompare */
        0,                       /* tp_weaklistoffset */
        0,                       /* tp_iter */
        0,                       /* tp_iternext */
        plist_methods,          /* tp_methods */
        plist_members,                       /* tp_members */
        0,                       /* tp_getset */
        0,                       /* tp_base */
        0,                       /* tp_dict */
        0,                       /* tp_descr_get */
        0,                       /* tp_descr_set */
        0,                       /* tp_dictoffset */
        (initproc)PList_init,   /* tp_init */
        0,                       /* tp_alloc */
        0,                       /* tp_new */
    };
    
    #ifndef PyMODINIT_FUNC
    #define PyMODINIT_FUNC void
    #endif
    
    PyMODINIT_FUNC
    initpersistent_list(void)
    {
      PyObject *m;
    
      PListType.tp_new = PyType_GenericNew;
      if (PyType_Ready(&PListType) < 0)
        return;
    
      m = Py_InitModule3("pysistence.persistent_list", 0,
                         "Docstring");
      Py_INCREF(&PListType);
      PyModule_AddObject(m, "PList", (PyObject*)&PListType);
    }
    

    如果我运行此代码,它会在最后一行显示故障:

    from pysistence.persistent_list import PList    
    
    p = PList(1)
    p = PList(2, p)
    p = p.cons(3)
    

    我肯定我只是在做一些蠢事,但我不知道这是什么。我有什么遗漏吗?

    1 回复  |  直到 14 年前
        1
  •  4
  •   Nicolas Viennot    14 年前

    我正在阅读文档:


    PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ..., NULL)
        Return value: New reference.
    

    调用一个可调用的Python对象callable,其中PyObject*参数的数目可变。参数是作为参数的变量数提供的,后面跟着NULL。成功时返回调用结果,失败时返回空值。


    结尾处缺少空值。

    编辑:Ho,您还想检查函数在内存故障时是否返回NULL