J
Jp Calderone
In trying to update some code built on top of reload(), I've hit a point
of confusion in how it is determined whether or not __class__ is allowed to
be rebound.
Consider, for example:
... __slots__ = 'a', 'b'
... ... __slots__ = 'a', 'b'
... Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: __class__ assignment: 'Bar' object layout differs from 'Foo'
The cause of this particular error does not actually seem to be that the
object layouts of Bar and Foo are incompatible, but rather that the object
layouts of _object_ and Foo are incompatible.
I've tracked down the point of rejection to same_slots_added
(Objects/typeobject.c:2347 or thereabouts):
static int
same_slots_added(PyTypeObject *a, PyTypeObject *b)
{
PyTypeObject *base = a->tp_base;
int size;
if (base != b->tp_base)
return 0;
if (equiv_structs(a, base) && equiv_structs(b, base))
return 1;
size = base->tp_basicsize;
if (a->tp_dictoffset == size && b->tp_dictoffset == size)
size += sizeof(PyObject *);
if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size)
size += sizeof(PyObject *);
return size == a->tp_basicsize && size == b->tp_basicsize;
}
I do not understand why the final line is comparing size against each of a
and b's tp_basicsize, rather than perfoming some comparison between a and b
directly.
Can anyone enlighten me?
Jp
of confusion in how it is determined whether or not __class__ is allowed to
be rebound.
Consider, for example:
... __slots__ = 'a', 'b'
... ... __slots__ = 'a', 'b'
... Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: __class__ assignment: 'Bar' object layout differs from 'Foo'
The cause of this particular error does not actually seem to be that the
object layouts of Bar and Foo are incompatible, but rather that the object
layouts of _object_ and Foo are incompatible.
I've tracked down the point of rejection to same_slots_added
(Objects/typeobject.c:2347 or thereabouts):
static int
same_slots_added(PyTypeObject *a, PyTypeObject *b)
{
PyTypeObject *base = a->tp_base;
int size;
if (base != b->tp_base)
return 0;
if (equiv_structs(a, base) && equiv_structs(b, base))
return 1;
size = base->tp_basicsize;
if (a->tp_dictoffset == size && b->tp_dictoffset == size)
size += sizeof(PyObject *);
if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size)
size += sizeof(PyObject *);
return size == a->tp_basicsize && size == b->tp_basicsize;
}
I do not understand why the final line is comparing size against each of a
and b's tp_basicsize, rather than perfoming some comparison between a and b
directly.
Can anyone enlighten me?
Jp