Ewald R. de Wit wrote: > I'm running into a something unexpected for a new-style class > that has both a class attribute and __slots__ defined. If the > name of the class attribute also exists in __slots__, Python > throws an AttributeError. Is this by design (if so, why)? > > class A( object ): > __slots__ = ( 'value', ) > value = 1 > > def __init__( self, value = None ): > self.value = value or A.value > > a = A() > print a.value > > > Traceback (most recent call last): > File "t1.py", line 8, in ? > a = A() > File "t1.py", line 6, in __init__ > self.value = value or A.value > AttributeError: 'A' object attribute 'value' is read-only
Check the documentation on __slots__[1]: __slots__ are implemented at the class level by creating descriptors (3.3.2) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __slots__; otherwise, the class attribute would overwrite the descriptor assignment. I agree that the error you get is a bit confusing. I think this has to do with how the descriptor machinery works. When you write something like a.value where a is a class instance, Python tries to invoke something like: type(a).value.__get__(a) Here's an example of that, working normallly: py> class A(object): ... __slots__ = ['value'] ... def __init__(self): ... self.value = 1 ... py> a = A() py> type(a).value <member 'value' of 'A' objects> py> type(a).value.__get__ <method-wrapper object at 0x0129A1B0> py> type(a).value.__get__(a) 1 Now when you add a class attribute called 'value', you overwrite the descriptor. So when Python tries to do the same thing (because your definition of __slots__ makes it assume that 'value' is a descriptor), the descriptor machinery raises an AttributeError: py> class A(object): ... __slots__ = ['value'] ... value = 1 ... py> a = A() py> type(a).value 1 py> type(a).value.__get__ Traceback (most recent call last): File "<interactive input>", line 1, in ? AttributeError: 'int' object has no attribute '__get__' This AttributeError must be somehow caught by the __slots__ machinery and interpreted to mean that you tried to write to a read-only attribute. The resulting error message is probably not what you want, but I don't know the source well enough to figure out whether or not a better error message could be given. But why do you want a class level attribute with the same name as an instance level attribute? I would have written your class as: class A(object): __slots__ = ['value'] def __init__(self, value=1): self.value = value where the default value you put in the class is simply expressed as a default value to the __init__ parameter. Steve [1]http://docs.python.org/ref/slots.html -- http://mail.python.org/mailman/listinfo/python-list