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

I accidentally discovered that the following works, at least in Python 3.4.2:
However, the following doesn't work:
I'd like to suggest that getattr(), setattr(), and hasattr() all be modified so that syntactically invalid statements raise SyntaxErrors. On a related note, are numbers defined in a module, or they are part of interpreter? Just to see how awful I could make things, I tried to extend the above to redefine 3 to be 4. Fortunately (unfortunately?) I couldn't find a way, but I'm curious if there is a pythonic way of making this happen, and if there is, I'd like to suggest making that impossible ASAP. Thanks, Cem Karan

On Fri, Dec 19, 2014 at 3:27 PM, Cem Karan <cfkaran2@gmail.com> wrote:
I'd like to suggest that getattr(), setattr(), and hasattr() all be modified so that syntactically invalid statements raise SyntaxErrors.
Is there actually a need to have them check like that? :) After all, attributes are just stored in a dictionary. You want syntactically-invalid attributes? Sure, no problem.
On a related note, are numbers defined in a module, or they are part of interpreter? Just to see how awful I could make things, I tried to extend the above to redefine 3 to be 4. Fortunately (unfortunately?) I couldn't find a way, but I'm curious if there is a pythonic way of making this happen, and if there is, I'd like to suggest making that impossible ASAP.
Syntax comes first. If you want to play with redefinitions like that, it'd be simpler to stuff stuff into globals(), which is also simply a dictionary.
When you type 3, Python compiles that into the integer 3, not into a name lookup. Now, you *can* fiddle with this kind of thing using ctypes, though I don't know how many other interpreters (PyPy, Jython, etc) will let you shoot yourself in that particular foot. But if you'd like to play around with this kind of thing, check out the 'ast' module and try compiling code to AST, then fiddling with it a bit, then finishing compilation and execution. And python-list will probably enjoy discussing the random things you can accomplish with that :) It's good fun. ChrisA

On Dec 19, 2014, at 12:15 AM, Chris Angelico <rosuav@gmail.com> wrote:
Its only needed from a 'Principle of Least Astonishment' point of view. When I realized I could work my way around the syntax by using getattr()/setattr(), I was astonished. I really didn't expect it to work, and I would MUCH prefer that trying to use getattr()/setattr() in this way would have the exact same results as normal attribute access.
I feel a wave of morbid curiosity coming over me... I think I'm going to have to try that, just to see what I can do. I'm terrified to think that I might actually be able to make it happen... O_o. But, getting back to the main question, is this a bug or a feature? I personally feel like this is a bug, and I'd like to both clarify it in the language spec, and have cpython modified to enforce the syntax, regardless of how you try to mess with an attribute. How does everyone else feel about this? Thanks, Cem Karan

On 19 December 2014 at 20:57, Cem Karan <cfkaran2@gmail.com> wrote:
Namespaces are just dictionaries. The one thing implementations may do is to place a type restriction on the keys, so they throw TypeError if you try to use something other than str (although *CPython* doesn't do that). getattr/setattr/delattr would never throw SyntaxError though - that's only thrown by the compiler. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Dec 19, 2014, at 6:03 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
I see what you're saying, but I feel like having (get|set|has)attr throw TypeError instead of SyntaxError would itself be astonishing in this case. The feature I'm after is that "foo.3" results in exactly the same behavior as "getattr(foo, '3')". Thanks, Cem Karan

On 19 December 2014 at 23:46, Nick Coghlan <ncoghlan@gmail.com> wrote:
To elaborate on that a bit:
The ".a" attribute access syntax is ultimately just syntactic sugar for a dictionary lookup with the string 'a'. That syntactic sugar is what applies the restriction to being a valid identifier, not the underlying namespace object. Even for string values, you can do syntactically unacceptable lookups via the underlying namespace mapping:
You'll find that kind of behaviour in a few different areas - syntactic restrictions aren't actually present in the underlying runtime machinery, they only exist at compile time. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 19 December 2014 at 15:15, Chris Angelico <rosuav@gmail.com> wrote:
As far as I'm aware, it's actually an implementation defined behaviour - implementations are permitted, but not required, to use string-only dictionaries for namespaces. (Although I can't currently lay my hands on anything in the language reference that actually *says* that...) Most implementations will go with whichever is faster in their particular case (for CPython, that means using the standard permissive dict type, for Jython, it means only allowing strings, for other implementations, I'm not sure). CPython is highly unlikely to ever break compatibility over this, but it *is* a potential cross-implementation portability problem when folks rely on it. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Fri, Dec 19, 2014 at 10:00 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
What do you mean by "only allowing strings"? CPython doesn't allow non-string attributes, and Jython does allow non-identifier attributes: Jython 2.5.3 (, Oct 8 2014, 03:39:09) [OpenJDK 64-Bit Server VM (Oracle Corporation)] on java1.7.0_65 Type "help", "copyright", "credits" or "license" for more information.
Python 3.5.0a0 (default:64e45efdc3e2, Dec 11 2014, 11:52:01) [GCC 4.7.2] on linux Type "help", "copyright", "credits" or "license" for more information.
(I'm not sure why there's the empty string in the Jython version tag; this is what I got by apt-getting jython on Debian Jessie.) In any case, it's probably time this moved off python-ideas. ChrisA

On Fri, Dec 19, 2014 at 10:20 PM, Cem Karan <cfkaran2@gmail.com> wrote:
What's the best place to move it to? If this is a bug, I'll write up a bug report, but if this is a change in the language definition, then it might be best to keep it here.
python-list@python.org I think; basically, it's now chatting about the language, rather than dealing with a known and recognized bug. If, as a result of a python-list discussion, a language change is recommended, you can bring a post-discussion proposal back to python-ideas, but more likely we'll just chat happily and decide that no change is needed. :) ChrisA

