Bug? Feature? setattr(foo, '3', 4) works!

Terry Reedy tjreedy at udel.edu
Fri Dec 19 08:50:54 EST 2014


On 12/19/2014 6:40 AM, Cem Karan wrote:
> I'm bringing this discussion over from the python-ideas mailing list
> to see what people think. I accidentally discovered that the
> following works, at least in Python 3.4.2:
>
>>>> class foo(object):
> ...     pass ...
>>>> setattr(foo, '3', 4) dir(foo)
> ['3', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__',
> '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
> '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__',
> '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
> '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>>> getattr(foo, '3')
> 4
>>>> bar = foo() dir(bar)
> ['3', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__',
> '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
> '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__',
> '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
> '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>>> getattr(bar, '3')
> 4
>>>> hasattr(foo, '3')
> True
>>>> hasattr(bar, '3')
> True

The fact that one has set and retrieve non-identifier attributes has 
always been true and known and discussed before.  Guido has declared 
that it should continue to work rather than break code that uses this 
fact (and their is apparently such).  This follows under Python's 
'consenting adults' policy.

The attribute 'name' is type-checked to be a string.

 >>> class C: pass

 >>> c = C()
 >>> setattr(c, 3, '3')
Traceback (most recent call last):
   File "<pyshell#3>", line 1, in <module>
     setattr(c, 3, '3')
TypeError: attribute name must be string, not 'int'
 >>> setattr(c, b'3', '3')
Traceback (most recent call last):
   File "<pyshell#4>", line 1, in <module>
     setattr(c, b'3', '3')
TypeError: attribute name must be string, not 'bytes'

If one accesses the dict directly, even the string limitation is 
bypassed, but one suffers the consequences.

 >>> c.__dict__[3] = 3
 >>> dir(c)
Traceback (most recent call last):
   File "<pyshell#9>", line 1, in <module>
     dir(c)
TypeError: unorderable types: int() < str()

> Thoughts?

Don't pursue this.  Leave good enough alone.

-- 
Terry Jan Reedy




More information about the Python-list mailing list