[Python-Dev] PEP 252 comment

Michael McLay mclay@nist.gov
Mon, 5 Nov 2001 12:54:10 -0500


The potential for optimizing the new class/type sytem in Python can be 
improved by adding an additional constraint to the name lookup rules[1].  
This new constrain only apply to the new name lookup rules for types that 
include __slots__ definitions so the change should not break backward 
compatibility.

 - Any name defined by __slot__  is not allowed as a key in the type
   dict. This rule would eliminate special type attribute names, like
   __dict__ and __class__, from the names allowed in __slots__.

The constraint would also make it illegal to injected a name into the type 
dictionary from outside the class definition if that name is one of the  
names in _slots__.

In the following example the costraint would allow the assignment to B.d, but 
not the assignment to B.b.  The assignment of 'c=5' would trigger a TypeError 
because the c is defined in __slots__.  The '__dict__' in __slots__ would 
also trigger a type error because it is a special attribute name that is 
defined for all types.

>>> class B(object):
	a = 3
	c = 5
	__slots__ = ['b', '__dict__' , 'c']
	def __init__(self):
		self.b = 4
		
>>> B.d = 'fish'
>>> b = B()
>>> b.b
4
>>> b.d
'fish'
>>> B.b = 3.2
>>> b.b
3.2000000000000002
>>> b.b = 55
Traceback (most recent call last):
  File "<pyshell#29>", line 1, in ?
    b.b = 55
AttributeError: 'B' object attribute 'b' is read-only
>>> 

The rule eliminates the need to look in the type dictionary if the name is 
defined in __slots__.  The cryptic AttributeError message in the example 
would never occur.

A slightly more restrictive rule would extend the constraint to eliminate any 
addition of names to the type dict from outside of the class definition.  
This additional constraint would make the assignment to B.d illegal in the 
previous example. This rule would make it possible to know the complete list 
of all names that could be referenced by an object of the given type.  

[1] From http://python.sourceforge.net/peps/pep-0252.html

  In the more complicated case, there's a conflict between names
      stored in the instance dict and names stored in the type dict.
      If both dicts have an entry with the same key, which one should
      we return?  Looking at classic Python for guidance, I find
      conflicting rules: for class instances, the instance dict
      overrides the class dict, *except* for the special attributes
      (like __dict__ and __class__), which have priority over the
      instance dict.

 - I resolved this with the following set of rules, implemented in
      PyObject_GenericGetAttr():

      1. Look in the type dict.  If you find a *data* descriptor, use
         its get() method to produce the result.  This takes care of
         special attributes like __dict__ and __class__.

      2. Look in the instance dict.  If you find anything, that's it.
         (This takes care of the requirement that normally the
         instance dict overrides the class dict.)

      3. Look in the type dict again (in reality this uses the saved
         result from step 1, of course).  If you find a descriptor,
         use its get() method; if you find something else, that's it;
         if it's not there, raise AttributeError.