The Python Oracle

Reason for allowing Special Characters in Python Attributes

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Melt

--

Chapters
00:00 Reason For Allowing Special Characters In Python Attributes
01:40 Accepted Answer Score 5
02:44 Answer 2 Score 2
04:36 Thank you

--

Full question
https://stackoverflow.com/questions/3827...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #leastastonishment

#avk47



ACCEPTED ANSWER

Score 5


I think that your assumption that attributes must be "identifiers" is incorrect. As you've noted, python objects support arbitrary attributes (not just identifiers) because for most objects, the attributes are stored in the instance's __dict__ (which is a dict and therefore supports arbitrary string keys). However, in order to have an attribute access operator at all, the set of names that can be accessed in that way needs to be restricted to allow for the generation of a syntax that can parse it.

Is it simply assumed that, if you have to use setattr to set the variable, you are going to reference it via getattr?

No. I don't think that's assumed. I think that the assumption is that if you're referencing attributes using the . operator, then you know what those attributes are. And if you have the ability to know what those attributes are, then you probably have control over what they're called. And if you have control over what they're called, then you can name them something that the parser knows how to handle ;-).




ANSWER 2

Score 2


I see that feature of the language as an unintended side-effect of how the language is implemented.

There are several issues which suggest the feature is a side-effect.

First, from the "Zen of Python":

There should be one-- and preferably only one --obvious way to do it.

For me, the obvious way to access an attribute is with . operator. Thus, I consider names incompatible with the operator illegal as they require "hacks" to use them.

Second, despite we can have integer key in the instance's __dict__ (as pointed by Mark Ransom), I do not consider int to be a valid attribute name. Especially that it breaks the object behaviour:

>>> a.__dict__[12] = 42
>>> dir(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()

Third, it is not completely true what Python documentation claims about the . operator and the getattr() builtin equivalence. The difference is in the resulting bytecode. The former compiles to LOAD_ATTR bytecode, while the latter - to CALL_FUNCTION:

>>> dis.dis(lambda x: x.a)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_ATTR                0 (a)
              6 RETURN_VALUE
>>> dis.dis(lambda x: getattr(x, 'a'))
  1           0 LOAD_GLOBAL              0 (getattr)
              3 LOAD_FAST                0 (x)
              6 LOAD_CONST               1 ('a')
              9 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
         12 RETURN_VALUE

Same applies to the setattr() builtin. Thus, I see builtins as a kind of walkarround introduced to facilitate dynamic attribute access (the builtin was absent in Python 0.9.1).

Finally, the following code (declaring __slots__ attributes) fails:

>>> class A(object):
...     __slots__ = ['a.b']
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __slots__ must be identifiers

which suggests that attribute names are supposed to be identifiers.

However, since I can not find any formal syntax for allowed attribute names, I also see the point raised by @mgilson valid.