This idea is simply that anywhere an identifier is expected in Python, a programmer could instead supply a string between two backtics. The only characters that could not be used between these backticks are other backtics, or any line breaks.
`Monty` # valid, but not necessary
`Monty Python` # valid
`twenty.two` # valid as one name
`1234` # perhaps very confusing, but allowed
`this\` # valid as backtics can't be contained, and so can't be escaped
`
not this
`
Python is very often a glue language, and this would allow it to fit even more bits together. It would allow more seamless interaction with namespaces where kebab case is prevalent; not only other languages but also the filesystem, shell options, docker registries, toml, etc. It would also allow the use of symbols used in other languages, such as Rubyâs success? or JavaScriptâs $item, without any lossy conversion.
Perhaps importantly, this change would be a change semantically by allowing a new way to write identifiers but does not require changes to how identifiers are stored or retrieved. The dict behind each python namespace is already capable of holding these and still more that still canât be represented by this new syntax.
Some further examples, including how the same could be achieved with the current implementation of python:
import `#hidden` as hidden
# hidden = __import__("#hidden")
order = menu.`spam&eggs`
# order = gettattr(menu, "spam&eggs")
`1 answer` = 42
# globlas()["1 answer"] = 42
post(`user-data`=my_data)
# post(**{"user-data": my_data})
I like this idea. Iâve been running into this problem repeatedly across projects and the only âfixâ was with MacroPy. Since thatâs not maintained anymore, I had to go back to âbackpatchingâ the names.
When I had the need, I was told to use dicts, and when shown the task, there was always a way to use dicts.
Thinking about your back ticks suggestion, I am concerned that you state that this form wouldnât be able to specify any string as a name - what if you want backticks in a name? Or to use hex chars in a name?
I also think there could be issues with having keywords in backticks, and in generating code.
In general, there could be a lot to resolve when fleshed out.
Approval is unlikely as some core developers really hate backticks and were delighted when they were removed from Python syntax. The currently methods listed above are considered to be the proper solution. The Steering Council has decided that these string options should be considered part of Python rather than just CPython implementation accidents. See https://discuss.python.org/t/non-identifier-names-of-kwargs-attributes-variables-etc/19293/3
Predictably, backticks are not going to be accepted because they are almost invisible. Also, how would you quote your code in Markdown ?
The idea of a syntax (allowing any name expressed as a string) is not unreasonable. The argument would have to be accepted that a spelling more succinct than getattr(o, "Monty Python") (etc.) is feasible and useful to enough people to be worth the complexity. Iâm not one of those people.
Look for quoted identifiers in statically typed languages that donât have equivalents of getattr and setattr. C# has it, verbatim identifiers prefixed with @. Java apparently doesnât.
Thanks for the link. I knew about the Ideas thread but not the Steering Counsel pronouncement.
The methods I listed above work, but I would argue the way of getting or setting a global variable is not obvious. But the real problem with the current functions is that there is no way to set a local. There is of course locals() but as noted in its own docstring
NOTE: Whether or not updates to this dictionary will affect name lookups in
the local scope and vice-versa is implementation dependent and not
covered by any backwards compatibility guarantees.
and indeed a statement like locals()["foo"] = 42 in CPython will sometimes alter the variable named foo (in module scope), sometimes not (in function scope).
And if what you actually need to access or edit is a nonlocal variable you are left with basically no functions to help you out.
Maybe this is a knee-jerk reaction, but I donât think we need this feature, we can use getattr() and friends for those cases where itâs necessary. Also, I would like to reserve backticks for a much more important feature.
Indeed. Backticks were removed from Python 3.0 syntax with this comment (PEP 3099):
Backticks will no longer be used as shorthand for repr â but that doesnât mean they are available for other uses. Even ignoring the backwards compatibility confusion, the character itself causes too many problems (in some fonts, on some keyboards, when typesetting a book, etc).
The rise of Markdown added another reason against backticks, so I think we can rule that particular syntax out. Rust- or Perl-style quoting might be still worth discussing here on Ideas, but IMO itâs getting too close to the verbosity of getattr(obj, "...") etc. to be a win.
(Speaking as myself here â I havenât consulted with the Steering Council on this)
Jeremiahâs reply that there is no real alternate to local identifier is the only good reason I can see for needing the backtick syntax. Iâve been using Python since 1.5.2, and Iâve only ever needed something like this once in all that time. It wasnât a local variable, but a class one, and I was able to solve it by using self.dict[âclass identifierâ]. Assigning to such a variable outside a function is a piece of cake:
assuming a function called âughâ, then âugh.dict[âweird variableâ]=12345â works fine, but inside the function, itâs different, as locals() is the only way to access the functionâs dict inside itself:
So thereâs a use case for backticks, but theyâre ugly. Thereâs another way, of course, and that would be to use the name of the function inside itself. However, that fails:
>>> def blurgh():
... blurgh.__dict__['weird variable']-'w'
... print(blurgh.__dict__["weird variable"])
...
>>> blurgh()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in blurgh
KeyError: 'weird variable'
>>>
Even if that worked, itâs also ugly, as well as a pain in the butt.
Looking at the use cases Iâd be hard pressed to find any way to apply any of them in my code.
You actually had a typo there, you did subtraction not assignment which is why the lookup failed. It would otherwise print w. But this does not change the locals in the function, it changes the attributes of the function object.
The other thing that is not possible right now, not even with dunders, is capturing a nonlocal in a closure. Whether explicitly with the keyword or implicitly by being referenced in the function body, there is no real way to find which outer namespace an identifier belongs to, or that it will still exist when you need it.