Defining *class* methods on C code

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Thomas Heller

    Defining *class* methods on C code

    I once knew how to do it, but I cannot find or remember it anymore:

    How can I attach *class* methods to a type in C code, when I have a
    function

    PyObject *func(PyObject *type, PyObject *arg);

    with the METH_O calling convention? The type is already created, I
    cannot insert it into the tp_methods array anymore.

    Something like this:

    class X(object):
    pass

    def func(cls, arg):
    ....

    X.func = classmethod(fun c)

    Thanks,

    Thomas
  • Diez B. Roggisch

    #2
    Re: Defining *class* methods on C code

    > How can I attach *class* methods to a type in C code, when I have a[color=blue]
    > function
    >
    > PyObject *func(PyObject *type, PyObject *arg);
    >
    > with the METH_O calling convention? The type is already created, I
    > cannot insert it into the tp_methods array anymore.
    >
    > Something like this:
    >
    > class X(object):
    > pass
    >
    > def func(cls, arg):
    > ....
    >
    > X.func = classmethod(fun c)[/color]

    Try METH_STATIC as flag for PyMethodDef.

    --

    Regards,

    Diez B. Roggisch

    Comment

    • Michael Hudson

      #3
      Re: Defining *class* methods on C code

      Thomas Heller <theller@python .net> writes:
      [color=blue]
      > I once knew how to do it, but I cannot find or remember it anymore:
      >
      > How can I attach *class* methods to a type in C code, when I have a
      > function
      >
      > PyObject *func(PyObject *type, PyObject *arg);
      >
      > with the METH_O calling convention? The type is already created, I
      > cannot insert it into the tp_methods array anymore.
      >
      > Something like this:
      >
      > class X(object):
      > pass
      >
      > def func(cls, arg):
      > ....
      >
      > X.func = classmethod(fun c)[/color]

      Just stuff it into tp_dict? You'll need to make the method object
      yourself, but that's easy.

      I think you probably have to hope that the name of the class method
      isn't a special method name (you'd want to call
      typeobject.c:up date_slots then, but I don't think you can arrange for
      that to happen from outside typeobject.c as all the juicy symbols are
      static).

      Or just stick TP_HEAPTYPE into tp_flags, use PyObject_SetAtt r and take
      TP_HEAPTYPE out again (that's very sick, though).

      Cheers,
      mwh

      --[color=blue]
      > Well, as an American citizen I hope that the EU tells the MPAA
      > and RIAA to shove it where the Sun don't shine.[/color]
      Actually they already did. Only first they bent over and dropped
      their trousers. -- Shmuel (Seymour J.) Metz & Toni Lassila, asr

      Comment

      • Thomas Heller

        #4
        Re: Defining *class* methods on C code

        Michael Hudson <mwh@python.net > writes:
        [color=blue]
        > Thomas Heller <theller@python .net> writes:
        >[color=green]
        >> I once knew how to do it, but I cannot find or remember it anymore:
        >>
        >> How can I attach *class* methods to a type in C code, when I have a
        >> function
        >>
        >> PyObject *func(PyObject *type, PyObject *arg);
        >>
        >> with the METH_O calling convention? The type is already created, I
        >> cannot insert it into the tp_methods array anymore.
        >>
        >> Something like this:
        >>
        >> class X(object):
        >> pass
        >>
        >> def func(cls, arg):
        >> ....
        >>
        >> X.func = classmethod(fun c)[/color]
        >
        > Just stuff it into tp_dict? You'll need to make the method object
        > yourself, but that's easy.
        >
        > I think you probably have to hope that the name of the class method
        > isn't a special method name (you'd want to call
        > typeobject.c:up date_slots then, but I don't think you can arrange for
        > that to happen from outside typeobject.c as all the juicy symbols are
        > static).[/color]

        No special names. Here's the code:

        static PyObject *my_method(PyOb ject *self, PyObject *arg)
        {
        Py_INCREF(arg);
        return arg;
        }

        static PyMethodDef my_methods[] = {
        { "my_method" , my_method, METH_O },
        { NULL, NULL },
        };

        and then ('type' is the type where I want to create the class method on):

        if (somecondition) {
        PyObject *func;
        PyObject *meth;
        PyMethodDef *ml = my_methods;

        for (; ml->ml_name; ++ml) {
        func = PyCFunction_New (ml, NULL);
        if (!func)
        return NULL;
        meth = PyClassMethod_N ew(func);
        if (!meth)
        return NULL;
        if (-1 == PyDict_SetItemS tring(result->tp_dict,
        ml->ml_name,
        meth))
        return NULL;
        }
        }

        I know that there are refcount leaks in this snippet, but that's not the
        point.

        Trying out the method:

        c:\sf\ctypes>py 23 -c "from ctypes import *; print c_int.my_method ()"
        <class 'ctypes.c_int'>

        c:\sf\ctypes>py 23 -c "from ctypes import *; print c_int.my_method (0)"
        Traceback (most recent call last):
        File "<string>", line 1, in ?
        TypeError: my_method() takes exactly one argument (2 given)
        c:\sf\ctypes>

        Works *nearly*, but I would have expected that the method accepts one
        parameter, pass it as 'arg' to the C function, plus the type itself as
        'self'.
        [color=blue]
        > Or just stick TP_HEAPTYPE into tp_flags, use PyObject_SetAtt r and take
        > TP_HEAPTYPE out again (that's very sick, though).[/color]

        Um, why that?

        Thanks,

        Thomas

        Comment

        • Thomas Heller

          #5
          Re: Defining *class* methods on C code

          Thomas Heller <theller@python .net> writes:

          [followup to myself, I found it][color=blue]
          > Michael Hudson <mwh@python.net > writes:
          >[color=green]
          >> Thomas Heller <theller@python .net> writes:
          >>[color=darkred]
          >>> I once knew how to do it, but I cannot find or remember it anymore:
          >>>
          >>> How can I attach *class* methods to a type in C code, when I have a
          >>> function
          >>>
          >>> PyObject *func(PyObject *type, PyObject *arg);
          >>>
          >>> with the METH_O calling convention? The type is already created, I
          >>> cannot insert it into the tp_methods array anymore.
          >>>
          >>> Something like this:
          >>>
          >>> class X(object):
          >>> pass
          >>>
          >>> def func(cls, arg):
          >>> ....
          >>>
          >>> X.func = classmethod(fun c)[/color]
          >>
          >> Just stuff it into tp_dict? You'll need to make the method object
          >> yourself, but that's easy.
          >>
          >> I think you probably have to hope that the name of the class method
          >> isn't a special method name (you'd want to call
          >> typeobject.c:up date_slots then, but I don't think you can arrange for
          >> that to happen from outside typeobject.c as all the juicy symbols are
          >> static).[/color]
          >
          > No special names. Here's the code:
          >
          > static PyObject *my_method(PyOb ject *self, PyObject *arg)
          > {
          > Py_INCREF(arg);
          > return arg;
          > }
          >
          > static PyMethodDef my_methods[] = {
          > { "my_method" , my_method, METH_O },
          > { NULL, NULL },
          > };
          >
          > and then ('type' is the type where I want to create the class method on):
          >[/color]
          [snipped non-working code]

          I have to call PyDescr_NewClas sMethodType:

          if (somecondition) {
          PyObject *meth;
          PyMethodDef *ml = my_methods;

          for (; ml->ml_name; ++ml) {
          meth = PyDescr_NewClas sMethod(type, ml);
          if (!meth)
          return NULL;
          if (-1 == PyDict_SetItemS tring(type->tp_dict,
          ml->ml_name,
          meth))
          return NULL;
          }
          }
          [color=blue]
          > I know that there are refcount leaks in this snippet, but that's not the
          > point.[/color]

          Thomas

          Comment

          • Michael Hudson

            #6
            Re: Defining *class* methods on C code

            Thomas Heller <theller@python .net> writes:
            [color=blue]
            > Michael Hudson <mwh@python.net > writes:
            >[color=green]
            > > Thomas Heller <theller@python .net> writes:
            > >[color=darkred]
            > >> I once knew how to do it, but I cannot find or remember it anymore:
            > >>
            > >> How can I attach *class* methods to a type in C code, when I have a
            > >> function
            > >>
            > >> PyObject *func(PyObject *type, PyObject *arg);
            > >>
            > >> with the METH_O calling convention? The type is already created, I
            > >> cannot insert it into the tp_methods array anymore.
            > >>
            > >> Something like this:
            > >>
            > >> class X(object):
            > >> pass
            > >>
            > >> def func(cls, arg):
            > >> ....
            > >>
            > >> X.func = classmethod(fun c)[/color]
            > >
            > > Just stuff it into tp_dict? You'll need to make the method object
            > > yourself, but that's easy.
            > >
            > > I think you probably have to hope that the name of the class method
            > > isn't a special method name (you'd want to call
            > > typeobject.c:up date_slots then, but I don't think you can arrange for
            > > that to happen from outside typeobject.c as all the juicy symbols are
            > > static).[/color]
            >
            > No special names. Here's the code:
            >
            > static PyObject *my_method(PyOb ject *self, PyObject *arg)
            > {
            > Py_INCREF(arg);
            > return arg;
            > }
            >
            > static PyMethodDef my_methods[] = {
            > { "my_method" , my_method, METH_O },
            > { NULL, NULL },
            > };
            >
            > and then ('type' is the type where I want to create the class method on):
            >
            > if (somecondition) {
            > PyObject *func;
            > PyObject *meth;
            > PyMethodDef *ml = my_methods;
            >
            > for (; ml->ml_name; ++ml) {
            > func = PyCFunction_New (ml, NULL);
            > if (!func)
            > return NULL;
            > meth = PyClassMethod_N ew(func);[/color]

            How about "meth = PyDescr_NewClas sMethod(result, ml);" here?
            [color=blue]
            > if (!meth)
            > return NULL;
            > if (-1 == PyDict_SetItemS tring(result->tp_dict,
            > ml->ml_name,
            > meth))
            > return NULL;
            > }
            > }
            >
            > I know that there are refcount leaks in this snippet, but that's not the
            > point.
            >
            > Trying out the method:
            >
            > c:\sf\ctypes>py 23 -c "from ctypes import *; print c_int.my_method ()"
            > <class 'ctypes.c_int'>
            >
            > c:\sf\ctypes>py 23 -c "from ctypes import *; print c_int.my_method (0)"
            > Traceback (most recent call last):
            > File "<string>", line 1, in ?
            > TypeError: my_method() takes exactly one argument (2 given)
            > c:\sf\ctypes>
            >
            > Works *nearly*, but I would have expected that the method accepts one
            > parameter, pass it as 'arg' to the C function, plus the type itself as
            > 'self'.[/color]

            Oh... I wouldn't have :-)
            [color=blue][color=green]
            > > Or just stick TP_HEAPTYPE into tp_flags, use PyObject_SetAtt r and take
            > > TP_HEAPTYPE out again (that's very sick, though).[/color]
            >
            > Um, why that?[/color]

            Well, if "my_method" was spelt "__add__", say, you'd want to call
            typeobject.c:up date_slots() to get the function into the
            tp_as_number.nb _add fields of the type and all the subclasses. The
            hack I outline is one way of doing that.

            Cheers,
            mwh

            --
            Every now and then, Google doesn't throw up what I need so I start
            checking Altavista, Yahoo, etc. In almost every single case, I am
            brutally reminded why I use Google in the first place.
            -- John Riddoch, asr

            Comment

            • Thomas Heller

              #7
              Re: Defining *class* methods on C code

              [color=blue][color=green]
              >> if (somecondition) {
              >> PyObject *func;
              >> PyObject *meth;
              >> PyMethodDef *ml = my_methods;
              >>
              >> for (; ml->ml_name; ++ml) {
              >> func = PyCFunction_New (ml, NULL);
              >> if (!func)
              >> return NULL;
              >> meth = PyClassMethod_N ew(func);[/color]
              >
              > How about "meth = PyDescr_NewClas sMethod(result, ml);" here?
              >[/color]

              Yes, that works. But it's not in Python 2.2, which is required ;-(

              Thanks,

              Thomas

              Comment

              • Andrew MacIntyre

                #8
                Re: Defining *class* methods on C code

                On Fri, 6 Feb 2004, Thomas Heller wrote:
                [color=blue]
                > I have to call PyDescr_NewClas sMethodType:[/color]

                File a doc bug? I can't find this in the 2.3.3 docs at all...

                --
                Andrew I MacIntyre "These thoughts are mine alone..."
                E-mail: andymac@bullsey e.apana.org.au (pref) | Snail: PO Box 370
                andymac@pcug.or g.au (alt) | Belconnen ACT 2616
                Web: http://www.andymac.org/ | Australia

                Comment

                • Michael Hudson

                  #9
                  Re: Defining *class* methods on C code

                  Thomas Heller <theller@python .net> writes:
                  [color=blue][color=green][color=darkred]
                  > >> if (somecondition) {
                  > >> PyObject *func;
                  > >> PyObject *meth;
                  > >> PyMethodDef *ml = my_methods;
                  > >>
                  > >> for (; ml->ml_name; ++ml) {
                  > >> func = PyCFunction_New (ml, NULL);
                  > >> if (!func)
                  > >> return NULL;
                  > >> meth = PyClassMethod_N ew(func);[/color]
                  > >
                  > > How about "meth = PyDescr_NewClas sMethod(result, ml);" here?
                  > >[/color]
                  >
                  > Yes, that works. But it's not in Python 2.2, which is required ;-([/color]

                  Arghl. I guess you can just steal the relavent code... wasn't it your
                  patch in the first place that implemented all this?

                  Cheers,
                  mwh

                  --
                  $ head -n 2 src/bash/bash-2.04/unwind_prot.c
                  /* I can't stand it anymore! Please can't we just write the
                  whole Unix system in lisp or something? */
                  -- spotted by Rich van der Hoff

                  Comment

                  • Thomas Heller

                    #10
                    Re: Defining *class* methods on C code

                    Michael Hudson <mwh@python.net > writes:
                    [color=blue]
                    > Thomas Heller <theller@python .net> writes:
                    >[color=green][color=darkred]
                    >> >> if (somecondition) {
                    >> >> PyObject *func;
                    >> >> PyObject *meth;
                    >> >> PyMethodDef *ml = my_methods;
                    >> >>
                    >> >> for (; ml->ml_name; ++ml) {
                    >> >> func = PyCFunction_New (ml, NULL);
                    >> >> if (!func)
                    >> >> return NULL;
                    >> >> meth = PyClassMethod_N ew(func);
                    >> >
                    >> > How about "meth = PyDescr_NewClas sMethod(result, ml);" here?
                    >> >[/color]
                    >>
                    >> Yes, that works. But it's not in Python 2.2, which is required ;-([/color]
                    >
                    > Arghl. I guess you can just steal the relavent code... wasn't it your
                    > patch in the first place that implemented all this?[/color]

                    No, it was my feature request. IIRC, it was implemented by Fred Drake.

                    Thomas

                    Comment

                    • Thomas Heller

                      #11
                      Re: Defining *class* methods on C code

                      Thomas Heller <theller@python .net> writes:
                      [color=blue]
                      > Michael Hudson <mwh@python.net > writes:
                      >[color=green]
                      >> Thomas Heller <theller@python .net> writes:
                      >>[color=darkred]
                      >>> >> if (somecondition) {
                      >>> >> PyObject *func;
                      >>> >> PyObject *meth;
                      >>> >> PyMethodDef *ml = my_methods;
                      >>> >>
                      >>> >> for (; ml->ml_name; ++ml) {
                      >>> >> func = PyCFunction_New (ml, NULL);
                      >>> >> if (!func)
                      >>> >> return NULL;
                      >>> >> meth = PyClassMethod_N ew(func);
                      >>> >
                      >>> > How about "meth = PyDescr_NewClas sMethod(result, ml);" here?
                      >>> >
                      >>>
                      >>> Yes, that works. But it's not in Python 2.2, which is required ;-([/color]
                      >>
                      >> Arghl. I guess you can just steal the relavent code... wasn't it your
                      >> patch in the first place that implemented all this?[/color]
                      >
                      > No, it was my feature request. IIRC, it was implemented by Fred Drake.[/color]

                      Guess I'm getting old. It *was* my patch ;-)

                      Thomas

                      Comment

                      • Thomas Heller

                        #12
                        Re: Defining *class* methods on C code

                        Andrew MacIntyre <andymac@bullse ye.apana.org.au > writes:
                        [color=blue]
                        > On Fri, 6 Feb 2004, Thomas Heller wrote:
                        >[color=green]
                        >> I have to call PyDescr_NewClas sMethodType:[/color]
                        >
                        > File a doc bug? I can't find this in the 2.3.3 docs at all...[/color]

                        I've checked it in directly, but only the function prototype.

                        Thomas

                        Comment

                        • Michael Hudson

                          #13
                          Re: Defining *class* methods on C code

                          Thomas Heller <theller@python .net> writes:
                          [color=blue]
                          > Thomas Heller <theller@python .net> writes:
                          >[color=green]
                          > > Michael Hudson <mwh@python.net > writes:
                          > >[color=darkred]
                          > >> Arghl. I guess you can just steal the relavent code... wasn't it your
                          > >> patch in the first place that implemented all this?[/color]
                          > >
                          > > No, it was my feature request. IIRC, it was implemented by Fred Drake.[/color]
                          >
                          > Guess I'm getting old. It *was* my patch ;-)[/color]

                          :-)

                          Cheers,
                          mwh

                          --
                          at any rate, I'm satisfied that not only do they know which end of
                          the pointy thing to hold, but where to poke it for maximum effect.
                          -- Eric The Read, asr, on google.com

                          Comment

                          Working...