Regarding __slots__ and other stuff: A couple of questions

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Thu Mar 27 15:33:06 EDT 2008


En Thu, 27 Mar 2008 11:27:42 -0300, dave berk <dave.brk at gmail.com>  
escribió:

> *first:*
> Why doesn't this works?
> <code>
>>>> class C(object):
> ... __slots__ = ['foo', 'bar']
> ... class_attr = 'class attribute'
> ...
>>>> c = C()
>>>> c.foo = 'foo'
>>>> c.bar = 'bar'
>>>> c.bar, c.foo
> ('bar', 'foo')
>>>> c.__slots__
> ['foo', 'bar']
>>>> c.__slots__.append('eggs')
>>>> c.__slots__
> ['foo', 'bar', 'eggs']
>>>> c.eggs = 'eggs'
> Traceback (innermost last):
> File "<stdin>", line 1, in <module>
> AttributeError: 'C' object has no attribute 'eggs'
> </code>

Because the __slots__ attribute is used when the object is constructed, to  
reserve space in its structure for those (and only those) attributes.  
That's the whole point of using __slots__: not creating the generic  
__dict__ container for all instances to save memory.

> *second:*
> what happens here? Why can I write to spam using the class object but not
> the using the instance?
> <code>
>>>> class C(object):
> ... __slots__ = ['foo', 'bar']
> ... class_attr = 'class attribute'
> ...
>>>> C.spam = 50
>>>> C.spam
> 50
>>>> C.spam = 56
>>>> c = C()
>>>> c.spam = 55
> Traceback (innermost last):
> File "<stdin>", line 1, in <module>
> AttributeError: 'C' object attribute 'spam' is read-only

C *instances* are affected by the __slots__ defined in the C *class*, but  
the C class itself is not. The C class would be affected by a __slots__  
defined in its type (the metatype) but since there exist only one C class  
object, that optimization would be useless. If you were dynamically  
creating thousands of classes one might consider the point...

> *Third:*
> <code>
> class RevealAccess(object):
> """A data descriptor that sets and returns values
> normally and prints a message logging their access.
> """
>
> def __init__(self, initval=None, name='var'):
> self.val = initval
> self.name = name
>
> def __get__(self, obj, objtype):
> print 'Retrieving', self.name
> return self.val
>
> def __set__(self, obj, val):
> print 'Updating' , self.name
> self.val = val
> class A(object):
> def __init__(self):
> self.x = RevealAccess(10, 'var "x"')
> self.y = 5
> class B(object):
> x = RevealAccess(10, 'var "x"')
> y = 5
>
>>>> a = A()
>>>> b = B()
>>>> a.x
> <__main__.RevealAccess object at 0x00BAC730>
>>>> a.x = 55
>>>> b.x
> Retrieving var "x"
> 10
>>>> b.x = 55
> Updating var "x"
>>>>
> </code>
> Why the descriptor works only when created as a static variable and not
> as an instance variable?

It's not a "static variable", it's a "class attribute". Classes are  
objects too, like functions, methods, code... [almost] everything in  
Python is an object.
The descriptor protocol isn't used when retrieving attributes directly  
 from the instance namespace (__dict__), this is a plain dict access. When  
you say self.x = RevealAccess(...) you are storing the RA instance  
directly in the instance namespace. Only when retrieving objects from the  
*class* the descriptor protocol comes into play.

-- 
Gabriel Genellina




More information about the Python-list mailing list