f-string, for dictionaries

We have a syntax to create strings with variables automatically inferred from its context:
Similarly, I'd like to suggest a similar feature for building dictionaries:
And a similar way to get the content from the dictionary into variables:
The syntaxes used here are of course just to illustrate the concept and I'm suggesting we must use those.

On 25 October 2016 at 20:11, Michel Desmoulin <desmoulinmichel@gmail.com> wrote:
I don't see a huge advantage over
dict(foo=foo, bar=bar)
Avoiding having to repeat the variable names doesn't feel like a killer advantage here, certainly not sufficient to warrant adding yet another dictionary construction syntax. Do you have examples of code that would be substantially improved with this syntax (over using an existing approach)?
There aren't as many obvious alternative approaches here, but it's not clear why you'd want to do this. So in this case, I'd want to see real-life use cases. Most of the ones I can think of are just to allow a shorter form for values['foo']. For those uses >>> from types import SimpleNamespace >>> o = SimpleNamespace(**values) >> o.foo 1 works pretty well.
The syntaxes used here are of course just to illustrate the concept and I'm suggesting we must use those.
Well, if we ignore the syntax for a second, what is your proposal exactly? It seems to be in 2 parts: 1. "We should have a dictionary building feature that uses keys based on variables from the local namespace". OK, that's not something I've needed much, and when I have, there have usually been existing ways to do the job (such as dict(foo=foo) noted above) that are perfectly sufficient. Sometimes the existing alternatives look a little clumsy and repetitive, but that's a very subjective judgement, and any new syntax could easily look worse to me (your specific proposal, for example, does). So I can see a small potential benefit in (subjective) readability, but that's offset by the proposal being another way of doing something that's already pretty well covered in the language. Add to that all of the "normal" objections to new syntax (more to teach/learn, hard to google, difficulty finding a form that suits everyone, etc) and it's hard to see this getting accepted. 2. "We should have a way of unpacking a dictionary into local variables". That's not something that I can immediately think of a way of doing currently - so that's a point in its favour. But honestly, I've never seen the need to do this outside of interactive use (for which see below). If all you want is to avoid the d['name'] syntax, which is quite punctuation-heavy, the SimpleNamespace trick above does that. So there's almost no use case that I can see for this. Can you give examples of real-world code where this would be useful? On the other hand, your proposal, like many that have come up recently, seems to be driven (if it's OK for me to guess at your motivations) by an interest in being able to write relatively terse one-liners, or at least to avoid some of the syntactic overheads of existing constructs. It seems to me that the environment I'd most want to do this in is the interactive interpreter. So I wonder if this (and similar) proposals are driven by a feeling that it's "clumsy" writing code at the interactive prompt. That may well be so. The standard interactive prompt is pretty basic, and yet it's a *huge* part of the unique experience working with Python to be able to work at the prompt as you develop. So maybe there's scope for discussion here on constructs focused more on interactive use? That probably warrants a separate thread, though, so I'll split it off from this discussion. Feel free to contribute there if I'm right in where I think the motivation for your proposals came from. Paul

Le 25/10/2016 à 22:27, Paul Moore a écrit :
{:bar, :foo} vs dict(foo=foo, bar=bar) has the same benefit that would have f"hello {foo} {bar}" vs "hello {} {}".format(foo, bar)
This is just unpacking for dicts really. As you would do: a, b = iterable you do: {:a, :b} = mapping
Currently I already have shortcuts those features. I have wrappers for dictionaries such as: d(mapping).unpack('foo', 'bar') Which does some hack with stack frame and locals(). And: d.from_vars('foo', 'bar') I use them only in the shell of course, because you can't really have such hacks in production code. I would use such features in my production code if they was a clean way to do it. It's just convenience syntaxic sugar. You can argue that decorator could be written: def func(): pass func = decorator(func) Instead of: @decorator def func(): pass But the second one is more convenient. And so are comprehensions, unpacking, and f-strings. Clearly not killer features, just nice to have.

Hi Michel, hi Paul, sorry for hijacking this thread somewhat. I would like to extend this proposal a bit in order make it useful for a broader audience and to provide a real-word use-case. So, this post is just to gather general acceptance and utility of it. Michel, you specifically mentioned dicts as the place where to start with this kind of syntax. I have to tell you one could easily extend this thought process to function calls as well. Keyword arguments cannot be simply passed like positional arguments. They always require the parameter name to be mentioned. In production we have masses of code that goes like this:
Causes: - verbose names of variables - extended usage of kwargs - passing the same data over and over again down the calling hierarchy So, instead providing this kind of syntax for dicts only, why not also providing them for kwargs? Basically marking arguments as keyword arguments: my_func(:param1, :param2) ":param" equals "param=param" again but as already said that might just be placeholder syntax. What do you think? On 25.10.2016 23:18, Michel Desmoulin wrote:

On 28 October 2016 at 22:25, Sven R. Kunze <srkunze@mail.de> wrote:
-1. I don't like the use of the colon here. I don't think there's any need to avoid the repetition in arg_name=arg_name, it's a common convention, easy to read and understand, and even to write with a bit of editor support. Explicit is better than implicit implies here, IMO. Paul

Yes, -1. I feel like we should add a header to all messages on this list: WARNING: PYTHON IS NOT PERL, NOR APL! I know I'm being snarky, but too many of the recent ideas feel like code golf for uncommon user cases. Or at least not common enough to warrant the cognitive burden of more syntax. On Oct 28, 2016 2:42 PM, "Paul Moore" <p.f.moore@gmail.com> wrote:

Sven R. Kunze writes:
Please don't. I need to write Lisp, where that syntax has a completely different meaning: "this symbol has itself as a value". Ie, (eval :key) always evaluates to :key itself. Syntax based on single characters is very hard to get right once you get past the 4-function calculator level. C's ternary operator was inspired design IMO (YMMV), but far too many others just fall flat. One aspect of Python that is important to me is that it is executable pseudo-code, as they say. A litmus test for that is that a reasonably bright English-speaking 12-year-old without previous exposure to Python should be able to tell you what a statement does. There are a few cases where that principle is violated (said 12-year-old won't know the difference between "=" and '==' though context will probably teach her, nor the meaning of the attribute operator period), but mostly it works. Infix operators "in", "or", and "and" help a lot. As English, the ternary operator "it's-this if test else it's-that" is stilted but the 12-year-old can parse it. This test also applies to the null-coalescing operators and '@'. The fact that '@' got in means the principle is hardly inviolable, of course. At least in the case of '@' you can tell it's a binary operator, but the "implicit-assignment" colon and "null-coalescing" question mark operator-mode-modifying operator[1] could do anything. Null-coalescing is plausible -- I've never needed it, nor do I expect to need it any time soon, but the examples of where it would be used seem reasonable to me, and where needed the existing WTDIs quickly lead to an unreadable morass of nested ternaries with extremely redundant operands. I'll leave the judgment about whether it clears the bar to those who have broader experience than I. But this colon notation is horrible. foo=foo and 'foo':foo are already the respective TOOWTDIs, and quite readable. These operations don't nest, so I can't see how they would become either unreadable or exponentially redundant. Rather than change Python, improve your editor[2], and your fingers will thank you for the rest of your life, even when you're not editing Python. Footnotes: [1] If that doesn't scare you, what will?<wink/> [2] In Emacs with "dynabbrev" enabled the keystrokes are respectively "f o o = meta-/" and "' f o o ' : meta-/". A good editor can -- and IMO should -- make this operation efficient, as a by-product of providing context-dependent prefix expansion.

On Tue, Oct 25, 2016 at 09:11:06PM +0200, Michel Desmoulin wrote:
How often do you do this? Under what circumstances do you do this? If your code is like my code, the answer is: very rarely; and it is so long since I've needed anything like this I don't recall why. I don't think this is a common operation. So even though writing: {'spam': spam, 'eggs': eggs} or even: dict(spam=spam, eggs=eggs) is a bit of an annoyance, it doesn't happen often enough to matter, and its better to just write what you want explicitly rather than have to learn another special syntax for something you use so rarely you'll probably never remember it. Or at least, *I'll* never remember it. It will be just one more cryptic and strange syntax to confuse beginners and intermediate users with: # I never remember which one to use... {:spam, :eggs} {spam:, eggs:} {spam, eggs}
Check the archives: https://mail.python.org/pipermail/python-ideas/2016-May/040430.html https://mail.python.org/pipermail/python-ideas/2008-March/001511.html https://mail.python.org/pipermail/python-ideas/2008-April/001513.html -- Steve

On 25 October 2016 at 20:11, Michel Desmoulin <desmoulinmichel@gmail.com> wrote:
I don't see a huge advantage over
dict(foo=foo, bar=bar)
Avoiding having to repeat the variable names doesn't feel like a killer advantage here, certainly not sufficient to warrant adding yet another dictionary construction syntax. Do you have examples of code that would be substantially improved with this syntax (over using an existing approach)?
There aren't as many obvious alternative approaches here, but it's not clear why you'd want to do this. So in this case, I'd want to see real-life use cases. Most of the ones I can think of are just to allow a shorter form for values['foo']. For those uses >>> from types import SimpleNamespace >>> o = SimpleNamespace(**values) >> o.foo 1 works pretty well.
The syntaxes used here are of course just to illustrate the concept and I'm suggesting we must use those.
Well, if we ignore the syntax for a second, what is your proposal exactly? It seems to be in 2 parts: 1. "We should have a dictionary building feature that uses keys based on variables from the local namespace". OK, that's not something I've needed much, and when I have, there have usually been existing ways to do the job (such as dict(foo=foo) noted above) that are perfectly sufficient. Sometimes the existing alternatives look a little clumsy and repetitive, but that's a very subjective judgement, and any new syntax could easily look worse to me (your specific proposal, for example, does). So I can see a small potential benefit in (subjective) readability, but that's offset by the proposal being another way of doing something that's already pretty well covered in the language. Add to that all of the "normal" objections to new syntax (more to teach/learn, hard to google, difficulty finding a form that suits everyone, etc) and it's hard to see this getting accepted. 2. "We should have a way of unpacking a dictionary into local variables". That's not something that I can immediately think of a way of doing currently - so that's a point in its favour. But honestly, I've never seen the need to do this outside of interactive use (for which see below). If all you want is to avoid the d['name'] syntax, which is quite punctuation-heavy, the SimpleNamespace trick above does that. So there's almost no use case that I can see for this. Can you give examples of real-world code where this would be useful? On the other hand, your proposal, like many that have come up recently, seems to be driven (if it's OK for me to guess at your motivations) by an interest in being able to write relatively terse one-liners, or at least to avoid some of the syntactic overheads of existing constructs. It seems to me that the environment I'd most want to do this in is the interactive interpreter. So I wonder if this (and similar) proposals are driven by a feeling that it's "clumsy" writing code at the interactive prompt. That may well be so. The standard interactive prompt is pretty basic, and yet it's a *huge* part of the unique experience working with Python to be able to work at the prompt as you develop. So maybe there's scope for discussion here on constructs focused more on interactive use? That probably warrants a separate thread, though, so I'll split it off from this discussion. Feel free to contribute there if I'm right in where I think the motivation for your proposals came from. Paul

Le 25/10/2016 à 22:27, Paul Moore a écrit :
{:bar, :foo} vs dict(foo=foo, bar=bar) has the same benefit that would have f"hello {foo} {bar}" vs "hello {} {}".format(foo, bar)
This is just unpacking for dicts really. As you would do: a, b = iterable you do: {:a, :b} = mapping
Currently I already have shortcuts those features. I have wrappers for dictionaries such as: d(mapping).unpack('foo', 'bar') Which does some hack with stack frame and locals(). And: d.from_vars('foo', 'bar') I use them only in the shell of course, because you can't really have such hacks in production code. I would use such features in my production code if they was a clean way to do it. It's just convenience syntaxic sugar. You can argue that decorator could be written: def func(): pass func = decorator(func) Instead of: @decorator def func(): pass But the second one is more convenient. And so are comprehensions, unpacking, and f-strings. Clearly not killer features, just nice to have.

Hi Michel, hi Paul, sorry for hijacking this thread somewhat. I would like to extend this proposal a bit in order make it useful for a broader audience and to provide a real-word use-case. So, this post is just to gather general acceptance and utility of it. Michel, you specifically mentioned dicts as the place where to start with this kind of syntax. I have to tell you one could easily extend this thought process to function calls as well. Keyword arguments cannot be simply passed like positional arguments. They always require the parameter name to be mentioned. In production we have masses of code that goes like this:
Causes: - verbose names of variables - extended usage of kwargs - passing the same data over and over again down the calling hierarchy So, instead providing this kind of syntax for dicts only, why not also providing them for kwargs? Basically marking arguments as keyword arguments: my_func(:param1, :param2) ":param" equals "param=param" again but as already said that might just be placeholder syntax. What do you think? On 25.10.2016 23:18, Michel Desmoulin wrote:

On 28 October 2016 at 22:25, Sven R. Kunze <srkunze@mail.de> wrote:
-1. I don't like the use of the colon here. I don't think there's any need to avoid the repetition in arg_name=arg_name, it's a common convention, easy to read and understand, and even to write with a bit of editor support. Explicit is better than implicit implies here, IMO. Paul

Yes, -1. I feel like we should add a header to all messages on this list: WARNING: PYTHON IS NOT PERL, NOR APL! I know I'm being snarky, but too many of the recent ideas feel like code golf for uncommon user cases. Or at least not common enough to warrant the cognitive burden of more syntax. On Oct 28, 2016 2:42 PM, "Paul Moore" <p.f.moore@gmail.com> wrote:

Sven R. Kunze writes:
Please don't. I need to write Lisp, where that syntax has a completely different meaning: "this symbol has itself as a value". Ie, (eval :key) always evaluates to :key itself. Syntax based on single characters is very hard to get right once you get past the 4-function calculator level. C's ternary operator was inspired design IMO (YMMV), but far too many others just fall flat. One aspect of Python that is important to me is that it is executable pseudo-code, as they say. A litmus test for that is that a reasonably bright English-speaking 12-year-old without previous exposure to Python should be able to tell you what a statement does. There are a few cases where that principle is violated (said 12-year-old won't know the difference between "=" and '==' though context will probably teach her, nor the meaning of the attribute operator period), but mostly it works. Infix operators "in", "or", and "and" help a lot. As English, the ternary operator "it's-this if test else it's-that" is stilted but the 12-year-old can parse it. This test also applies to the null-coalescing operators and '@'. The fact that '@' got in means the principle is hardly inviolable, of course. At least in the case of '@' you can tell it's a binary operator, but the "implicit-assignment" colon and "null-coalescing" question mark operator-mode-modifying operator[1] could do anything. Null-coalescing is plausible -- I've never needed it, nor do I expect to need it any time soon, but the examples of where it would be used seem reasonable to me, and where needed the existing WTDIs quickly lead to an unreadable morass of nested ternaries with extremely redundant operands. I'll leave the judgment about whether it clears the bar to those who have broader experience than I. But this colon notation is horrible. foo=foo and 'foo':foo are already the respective TOOWTDIs, and quite readable. These operations don't nest, so I can't see how they would become either unreadable or exponentially redundant. Rather than change Python, improve your editor[2], and your fingers will thank you for the rest of your life, even when you're not editing Python. Footnotes: [1] If that doesn't scare you, what will?<wink/> [2] In Emacs with "dynabbrev" enabled the keystrokes are respectively "f o o = meta-/" and "' f o o ' : meta-/". A good editor can -- and IMO should -- make this operation efficient, as a by-product of providing context-dependent prefix expansion.

On Tue, Oct 25, 2016 at 09:11:06PM +0200, Michel Desmoulin wrote:
How often do you do this? Under what circumstances do you do this? If your code is like my code, the answer is: very rarely; and it is so long since I've needed anything like this I don't recall why. I don't think this is a common operation. So even though writing: {'spam': spam, 'eggs': eggs} or even: dict(spam=spam, eggs=eggs) is a bit of an annoyance, it doesn't happen often enough to matter, and its better to just write what you want explicitly rather than have to learn another special syntax for something you use so rarely you'll probably never remember it. Or at least, *I'll* never remember it. It will be just one more cryptic and strange syntax to confuse beginners and intermediate users with: # I never remember which one to use... {:spam, :eggs} {spam:, eggs:} {spam, eggs}
Check the archives: https://mail.python.org/pipermail/python-ideas/2016-May/040430.html https://mail.python.org/pipermail/python-ideas/2008-March/001511.html https://mail.python.org/pipermail/python-ideas/2008-April/001513.html -- Steve
participants (6)
-
David Mertz
-
Michel Desmoulin
-
Paul Moore
-
Stephen J. Turnbull
-
Steven D'Aprano
-
Sven R. Kunze