Assignments to __class_ broken in Python 2.5?

samwyse samwyse at gmail.com
Fri Jul 13 07:56:10 CEST 2007


On Jul 12, 11:48 am, samwyse <samw... at gmail.com> wrote:
> On Jul 12, 6:31 am,samwyse<samw... at gmail.com> wrote:
>
> > On Jul 8, 8:50 am, Christoph Zwerschke <c... at online.de> wrote:
>
> > > With Py 2.5 I get:
>
> > >      new.__class__ = old.__class__
> > > TypeError: __class__ must be set to a class
>
> Hmmm, under Python 2.4.X, printing repr(old.__class__) gives me this:
>   <class exceptions.UnicodeDecodeError at 0x00A24F00>
> while under 2.5.X, I get this:
>   <type 'exceptions.UnicodeDecodeError'>
>
> So, let's try sub-classing the type:
>
> def modify_message(old, f):
>     class Empty: pass
>     new = Empty()
>     print "old.__class__ =", repr(old.__class__)
>     print "Empty =", repr(Empty)
>     new.__class__ = Empty
>
>     class Excpt(old.__class__): pass
>     print "Excpt =", repr(Excpt)
>     print "Excpt.__class__ =", repr(Excpt.__class__)
>     new.__class__ = Excpt
>
>     new.__dict__ = old.__dict__.copy()
>     new.__str__ = f
>     return new
>
> Nope, that gives us the same message:
>
> old.__class__ = <type 'exceptions.UnicodeDecodeError'>
> Empty = <class __main__.Empty at 0x00AB0AB0>
> Excpt = <class '__main__.Excpt'>
> Excpt.__class__ = <type 'type'>
> Traceback (most recent call last):
> [...]
> TypeError: __class__ must be set to a class
>
> Excpt certainly appears to be a class.  Does anyone smarter than me
> know what's going on here?

OK, in classobject.h, we find this:

#define PyClass_Check(op) ((op)->ob_type == &PyClass_Type)

That seems straightforward enough.  And the relevant message appears
in classobject.c here:

static int
instance_setattr(PyInstanceObject *inst, PyObject *name, PyObject *v)
[...]
    if (strcmp(sname, "__class__") == 0) {
        if (v == NULL || !PyClass_Check(v)) {
            PyErr_SetString(PyExc_TypeError,
               "__class__ must be set to a class");
            return -1;
        }

Back in our test code, we got these:
> Empty = <class __main__.Empty at 0x00AB0AB0>
> Excpt = <class '__main__.Excpt'>

The first class (Empty) passes the PyClass_Check macro, the second one
(Excpt) evidently fails.  I'll need to dig deeper.  Meanwhile, I still
have to wonder why the code doesn't allow __class_ to be assigned a
type instead of a class.  Why can't we do this in the C code (assuming
the appropriate PyType_Check macro):

        if (v == NULL || !(PyClass_Check(v) || PyType_Check(v))) {




More information about the Python-list mailing list