[Python-Dev] Change in evaluation order in new object model

Michael McLay mclay@nist.gov
Fri, 2 Nov 2001 14:02:27 -0400


On Friday 02 November 2001 11:22 am, M.-A. Lemburg wrote:
> Michael McLay wrote:
> > I was suprised by a change to the order of evaluation of members in the
> > new object type.  I haven't found an explanation for why the change was
> > made.  I was comfortable with the way it worked.  Is there an advantage
> > to the change?.
> >
> > In the classic python model the interpreter looked in the instance
> > dictionary and if the name wasn't there it looked in the class
> > dictionary.  The following illustrates this evaluation order.
> > ...
> >
> > With the new slots mechanism the order has been reversed.  The class
> > level dictionary is searched and then the slots are evaluated.
> >
> > >>> class B(object):
> >
> >     __slots__ = ['a','b','c']
> >
> > >>> b = B()
> > >>> b.a = 4
> > >>> b.a
> >
> > 4
> >
> > >>> B.a = 6
> > >>> b.a
> >
> > 6
> >
> > >>> b.a = 8
> >
> > Traceback (most recent call last):
> >   File "<pyshell#61>", line 1, in ?
> >     b.a = 8
> > AttributeError: 'B' object attribute 'a' is read-only
>
> Could someone please first explain what these slots are used for
> in the first place :-? There must be some difference to standard
> class attributes... which is probably also the reason for the
> above behaviour (even though it does look like a bug to me).

Classes defined with slots do not use a __dict__ to hold the content of the 
class.  Instead an instance of a type includes a table with one entry per 
slot name.  The "member descriptor"  for each slot defines the offset into 
the table for that slot. 

The size of each instances is reduced by the elimination of the __dict__.  
The lookup of a member is also faster because it uses a lookup of an offset 
instead of a dictionary lookup.  The following example shows some of the 
characteristics of slots.

>>> class B(object):
    __slots__ = ['a','b','c']

>>> b.__dict__
Traceback (most recent call last):
  File "<pyshell#85>", line 1, in ?
    b.__dict__
AttributeError: 'B' object has no attribute '__dict__'
>>> dir(b)
['__class__', '__delattr__', '__getattribute__', '__hash__', '__init__', 
'__module__', '__new__', '__reduce__', '__repr__', '__setattr__', 
'__slots__', '__str__', 'a', 'b', 'c']

The slot returns a None value if it is referenced before it is initialized

>>> b = B()
>>> b.a
>>> b.a = 3
>>> b.a
3

If a reference is made to an undefined slot an AttributeError is generated.

>>> b.d = 5
Traceback (most recent call last):
  File "<pyshell#100>", line 1, in ?
    b.d = 5
AttributeError: 'B' object has no attribute 'd'


The declaration of slots using __slots__ is somewhat awkward and Guido's 
comment about the syntax indicates this may change. One immediate problem 
with the syntax is that it doesn't support associating doc strings with slot 
names.

Andrew described an example of how the descriptor[1] capability will allow 
Python to be extended in interesting ways.  It turns out to be relatively 
easy to extend the descriptor capability. I submitted a patch yesterday that 
adds  support for doc strings and optional type checking to the members 
defined by slots.  The syntax to add the new capabilities is similar to the 
__slots__, but uses dictionaries to assign the values.

class B(object):
    __slots__ = ['a','b','c']
    __slot_docs__ = {'a':"doc string for a", 'b' : "doc string for b"}
    __slot_types__ = {'a':(int,str), 'c':int, }

[1] http://www.amk.ca/python/2.2/index.html#SECTION000320000000000000000