
On Mon, Jul 20, 2015 at 11:33 AM, Steve Dower <Steve.Dower@microsoft.com> wrote:
Chris Angelico wrote:
On Mon, Jul 20, 2015 at 10:43 AM, Steve Dower <Steve.Dower@microsoft.com> wrote: It'd obviously have to be a compile-time transformation. My point is that it would, unlike all other forms of literal, translate into a function call.
Excluding dictionary literals, of course. And class definitions. Decorators too, and arguably the descriptor protocol and __getattribute__ make things that look like attribute lookups into function calls. Python is littered with these, so I'm not sure that your point has any historical support.
Dictionary/list display isn't a literal, and every time it's evaluated, you get a brand new object, not another reference to the same literal. Compare:
def make_list(): return [1,2,3] make_list() is make_list() False
Class and function definitions are also not literals, although people coming from other languages are often confused by this. (I've seen people write functions down the bottom of the file that are needed by top-level code higher up. It's just something you have to learn - Python doesn't "declare" functions, it "defines" them.) Going the other direction, there are a few things that you might think are literals but aren't technically so, such as "2+3j", which is actually two literals (int and imaginary) and a binary operation; but constant folding makes them functionally identical to constants. The nearest equivalent to this proposal is tuple display, which can sometimes function almost like a literal:
def make_tuple(): return (1,2,3) make_tuple() is make_tuple() True
This disassembles to a simple fetching of a constant. However, it's really just like list display plus constant folding - the compiler notices that it'll always produce the same tuple, so it optimizes it down to a constant. In none of these cases is a string ever anything other than a simple constant. That's why this proposal is a distinct change; all of the cases where Python has non-constants that might be thought of as constants, they contain expressions (or even statements - class/function definitions), and are syntactically NOT single entities. Now, that's not to say that it cannot possibly be done. But I personally am not in favour of it.
How is your "x=x, y=y" version materially different from explicitly mentioning locals() or globals()? The only significant difference is that your version follows the scope order outward, where locals() and globals() call up a specific scope each.
Yes, it follows normal scoping rules and doesn't invent/define/describe new ones for this particular case. There is literally no difference between the function call version and the prefix version wrt scoping.
As an example of why "normal rules" are better than "locals()/globals()", how would you implement this using just locals() and globals()?
def f(): ... x = 123 ... return [f'{x}' for _ in range(1)] ... f() ['123']
Given that this is the current behaviour:
def f(): ... return [locals()[x] for _ in range(1)] ... f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in f File "<stdin>", line 1, in <listcomp> KeyError: 'x'
Sure, that's where following the scoping rules is better than explicitly calling up locals(). On the flip side, going for locals() alone means you can easily and simply protect your code against grabbing the "wrong" things, by simply putting it inside a nested function (which is what your list comp there is doing), and it's also easier to explain what this construct does in terms of locals() than otherwise (what if there are attribute lookups or subscripts?).
Will an f"..." format string be mergeable with other strings? All the other types of literal can be (apart, of course, from mixing bytes and unicode), but this would have to be something somehow different.
I don't mind saying "no" here, especially since the merging is done while compiling, but it would be possible to generate a runtime concatentation here. Again, you only "know" that code (currently) has no runtime effect because, well, because you know it. It's a change, but it isn't world ending.
Fair enough. I wouldn't mind saying "no" here too - in the same way that it's a SyntaxError to write u"hello" b"world", it would be a SyntaxError to mix either with f"format string".
In every way that I can think of, this is not a literal - it is a construct that results in a run-time operation.
Most new Python developers (with backgrounds in other languages) are surprised that "class" is a construct that results in a run-time operation, and would be surprised that writing a dictionary literal also results in a run-time operation if they ever had reason to notice. I believe the same would apply here.
That's part of learning the language (which things are literals and which aren't). Expanding the scope of potential confusion is a definite cost; I'm open to the argument that the benefit justifies that cost, but it is undoubtedly a cost.
A context-dependent operation, at that.
You'll need to explain this one for me - how is it "context-dependent" when you are required to provide a string prefix?
def func1(): x = "world" return f"Hello, {x}!" def func2(): return f"Hello, {x}!" They both return what looks like a simple string, but in one, it grabs a local x, and in the other, it goes looking for a global. This is one of the potential risks of such things as decimal.Decimal literals, because literals normally aren't context-dependent, but the Decimal constructor can be affected by precision controls and such. Again, not a killer, but another cost.
That's why I'm -1 on this looking like a literal.
I hope you'll reconsider, because I think you're working off some incorrect or over-simplified beliefs. (Though this reply isn't just intended for Chris, but for everyone following the discussion, so I hope *everyone* considers both sides.)
Having read your above responses, I'm now -0.5 on this proposal. There is definite merit to it, but I'm a bit dubious that it'll end up with one of the problems of PHP code: the uncertainty of whether something is a string or a piece of code. Some editors syntax-highlight all strings as straight-forward strings, same color all the way, while others will change color inside there to indicate interpolation sites. Which is correct? At least here, the prefix on the string makes it clear that this is a piece of code; but it'll take editors a good while to catch up and start doing the right thing - for whatever definition of "right thing" the authors choose. Maybe my beliefs are over-simplified, in which case I'll be happy to be proven wrong by some immensely readable and clear real-world code examples. :) ChrisA