On 19/12/14 05:27, Cem Karan wrote:
I'd like to suggest that getattr(), setattr(), and hasattr() all be modified so that syntactically invalid statements raise SyntaxErrors.
I'd like to object! This would break a lot of code that depends on HD5 and NetCDF databases, e.g. PyTables. Often we can do table.x but sometimes we need to do getattr(table,'some long field name') A lot of scientific software depends on this, and it would break at the moment your proposal is introduced. It would be a major disaster. It would even set back NASA's space program (no kidding!) Sturla

On Dec 22, 2014, at 7:43 AM, Sturla Molden <sturla.molden@gmail.com> wrote:
Yup, someone else pointed out that ctypes also relies on the current behavior, so I dropped the suggestion. (To the person that pointed about ctypes, I apologize about not giving you credit, but I deleted the email). Thanks, Cem Karan

On Fri, Dec 19, 2014 at 3:27 PM, Cem Karan <cfkaran2@gmail.com> wrote:
I'd like to suggest that getattr(), setattr(), and hasattr() all be modified so that syntactically invalid statements raise SyntaxErrors.
Is there actually a need to have them check like that? :) After all, attributes are just stored in a dictionary. You want syntactically-invalid attributes? Sure, no problem.
On a related note, are numbers defined in a module, or they are part of interpreter? Just to see how awful I could make things, I tried to extend the above to redefine 3 to be 4. Fortunately (unfortunately?) I couldn't find a way, but I'm curious if there is a pythonic way of making this happen, and if there is, I'd like to suggest making that impossible ASAP.
Syntax comes first. If you want to play with redefinitions like that, it'd be simpler to stuff stuff into globals(), which is also simply a dictionary.
When you type 3, Python compiles that into the integer 3, not into a name lookup. Now, you *can* fiddle with this kind of thing using ctypes, though I don't know how many other interpreters (PyPy, Jython, etc) will let you shoot yourself in that particular foot. But if you'd like to play around with this kind of thing, check out the 'ast' module and try compiling code to AST, then fiddling with it a bit, then finishing compilation and execution. And python-list will probably enjoy discussing the random things you can accomplish with that :) It's good fun. ChrisA

On Dec 19, 2014, at 12:15 AM, Chris Angelico <rosuav@gmail.com> wrote:
Its only needed from a 'Principle of Least Astonishment' point of view. When I realized I could work my way around the syntax by using getattr()/setattr(), I was astonished. I really didn't expect it to work, and I would MUCH prefer that trying to use getattr()/setattr() in this way would have the exact same results as normal attribute access.
I feel a wave of morbid curiosity coming over me... I think I'm going to have to try that, just to see what I can do. I'm terrified to think that I might actually be able to make it happen... O_o. But, getting back to the main question, is this a bug or a feature? I personally feel like this is a bug, and I'd like to both clarify it in the language spec, and have cpython modified to enforce the syntax, regardless of how you try to mess with an attribute. How does everyone else feel about this? Thanks, Cem Karan

