classification
Title: strange interaction between __slots__ and class-level attributes
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.2, Python 3.3
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: benjamin.peterson, pitrou, python-dev
Priority: normal Keywords:

Created on 2011-08-16 22:44 by pitrou, last changed 2011-08-16 23:53 by python-dev. This issue is now closed.

Messages (8)
msg142232 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-08-16 22:44
>>> class Foo:
...    __slots__ = ['foo']
...    foo = None
... 
>>> x = Foo()
>>> x.foo
>>> x.foo = 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object attribute 'foo' is read-only
msg142234 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2011-08-16 23:09
This sort of thing is true of any slotted class with class attributes:

>>> class X:
...     __slots__ = ()
...     foo = None
... 
>>> X().foo = "hello"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'X' object attribute 'foo' is read-only

I think what needs to happen is the error message needs to be improved in both cases.
msg142235 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-08-16 23:13
> This sort of thing is true of any slotted class with class attributes:
> 
> >>> class X:
> ...     __slots__ = ()
> ...     foo = None
> ... 
> >>> X().foo = "hello"
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> AttributeError: 'X' object attribute 'foo' is read-only

But that's quite different. In your example, the attribute can't be set
on the instance, while it should be in mine (since 'foo' is amongst the
__slots__).
msg142236 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2011-08-16 23:16
So would you prefer to see

>>> x.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: foo
>>> x.foo = 5
>>> x.foo
5
?
msg142237 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-08-16 23:20
> So would you prefer to see
> 
> >>> x.foo
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> AttributeError: foo
> >>> x.foo = 5
> >>> x.foo
> 5
> ?

No, I would prefer to see

True
>>> x.foo = 5
>>> x.foo
5

... exactly as in the same class without a __slots__

(the whole point of class attributes being to set default values without
complicating the constructor)
msg142238 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2011-08-16 23:29
I'm afraid that's not (easily) possible. Using __slots__ implicitly gives classes attributes, so what you are seeing is the effect of toying with that. It's not really possible to pretend there are different attributes on the class than the descriptors. We can:

- Silently override slot descrs with attributes (as currently done).
- Warn or error out on conflicts.
- Just override other class attributes with the descrs.
msg142239 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-08-16 23:32
> I'm afraid that's not (easily) possible. Using __slots__ implicitly
> gives classes attributes, so what you are seeing is the effect of
> toying with that. It's not really possible to pretend there are
> different attributes on the class than the descriptors. We can:
> 
> - Silently override slot descrs with attributes (as currently done).
> - Warn or error out on conflicts.
> - Just override other class attributes with the descrs.

Erroring on conflicts would seem reasonable. If that threatens to break
existing code, at least improving the current error message would be
nice.
msg142240 - (view) Author: Roundup Robot (python-dev) Date: 2011-08-16 23:53
New changeset 45b63a8a76c9 by Benjamin Peterson in branch 'default':
complain when a class variable shadows a name in __slots__ (closes #12766)
http://hg.python.org/cpython/rev/45b63a8a76c9
History
Date User Action Args
2011-08-16 23:53:37python-devsetstatus: open -> closed

nosy: + python-dev
messages: + msg142240

resolution: fixed
stage: resolved
2011-08-16 23:32:05pitrousetmessages: + msg142239
2011-08-16 23:29:44benjamin.petersonsetmessages: + msg142238
2011-08-16 23:20:01pitrousetmessages: + msg142237
2011-08-16 23:16:47benjamin.petersonsetmessages: + msg142236
2011-08-16 23:13:13pitrousetmessages: + msg142235
2011-08-16 23:09:33benjamin.petersonsetmessages: + msg142234
2011-08-16 22:44:41pitroucreate