[Python-Dev] Adding __format__ to classic classes

Eric Smith eric+python-dev at trueblade.com
Thu Feb 14 02:31:06 CET 2008


[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.




More information about the Python-Dev mailing list