On 19 December 2014 at 20:57, Cem Karan <cfkaran2@gmail.com> wrote:
Namespaces are just dictionaries. The one thing implementations may do is to place a type restriction on the keys, so they throw TypeError if you try to use something other than str (although *CPython* doesn't do that). getattr/setattr/delattr would never throw SyntaxError though - that's only thrown by the compiler. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Dec 19, 2014, at 6:03 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
I see what you're saying, but I feel like having (get|set|has)attr throw TypeError instead of SyntaxError would itself be astonishing in this case. The feature I'm after is that "foo.3" results in exactly the same behavior as "getattr(foo, '3')". Thanks, Cem Karan

On 19 December 2014 at 23:46, Nick Coghlan <ncoghlan@gmail.com> wrote:
To elaborate on that a bit:
The ".a" attribute access syntax is ultimately just syntactic sugar for a dictionary lookup with the string 'a'. That syntactic sugar is what applies the restriction to being a valid identifier, not the underlying namespace object. Even for string values, you can do syntactically unacceptable lookups via the underlying namespace mapping:
You'll find that kind of behaviour in a few different areas - syntactic restrictions aren't actually present in the underlying runtime machinery, they only exist at compile time. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 19 December 2014 at 15:15, Chris Angelico <rosuav@gmail.com> wrote:
As far as I'm aware, it's actually an implementation defined behaviour - implementations are permitted, but not required, to use string-only dictionaries for namespaces. (Although I can't currently lay my hands on anything in the language reference that actually *says* that...) Most implementations will go with whichever is faster in their particular case (for CPython, that means using the standard permissive dict type, for Jython, it means only allowing strings, for other implementations, I'm not sure). CPython is highly unlikely to ever break compatibility over this, but it *is* a potential cross-implementation portability problem when folks rely on it. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Fri, Dec 19, 2014 at 10:00 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
What do you mean by "only allowing strings"? CPython doesn't allow non-string attributes, and Jython does allow non-identifier attributes: Jython 2.5.3 (, Oct 8 2014, 03:39:09) [OpenJDK 64-Bit Server VM (Oracle Corporation)] on java1.7.0_65 Type "help", "copyright", "credits" or "license" for more information.
Python 3.5.0a0 (default:64e45efdc3e2, Dec 11 2014, 11:52:01) [GCC 4.7.2] on linux Type "help", "copyright", "credits" or "license" for more information.
(I'm not sure why there's the empty string in the Jython version tag; this is what I got by apt-getting jython on Debian Jessie.) In any case, it's probably time this moved off python-ideas. ChrisA

On Fri, Dec 19, 2014 at 10:20 PM, Cem Karan <cfkaran2@gmail.com> wrote:
What's the best place to move it to? If this is a bug, I'll write up a bug report, but if this is a change in the language definition, then it might be best to keep it here.
python-list@python.org I think; basically, it's now chatting about the language, rather than dealing with a known and recognized bug. If, as a result of a python-list discussion, a language change is recommended, you can bring a post-discussion proposal back to python-ideas, but more likely we'll just chat happily and decide that no change is needed. :) ChrisA

On 19/12/14 05:27, Cem Karan wrote:
I'd like to suggest that getattr(), setattr(), and hasattr() all be modified so that syntactically invalid statements raise SyntaxErrors.
I'd like to object! This would break a lot of code that depends on HD5 and NetCDF databases, e.g. PyTables. Often we can do table.x but sometimes we need to do getattr(table,'some long field name') A lot of scientific software depends on this, and it would break at the moment your proposal is introduced. It would be a major disaster. It would even set back NASA's space program (no kidding!) Sturla

On Dec 22, 2014, at 7:43 AM, Sturla Molden <sturla.molden@gmail.com> wrote:
Yup, someone else pointed out that ctypes also relies on the current behavior, so I dropped the suggestion. (To the person that pointed about ctypes, I apologize about not giving you credit, but I deleted the email). Thanks, Cem Karan
participants (4)
-
Cem Karan
-
Chris Angelico
-
Nick Coghlan
-
Sturla Molden