[Python-Dev] Adding __format__ to classic classes

Guido van Rossum guido at python.org
Thu Feb 14 05:09:58 CET 2008


Try this:

if (PyInstance_Check(obj)) {
  bound_method = PyObject_GetAttr(obj,  str__format__);
  if (!bound_method)
  return NULL;
  <call it passing only the format string>
  Py_DECREF(bound_method);
  return <whatever the call returned>
}
else {
  do it the py3k way;
}


On Feb 13, 2008 5:31 PM, Eric Smith <eric+python-dev at trueblade.com> wrote:
> [slight mailer problem, this might show up as a dupe.  sorry]
> Guido van Rossum wrote:
> > On Feb 13, 2008 2:57 PM, Eric Smith <eric+python-dev at trueblade.com> wrote:
> >> Guido van Rossum wrote:
> >>> On Feb 13, 2008 2:20 PM, Eric Smith <eric+python-dev at trueblade.com> wrote:
> >>>> Nick Coghlan wrote:
> >>>>> However, the source code for cPickle may provide some ideas (when it
> >>>>> looks up _reduce__/__getstate__/etc).
> >>>> Those do look promising.  Thanks!
> >>> Or look in classobject.c itself; e.g. instance_str().
> >> It uses a static helper function instance_getattr(), which while it
> >> looks like what I want, I can't get to.
> >
> > Well, it just implements PyObject_GetAttr for classic class instances...
> >
> >> So I've come up with the following.  I haven't checked for leaks yet,
> >> but at least it appears to do what I want, for both classic and
> >> new-style classes.  I'm still porting over test cases from 3.0, so I'm
> >> not convinced this is correct, yet.
> >>
> >> /* Check for a __format__ method. */
> >> meth = PyObject_GetAttr(value, str__format__);
> >> if (meth)
> >>      result = PyObject_CallFunctionObjArgs(meth, spec, NULL);
> >> else {
> >
> > You'd need PyErr_Clear() here the way this is written.
>
> Okay.
>
> > But the
> > following call is redundant -- if that _PyType_Lookup() call finds
> > something, PyObject_GetAttr() will have found that too (or something
> > else).
> >
> >>      meth = _PyType_Lookup(Py_TYPE(value), str__format__);
> >>      if (meth)
> >>          result = PyObject_CallFunctionObjArgs(meth, value, spec, NULL);
> >>      else {
> >>         PyErr_Format(PyExc_TypeError,
> >>                  "Type %.100s doesn't define __format__",
> >>                  Py_TYPE(value)->tp_name);
> >>          goto done;
> >>      }
> >> }
>
> Yes, but what's the "or something else", and is it the right thing?  Are
> you saying I should call _PyType_Lookup first?  But that's how I
> started: if I do it that way, I can't override __format__ in a classic
> class.  As the code stands (PyObject_GetAttr then _PyType_Lookup), it's
> definitely true that _PyType_Lookup will succeed when PyObject_GetAttr
> will have failed.
>
> Or should the logic be:
> if is-new-style-class(Py_TYPE(value)):
>     lookup method with _PyType_Lookup(Py_TYPE(value))
> else:
>     lookup method with PyObject_GetAttr(value)
>
> And if so, how to test for "is-new-style-class"?
>
> Sorry to be wasting your time, but I'm don't understand all of the
> issues trying to support both new and classic classes in C.  I think
> I'll get the rest of PEP 3101 working, then come back to this issue.
> It's pretty well contained.  I'll spend some time understanding
> classobject.c's implementation.  It just seems like it shouldn't be this
> hard to call a method (if it exists), given an instance.
>
> I think my confusion leads to this problem (if in fact it's a problem):
> >>> format(object, '')
> Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
> TypeError: __format__() takes exactly 1 argument (0 given)
> >>> format(object(), '')
> '<object object at 0x307408>'
> >>> ^D
>
> Which works in the py3k branch.
>
> > Since PyObject_GetAttr() sets an AttributeError exception already, I
> > question the benefit of setting a different exception.
>
> Agreed.
>
>
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
>



-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-Dev mailing list