Allow "assigning" to Ellipse to discard values.

Basically, in any location where a variable name is provided for assignment (tuple unpacking, for loops, function parameters, etc) a variable name can be replaced by '...' to indicate that that value will not be used. This would be syntactically equivalent to del-ing the variable immediately after, except that the assignment never needs to be done.
Examples:
tup = ('val1', 'val2', (123, 456, 789)) name, ..., (..., value, ...) = tup
instead of:
name = tup[0] value = tup[2][1]
This shows slightly more clearly what format the tuple will be in, and provides some additional error-checking - the unpack will fail if the tuple is a different size or format.
for ... in range(100): pass
This particular case could be optimised by checking to see if the iterator has a len() method, and if so directly looping that many times in C instead of executing the __next__() method repeatedly.
for i, ... in enumerate(object):
is equivalent to:
for i in range(len(object)):
The Ellipse form is slightly more clear and works for objects without len().
first, second, *... = iterator
In the normal case, this would extract the first two values, and exhaust the rest of the iterator. Perhaps this could be special-cased so the iterator is left alone, and the 3rd+ values are still available.
def function(param1, ..., param3, key1=True, key2=False, **...): pass
This could be useful when overriding functions in a subclass, or writing callback functions. Here we don't actually need the 2nd argument. The '**...' would be the only allowable form of Ellipse in keyword arguments, and just allows any other keywords to be given to the function.
- Spencer

On Tue, Feb 10, 2015 at 1:01 PM, Spencer Brown spencerb21@live.com wrote:
Basically, in any location where a variable name is provided for assignment (tuple unpacking, for loops, function parameters, etc) a variable name can be replaced by '...' to indicate that that value will not be used. This would be syntactically equivalent to del-ing the variable immediately after, except that the assignment never needs to be done.
Examples:
tup = ('val1', 'val2', (123, 456, 789)) name, ..., (..., value, ...) = tup
I generally handle this by using a really simple no-meaning name, like"_" :
name, _, (_, value, __ ) = tup
granted, the _ sticks around and keeps the object alive, which may cause issues. But is it often a big deal?
-Chris

On Tue, Feb 10, 2015, at 16:23, Chris Barker wrote:
granted, the _ sticks around and keeps the object alive, which may cause issues. But is it often a big deal?
Is cpython capable of noticing that the variable is never referenced (or is only assigned) after this point and dropping it early? Might be a good improvement to add if not.

On Feb 10, 2015, at 13:33, random832@fastmail.us wrote:
On Tue, Feb 10, 2015, at 16:23, Chris Barker wrote:
granted, the _ sticks around and keeps the object alive, which may cause issues. But is it often a big deal?
Is cpython capable of noticing that the variable is never referenced (or is only assigned) after this point and dropping it early? Might be a good improvement to add if not.
This seems pretty simple in concept, but a lot of code. Currently CPython only runs a keyhole optimizer step; you'd need a whole-function optimizer step that runs after each function definition is complete. But then all it has to do is look for any locals that are never referenced and remove all assignments to them, skipping any functions that use eval of course. (This wouldn't get rid of unnecessary repeated assignments to global, closure, item, or attr, but that wouldn't matter for this use case.)
To play with this and see how much benefit you'd get, someone could write this pretty simply from Python with byteplay (especially since you don't have to write anything fully general and safe for the test) and run some timeits. (Of course to measure how much it slows down the compiler, and how much of your coding time it takes, and how risky the code looks, you'd have to actually do the work, but knowing how much benefit you're talking about may be enough information to guess that the cost isn't worth it.)

On Tue, Feb 10, 2015 at 1:33 PM, random832@fastmail.us wrote:
Is cpython capable of noticing that the variable is never referenced (or is only assigned) after this point and dropping it early? Might be a good improvement to add if not.
I'm not sure that such would be viable in the general case, as assignment of classes could have side-effects. Consider the following code (untested):
class MyClass: def __init__(self): global a a = 1 def __del__(self): global a a = 2
def myFunction(): b = MyClass() # Note that b is not referenced anywhere - it is local and not used in the scope or a internal scope. print(a)
myFunction()
Without the optimization (existing behavior), this will print 1. With the optimization, MyClass could be garbage collected early (as it cannot be referenced), and thus the code would print 2 (in CPython, but it could also be a race condition or otherwise undetermined whether 1 or 2 will be printed).
I'm not saying that it is a good idea to write such a class, but a change to how variables are assigned would be backwards-incompatible, and could result in very odd behavior in somebody's code.
Chris

On Feb 10, 2015, at 13:51, Chris Kaynor ckaynor@zindagigames.com wrote:
On Tue, Feb 10, 2015 at 1:33 PM, random832@fastmail.us wrote:
Is cpython capable of noticing that the variable is never referenced (or is only assigned) after this point and dropping it early? Might be a good improvement to add if not.
I'm not sure that such would be viable in the general case, as assignment of classes could have side-effects. Consider the following code (untested):
class MyClass: def __init__(self): global a a = 1 def __del__(self): global a a = 2
def myFunction(): b = MyClass() # Note that b is not referenced anywhere - it is local and not used in the scope or a internal scope. print(a)
myFunction()
Without the optimization (existing behavior), this will print 1. With the optimization, MyClass could be garbage collected early (as it cannot be referenced), and thus the code would print 2 (in CPython, but it could also be a race condition or otherwise undetermined whether 1 or 2 will be printed).
Good point.
But does Python actually guarantee that a variable will be alive until the end of the scope even if never referenced?
That seems like the kind of thing Jython and PyPy would ensure for compatibility reasons even if it's not required (the same way, e.g., Jython ensures GIL-like sequential consistency on __setattr__ calls to normal dict-based classes), so it might be a bad idea to change it even if it's legal. But then it's more a practical question of how much working code would break, what the benefit is, etc.
Of course this same consideration also affects the original proposal. I can very easily write a class that does something that affects the global environment on __next__ but that's still a valid Sequence, so skipping the __next__ calls is even more dangerous than skipping the assignment...

On 11 February 2015 at 08:44, Andrew Barnert abarnert@yahoo.com.dmarc.invalid wrote:
But does Python actually guarantee that a variable will be alive until the end of the scope even if never referenced?
Yes, due to the way namespace semantics are defined. Bound names are always referenced from the local namespace (so locals() can return them), even if nothing visible to the compiler looks them up. That reference doesn't go away until the namespace does.
Cheers, Nick.

Is this true? I thought that b can be immediately deleted early since it can no longer be referenced. C++ has guaranteed object lifetimes. I didn't think Python was the same way.
On Tuesday, February 10, 2015 at 4:52:10 PM UTC-5, Chris Kaynor wrote:
On Tue, Feb 10, 2015 at 1:33 PM, <rand...@fastmail.us javascript:> wrote:
Is cpython capable of noticing that the variable is never referenced (or is only assigned) after this point and dropping it early? Might be a good improvement to add if not.
I'm not sure that such would be viable in the general case, as assignment of classes could have side-effects. Consider the following code (untested):
class MyClass: def __init__(self): global a a = 1 def __del__(self): global a a = 2
def myFunction(): b = MyClass() # Note that b is not referenced anywhere - it is local and not used in the scope or a internal scope. print(a)
myFunction()
Without the optimization (existing behavior), this will print 1. With the optimization, MyClass could be garbage collected early (as it cannot be referenced), and thus the code would print 2 (in CPython, but it could also be a race condition or otherwise undetermined whether 1 or 2 will be printed).
I'm not saying that it is a good idea to write such a class, but a change to how variables are assigned would be backwards-incompatible, and could result in very odd behavior in somebody's code.
Chris _______________________________________________ Python-ideas mailing list Python...@python.org javascript: https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On Wed, Feb 11, 2015 at 8:33 AM, random832@fastmail.us wrote:
On Tue, Feb 10, 2015, at 16:23, Chris Barker wrote:
granted, the _ sticks around and keeps the object alive, which may cause issues. But is it often a big deal?
Is cpython capable of noticing that the variable is never referenced (or is only assigned) after this point and dropping it early? Might be a good improvement to add if not.
CPython? Seems pretty unlikely. Other Pythons, like PyPy? Maybe... but only for types without __del__. Consider:
class ReportDestruction: def __init__(self, msg): self.msg = msg def __del__(self): print("DESTROY:", self.msg)
def f(): x = ReportDestruction("on leaving f()") ReportDestruction("Immediate") ... other code ...
In current CPython, the second reporter will speak immediately, and the first one will speak when the function terminates, unless the "other code" creates a refloop, in which case it'll speak when the loop's broken (eg by gc.collect()). It's perfectly possible for object lifetimes to be _extended_. However, I don't know of any way that you could - or would ever want to - _shorten_ the lifetime of an object. There'll be a lot of code out there that assumes that objects stick around until the end of the function.
For something like PyPy, which already has special cases for different data types, it's reasonable that some might be disposed of early (especially simple strings and integers, etc). But I doubt CPython will get anything like this in the near future. It's a dangerous optimization.
ChrisA

On Tue, 10 Feb 2015 13:23:58 -0800 Chris Barker chris.barker@noaa.gov wrote:
On Tue, Feb 10, 2015 at 1:01 PM, Spencer Brown spencerb21@live.com wrote:
Basically, in any location where a variable name is provided for assignment (tuple unpacking, for loops, function parameters, etc) a variable name can be replaced by '...' to indicate that that value will not be used. This would be syntactically equivalent to del-ing the variable immediately after, except that the assignment never needs to be done.
Examples:
tup = ('val1', 'val2', (123, 456, 789)) name, ..., (..., value, ...) = tup
I generally handle this by using a really simple no-meaning name, like"_" :
name, _, (_, value, __ ) = tup
granted, the _ sticks around and keeps the object alive, which may cause issues. But is it often a big deal?
The actual deal with that is when you are using gettext or a similar I18N framework :-)
Regards
Antoine.

On Wed, Feb 11, 2015 at 7:46 AM, Antoine Pitrou solipsis@pitrou.net wrote:
name, _, (_, value, __ ) = tup
granted, the _ sticks around and keeps the object alive, which may cause issues. But is it often a big deal?
The actual deal with that is when you are using gettext or a similar I18N framework :-)
then use a different simple name.
I sometimes use tmp, also.
-Chris

On Wed, 11 Feb 2015 08:27:39 -0800 Chris Barker chris.barker@noaa.gov wrote:
On Wed, Feb 11, 2015 at 7:46 AM, Antoine Pitrou solipsis@pitrou.net wrote:
name, _, (_, value, __ ) = tup
granted, the _ sticks around and keeps the object alive, which may cause issues. But is it often a big deal?
The actual deal with that is when you are using gettext or a similar I18N framework :-)
then use a different simple name.
Well, thanks for stating the obvious :-)
Regards
Antoine.

On 12 February 2015 at 01:46, Antoine Pitrou solipsis@pitrou.net wrote:
On Tue, 10 Feb 2015 13:23:58 -0800 Chris Barker chris.barker@noaa.gov wrote:
On Tue, Feb 10, 2015 at 1:01 PM, Spencer Brown spencerb21@live.com wrote:
Basically, in any location where a variable name is provided for assignment (tuple unpacking, for loops, function parameters, etc) a variable name can be replaced by '...' to indicate that that value will not be used. This would be syntactically equivalent to del-ing the variable immediately after, except that the assignment never needs to be done.
Examples:
tup = ('val1', 'val2', (123, 456, 789)) name, ..., (..., value, ...) = tup
I generally handle this by using a really simple no-meaning name, like"_" :
name, _, (_, value, __ ) = tup
granted, the _ sticks around and keeps the object alive, which may cause issues. But is it often a big deal?
The actual deal with that is when you are using gettext or a similar I18N framework :-)
I switched my own dummy variable recommendation to a double-underscore years ago for exactly that reason. It (very) mildly irritates me that so many sources still recommend the single-underscore that clobbers the conventional name for the gettext translation builtin :)
Cheers, Nick.

On 02/11/2015 03:01 PM, Nick Coghlan wrote:
On 12 February 2015 at 01:46, Antoine Pitrou wrote:
The actual deal with that is when you are using gettext or a similar I18N framework :-)
I switched my own dummy variable recommendation to a double-underscore years ago for exactly that reason. It (very) mildly irritates me that so many sources still recommend the single-underscore that clobbers the conventional name for the gettext translation builtin :)
Python 3.4.3rc1+ (3.4:645f3d750be1, Feb 10 2015, 13:25:59) [GCC 4.7.3] on linux Type "help", "copyright", "credits" or "license" for more information. --> _ Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name '_' is not defined --> import gettext --> gettext._ Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute '_'
What globalness are you talking about?
-- ~Ethan~

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 2/11/2015 6:06 PM, Ethan Furman wrote:
On 02/11/2015 03:01 PM, Nick Coghlan wrote:
On 12 February 2015 at 01:46, Antoine Pitrou wrote:
The actual deal with that is when you are using gettext or a similar I18N framework :-)
I switched my own dummy variable recommendation to a double-underscore years ago for exactly that reason. It (very) mildly irritates me that so many sources still recommend the single-underscore that clobbers the conventional name for the gettext translation builtin :)
Python 3.4.3rc1+ (3.4:645f3d750be1, Feb 10 2015, 13:25:59) [GCC 4.7.3] on linux Type "help", "copyright", "credits" or "license" for more information. --> _ Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name '_' is not defined --> import gettext --> gettext._ Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute '_'
What globalness are you talking about?
https://docs.python.org/2/library/gettext.html#gettext.install
import gettext gettext.install('foo') _
<bound method NullTranslations.gettext of <gettext.NullTranslations instance at 0xffeb65cc>>
- -- Eric.

On 2/11/2015 6:13 PM, Eric V. Smith wrote:
On 2/11/2015 6:06 PM, Ethan Furman wrote:
What globalness are you talking about?
https://docs.python.org/2/library/gettext.html#gettext.install
import gettext gettext.install('foo') _
<bound method NullTranslations.gettext of <gettext.NullTranslations instance at 0xffeb65cc>>
Thanks, Thunderbird, for mangling that for me. Hopefully this works better:
import gettext gettext.install('foo') _
<bound method NullTranslations.gettext of gettext.NullTranslations instance at 0xffeb65cc>>

On 02/11/2015 03:15 PM, Eric V. Smith wrote:
Thanks, Thunderbird, for mangling that for me. Hopefully this works better:
--> import gettext --> gettext.install('foo') --> _ <bound method NullTranslations.gettext of gettext.NullTranslations instance at 0xffeb65cc>>
Oh, cool. It is somewhat amusing to see the stdlib doing something we are usually strongly advised against -- adding things to __bulitins__ ;) . (Yes, I agree it is a good case... still amusing.)
-- ~Ethan~

On Feb 11 2015, Ethan Furman ethan-gcWI5d7PMXnvaiG9KC9N7Q@public.gmane.org wrote:
On 02/11/2015 03:15 PM, Eric V. Smith wrote:
Thanks, Thunderbird, for mangling that for me. Hopefully this works better:
--> import gettext --> gettext.install('foo') --> _ <bound method NullTranslations.gettext of gettext.NullTranslations instance at 0xffeb65cc>>
Oh, cool. It is somewhat amusing to see the stdlib doing something we are usually strongly advised against -- adding things to __bulitins__ ;) . (Yes, I agree it is a good case... still amusing.)
Why is that a good case? What's wrong with e.g. _ = gettext.install('foo') or from gettext import _ ?
Thanks, Nikolaus

On 2/11/2015 6:01 PM, Nick Coghlan wrote:
I switched my own dummy variable recommendation to a double-underscore years ago for exactly that reason. It (very) mildly irritates me that so many sources still recommend the single-underscore that clobbers the conventional name for the gettext translation builtin :)
People are just copying python itself, which defines _ as a throwaway name. I suspect it did so before gettext.
By reusing _, gettext made interactive experimentation tricky.
import gettext gettext.install('foo') _
<bound method NullTranslations.gettext of <gettext.NullTranslations object at 0x000000000361E978>>
_('abc')
'abc'
_
'abc' # whoops
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
Since () has equal precedence with . while + and - are lower, we would have the following equivalences for mixed expressions with '.':
_(snake.format()) == -snake.format() # format, then translate # or -(snake.lower()) _(snake).format() == (-snake).format() # translate, then format

Terry Reedy tjreedy@udel.edu writes:
People are just copying python itself, which defines _ as a throwaway name. I suspect it did so before gettext.
By reusing _, gettext made interactive experimentation tricky.
Gettext has been using the name ‘_’ since 1995, which was in Python's infancy. The name ‘_’ is pretty obvious, I'm sure it was in use before Python came along.
So, rather than the point-the-finger phrasing you give above, I'd say instead:
By choosing the name ‘_’, both Gettext and Python (and any of numerous other systems which chose that name) made a name collision likely.

On Feb 12, 2015, at 02:40 PM, Ben Finney wrote:
Gettext has been using the name ‘_’ since 1995, which was in Python's infancy. The name ‘_’ is pretty obvious, I'm sure it was in use before Python came along.
Exactly. All this was designed for compatibility with GNU gettext conventions such as in i18n'd C programs. It was especially useful to interoperate with source text extraction tools. We were aware of the collision with the interactive interpreter convenience but that wasn't deemed enough to buck established convention. Using _ to imply "ignore this value" came along afterward.
Cheers, -Barry

On 2/12/2015 10:53 AM, Barry Warsaw wrote:
On Feb 12, 2015, at 02:40 PM, Ben Finney wrote:
Gettext has been using the name ‘_’ since 1995, which was in Python's infancy. The name ‘_’ is pretty obvious, I'm sure it was in use before Python came along.
Exactly. All this was designed for compatibility with GNU gettext conventions such as in i18n'd C programs. It was especially useful to interoperate with source text extraction tools.
Are you referring to then existing tools that would pull out string literals inside _(...) and put them in a file for translation? I can see how you (all) would not want to break them.
We were aware of the collision with the interactive interpreter convenience but that wasn't deemed enough to buck established convention.
It leads to this
import gettext gettext.install('foo') _
<bound method NullTranslations.gettext of <gettext.NullTranslations object at 0x000000000361E978>>
_('abc')
'abc'
_
'abc' # whoops
of
_('cat')
... TypeError: 'str' object is not callable
Of course, one can learn to forgo the '_' convenience and test or experiment with explicit assignments.
s = _('cat') s
'gato' # for instance
I presume you decided then that this was less evil that bucking the external convention.
Using _ to imply "ignore this value" came along afterward.
Since interactive _ is usually ignored, I do not see this usage as all that different, except that it extends the conflict to batch made -- which is, of course, an important difference.

On Feb 12, 2015, at 05:41 PM, Terry Reedy wrote:
Are you referring to then existing tools that would pull out string literals inside _(...) and put them in a file for translation?
Yes.
We were aware of the collision with the interactive interpreter convenience but that wasn't deemed enough to buck established convention.
It leads to this
[...]
I presume you decided then that this was less evil that bucking the external convention.
Right, and observing that interactive interpreter use has always been rather special.
Cheers, -Barry

On 2/12/2015 5:41 PM, Terry Reedy wrote:
Of course, one can learn to forgo the '_' convenience and test or experiment with explicit assignments.
s = _('cat') s
'gato' # for instance
As pointed out to me privately, this rebinds _ to the value of s. So instead
print(s)
gato

On 2/11/2015 10:40 PM, Ben Finney wrote:
Terry Reedy tjreedy@udel.edu writes:
Nick Coughlin wrote a comment 'pointing his finger' at people who use '_' to mean something other than the gettext convert function. I replied ...
People are just copying python itself, which defines _ as a throwaway name. I suspect it did so before gettext.
By reusing _, gettext made interactive experimentation tricky.
Gettext has been using the name ‘_’ since 1995, which was in Python's infancy. The name ‘_’ is pretty obvious, I'm sure it was in use before Python came along.
I believe Python 1.0 was released in Feb 1992. I strongly suspect that '_' was bound to expression in the interactive interpreter before the gettext module was added.
So, rather than the point-the-finger phrasing you give above,
By snipping Nick's point-the-finger phrasing, you are being a little unfair to me.
I'd say instead:
By choosing the name ‘_’, both Gettext and Python (and any of numerous other systems which chose that name) made a name collision likely.
And so I suggested a possible solution.

:
On Wed, Feb 11, 2015 at 10:33:15PM -0500, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
~'python' is a nicer visual representation of translation IMO - and __invert__ could be retconned to mean INternationalisation-conVERT in the case of strings ;-)
-[]z.

On 12.02.2015 04:33, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
Doesn't read well:
label = +'I like' + +'Python'
and this is even worse, IMO:
label = -'I like' + -'Python'
I think the proper way of doing this would be to add a string literal modifier like we have with r'' for raw strings, e.g. i'Internationalized String'.
The Python compiler would then map this to a call to sys.i18n like so:
i'Internationalized String' -> sys.i18n('Internationalized String')
and applications could set sys.i18n to whatever they use for internationalization.
Python itself would default to this:
def i18n(x): return x
sys.i18n = i18n
The result looks much nicer:
label = i'I like' + i'Python'

On Thu, Feb 12, 2015 at 8:00 PM, M.-A. Lemburg mal@egenix.com wrote:
I think the proper way of doing this would be to add a string literal modifier like we have with r'' for raw strings, e.g. i'Internationalized String'.
The Python compiler would then map this to a call to sys.i18n like so:
i'Internationalized String' -> sys.i18n('Internationalized String')
and applications could set sys.i18n to whatever they use for internationalization.
While the syntax is very cute, it seems unnecessary to have compiler support for something that could just be done with a library. It'd be impossible to backport code that uses this notation, so you'd have to either require Python 3.5 (or whatever version), or maintain two different codebases, or have a 2to3-style precompiler.
Hmm. How hard is it to write a parser for Python code that extends the grammar in some way? I know there've been a lot of proposals around the place for decimal.Decimal literals and empty set literals and such; is there an elegant way to do a proof-of-concept without touching the C code at all?
ChrisA

On Thu, Feb 12, 2015 at 09:59:35PM +1100, Chris Angelico wrote:
Hmm. How hard is it to write a parser for Python code that extends the grammar in some way? I know there've been a lot of proposals around the place for decimal.Decimal literals and empty set literals and such; is there an elegant way to do a proof-of-concept without touching the C code at all?
I'm not sure if this is the sort of thing that could be adapted:
http://www.staringispolite.com/likepython/
Obviously LikePython is a joke, but perhaps you could adapt it to do what you want?

On Thu, Feb 12, 2015 at 10:08 PM, Steven D'Aprano steve@pearwood.info wrote:
On Thu, Feb 12, 2015 at 09:59:35PM +1100, Chris Angelico wrote:
Hmm. How hard is it to write a parser for Python code that extends the grammar in some way? I know there've been a lot of proposals around the place for decimal.Decimal literals and empty set literals and such; is there an elegant way to do a proof-of-concept without touching the C code at all?
I'm not sure if this is the sort of thing that could be adapted:
http://www.staringispolite.com/likepython/
Obviously LikePython is a joke, but perhaps you could adapt it to do what you want?
Thanks for the link... but turns out it's actually a very simple tokenizer that simply discards a particular set of tokens, and passes the rest through to Python. It's a stateless and very simple preprocessor. I'm hoping for something that's a little more intelligent. Basically, what I want is Python's own ast.parse(), but able to be extended to handle specific additional grammar; currently, ast.parse in CPython drops through to the C parser, which means the grammar has to be absolutely exactly the grammar of the host language.
I may have to look into 2to3. If you can run 2to3 on Python 3, then it would have to be capable of parsing something which is invalid syntax for its host interpreter, which is what I'm looking for. To take a very simple example, imagine a Python script that can translate print statements into print functions, running under Python 3; now change that 'print' to be some new statement that you're mocking (maybe a 'yield from' if we were developing Python 3.3), and you have a means of POC testing your grammar.
ChrisA

On 12 February 2015 at 11:27, Chris Angelico rosuav@gmail.com wrote:
Basically, what I want is Python's own ast.parse(), but able to be extended to handle specific additional grammar; currently, ast.parse in CPython drops through to the C parser, which means the grammar has to be absolutely exactly the grammar of the host language.
You may want to take a look at MacroPy (https://github.com/lihaoyi/macropy). I think it's aimed at the sort of thing you're talking about.
Paul

On 12 Feb 2015, at 10:00, M.-A. Lemburg mal@egenix.com wrote:
On 12.02.2015 04:33, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
Doesn't read well:
label = +'I like' + +'Python'
and this is even worse, IMO:
label = -'I like' + -'Python'
I think the proper way of doing this would be to add a string literal modifier like we have with r'' for raw strings, e.g. i'Internationalized String’.
As far as I know every other language as well as all i18n-related tools use _(..) to mark translatable strings. Changing Python from using that same standard (as most, if not all i18n-supporting Python software does) to something sounds like a huge step backwards.
Wichert.

On 12.02.2015 12:41, Wichert Akkerman wrote:
On 12 Feb 2015, at 10:00, M.-A. Lemburg mal@egenix.com wrote:
On 12.02.2015 04:33, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
Doesn't read well:
label = +'I like' + +'Python'
and this is even worse, IMO:
label = -'I like' + -'Python'
I think the proper way of doing this would be to add a string literal modifier like we have with r'' for raw strings, e.g. i'Internationalized String’.
As far as I know every other language as well as all i18n-related tools use _(..) to mark translatable strings. Changing Python from using that same standard (as most, if not all i18n-supporting Python software does) to something sounds like a huge step backwards.
Depends on how you look at it, I guess :-)
_(...) is a kludge which was invented because languages don't address the need at the language level. i"want this translated" would be such language level syntax.

M.-A. Lemburg wrote:
_(...) is a kludge which was invented because languages don't address the need at the language level.
And monkeypatching _ into the builtins was a further kludge invented because... well, I don't really know why. Because people were too lazy to import it themselves?
I think that was a really bad idea. If it hadn't been done, we would be free to provide a different way that doesn't implicitly clobber the interactive _ without it affecting existing code.

On 2015-02-12, at 12:41 , Wichert Akkerman wichert@wiggy.net wrote:
On 12 Feb 2015, at 10:00, M.-A. Lemburg mal@egenix.com wrote:
On 12.02.2015 04:33, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
Doesn't read well:
label = +'I like' + +'Python'
and this is even worse, IMO:
label = -'I like' + -'Python'
I think the proper way of doing this would be to add a string literal modifier like we have with r'' for raw strings, e.g. i'Internationalized String’.
As far as I know every other language as well as all i18n-related tools use _(..) to mark translatable strings.
In many functional languages `_` is a universal value-less matcher (that is it pattern-matches everything, but is nonsensical as a value).

On 02/12/2015 03:00 AM, M.-A. Lemburg wrote:
On 12.02.2015 04:33, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even*less* intrusive and easier to write than _('python').
Doesn't read well:
label = +'I like' + +'Python'
and this is even worse, IMO:
label = -'I like' + -'Python'
I think the proper way of doing this would be to add a string literal modifier like we have with r'' for raw strings, e.g. i'Internationalized String'.
Another option may be to add a '_' property to the string type as an alternate interface to Gettext, and possibly for use with other translators. The '_' property would still access a global function, but it could have a much longer and more meaningful name like __string_translator__.
label = 'I like'._ + 'Python'._
Then in cases where '_' is used locally as a temp name, like with lambda, you can use the '_' property instead of the global '_' function.
An advantage of the 'i' prefix notation is the translation could be done at parse time instead of run time. But that may be hard to do because all the parts may not be available at parse time. (?)
-Ron

On Feb 11, 2015, at 10:33 PM, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
This is really unnecessary. These days, I believe standard GNU xgettext can parse Python code and can be told to use an alternative marker function. Tools/i18n/pygettext.py certainly can.
Aside from all that, IIRC pygettext (and maybe xgettext) will only recognize underscore function calls that take exactly one string. That doesn't help the module global collision issue, but oh well.
I might as well use this opportunity to plug my flufl.i18n package:
http://pythonhosted.org/flufl.i18n/
It provides a nice, higher level API for doing i18n. It also does not install _ into globals by default.
(FWIW, the reason why stdlib gettext installs by default is for ease of use. People preferred to do the i18n setup in their main module and then just have that name automatically available everywhere else. I'm not defending that, just pointing out the history of this particular baggage.)
Cheers, -Barry

On 2/12/2015 11:09 AM, Barry Warsaw wrote:
[alternate syntax] is really unnecessary. These days, I believe standard GNU xgettext can parse Python code and can be told to use an alternative marker function.
My current interest in gettext is due to (incomplete) proposals (such as #17776) to internationalize parts of Idle. There are no instances of '_,' in idlelib, and probably no other use of '_' as an identifier, so injection of '_' into builtins is not my concern for batch (production) mode running.
But I don't like turning code like this (idlelib/Binding.py)
(_'file', [ ('_New File', '<<open-new-window>>'), ('_Open...', '<<open-window-from-file>>'), ('Open _Module...', '<<open-module>>'), ('Class _Browser', '<<open-class-browser>>'), ('_Path Browser', '<<open-path-browser>>'), ... and so on for another 59 lines
loaded with tuple parens and _Hotkey markers into the following with () and _ doing double duty and doubled in number.
(_('file'), [ (_('_New File'), '<<open-new-window>>'), (_('_Open...'), '<<open-window-from-file>>'), (_('Open _Module...'), '<<open-module>>'), (_('Class _Browser'), '<<open-class-browser>>'), (_('_Path Browser'), '<<open-path-browser>>'), ... and so on for another 59 lines
Tools/i18n/pygettext.py certainly can.
Are there any tests of this script, especially for 3.x, other than the two examples at the end?
I might as well use this opportunity to plug my flufl.i18n package: http://pythonhosted.org/flufl.i18n/ It provides a nice, higher level API for doing i18n.
The short "Single language context" doc section is certainly a lot simpler and clearer than the gettext doc. But I cannot use your package for Idle. I might, however, use your idea of using rot13 for testing.
I18n of existing code would be easier if Tools/i18n had a stringmark.py script that would either mark all strings with _() (or alternative) or interactively let one say yes or no to each.

On Feb 12, 2015, at 17:39, Terry Reedy tjreedy@udel.edu wrote:
I18n of existing code would be easier if Tools/i18n had a stringmark.py script that would either mark all strings with _() (or alternative) or interactively let one say yes or no to each.
One nice thing about the existing idiom is that you can use tools designed for perl or C and they do the right thing. Except, of course, that they don't handle triple quotes.
At a job around 10-12 years ago, we used this horrible commercial Windows tool for internationalization that did this, among other things. When I wanted to write some new server code in Python, management objected that it wouldn't work with our existing i18n tools. I was able to whip up a pre- and post-processor to deal with the triple quotes, and integrate it into the toolchain, in half a day. If I couldn't have done that, I probably wouldn't have been able to use Python.
By the way the injecting _ into builtins thing was actually a (tiny) problem. In C, only files that include the header have _, so the rest can be skipped; in Python, they all get _ without an import, so you have to assume they all need to be handled. (I solved that by actually importing gettext in all the modules even though it wasn't necessary, so the preprocessor could turn that import into the include the tool expected.)
Hopefully things aren't quite as bad as they were back then, but there must still be some nice gettext-style tools that either work, or can be hacked around easily, with Python gettext with the _ idiom, and I have no idea what fraction of them would be lost if we used a different idiom.
Of course there's be nothing stopping anyone from using the old _ idiom even if we added a new one, so don't take this as a vote against coming up with something better.

Terry Reedy writes:
I18n of existing code would be easier if Tools/i18n had a stringmark.py script that would either mark all strings with _() (or alternative)
This loses badly on your menu example, because you'll end up marking all the command names. More generally, I think "mark all" is almost never going to work as desired in Python because there are so many places where it's nontrivial to distinguish UI strings needing I18N from "symbols" (eg, for has_attr() or as internal hash keys), since Python doesn't have a symbol or bareword type.
or interactively let one say yes or no to each.
That's a good idea, although I'd say adding this capability to IDLE itself would be better yet. Eg, a command mark-this-string, and a quick keyboard macro "mark-this-string; 2 * forward-next-string" would be great in the menu example.

On Feb 12, 2015, at 08:39 PM, Terry Reedy wrote:
But I don't like turning code like this (idlelib/Binding.py)
(_'file', [ ('_New File', '<<open-new-window>>'), ('_Open...', '<<open-window-from-file>>'), ('Open _Module...', '<<open-module>>'), ('Class _Browser', '<<open-class-browser>>'), ('_Path Browser', '<<open-path-browser>>'), ... and so on for another 59 lines
loaded with tuple parens and _Hotkey markers into the following with () and _ doing double duty and doubled in number.
(_('file'), [ (_('_New File'), '<<open-new-window>>'), (_('_Open...'), '<<open-window-from-file>>'), (_('Open _Module...'), '<<open-module>>'), (_('Class _Browser'), '<<open-class-browser>>'), (_('_Path Browser'), '<<open-path-browser>>'), ... and so on for another 59 lines
I agree it looks cluttered, but I'm not sure how you could improve things. You have to be able to mark some strings as translatable, while other strings are not. E.g. I never translate log output because that is typically not consumed by the end user, and if it were me-as-developer trying to parse Russian log output to find a bug, I wouldn't get very far. :) Plus, there are plenty of strings in a typical program that also aren't for consumption by the end user.
Tools/i18n/pygettext.py certainly can.
Are there any tests of this script, especially for 3.x, other than the two examples at the end?
Probably not. I think once GNU xgettext learned how to parse Python, our script hasn't seen much love.
I18n of existing code would be easier if Tools/i18n had a stringmark.py script that would either mark all strings with _() (or alternative) or interactively let one say yes or no to each.
I'm not sure what you're asking for; do you want something you could point at a Python file and it would rewrite it after interactively asking for translatability or not? Hmm, maybe that would be cool. I look forward to the contribution. <wink>
Cheers, -Barry

On 2/13/2015 11:26 AM, Barry Warsaw wrote:
On Feb 12, 2015, at 08:39 PM, Terry Reedy wrote:
I18n of existing code would be easier if Tools/i18n had a stringmark.py script that would either mark all strings with _() (or alternative) or interactively let one say yes or no to each.
I'm not sure what you're asking for; do you want something you could point at a Python file and it would rewrite it after interactively asking for translatability or not?
Yes.
Hmm, maybe that would be cool. I look forward to the contribution. <wink>
If I end up needing to do much marking, I will consider doing so.

On 2/11/2015 10:33 PM, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
Since () has equal precedence with . while + and - are lower, we would have the following equivalences for mixed expressions with '.':
_(snake.format()) == -snake.format() # format, then translate # or -(snake.lower()) _(snake).format() == (-snake).format() # translate, then format
The core idea of this proposal is to add a single prefix symbol as an alternative to _(...). Summarizing the alternate proposals:
Zero Piraeus suggests that ~ (.__invert__ (normally bitwise)) would be better. I agree.
M.-A. Lemburg points out that neither of label = +'I like' + +'Python' label = -'I like' + -'Python' do not 'read well'. I do not know how common such concatentions are, but I agree that they do not look good.
He then suggests a new string prefix, such as i'Internationalized String'. ('_' could also be used as a prefix.) The compiler could map this to, for instance, sys.i18n('Internationalized String'), where initially sys.i18n = lambda s: s The above code would then become label = i'I like' + i'Python' # or label = _'I like' + _'Python' I like this even better except that it raises the issue of interaction with the existing r and b (and u) prefixes.
Ron Adam suggests a str._ property, leading to label = 'I like'._ + 'Python'._ I prefer 1 char to 2. On the other hand, a 'suffix' makes a certain sense for indicating translation. Current string prefixes affect the translation of literal to object. To properly process a string literal containing '\'s, for instance, both compilers and people need to know whether it is to be interpreted 'raw' or 'cooked'. Both also need to know whether to read it as text or bytes. Translation is an afterthought, currently performed later.
Barry Warsaw pointed out that existing tools can go thru a file, written in whatever language, and extract literal strings inside _(...). For this, distinctive awkwardness is an advantage. A new syntax would work better if there were a script to translate back to the old.

On 2015-02-13 00:01, Terry Reedy wrote:
On 2/11/2015 10:33 PM, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
Since () has equal precedence with . while + and - are lower, we would have the following equivalences for mixed expressions with '.':
_(snake.format()) == -snake.format() # format, then translate # or -(snake.lower()) _(snake).format() == (-snake).format() # translate, then format
The core idea of this proposal is to add a single prefix symbol as an alternative to _(...). Summarizing the alternate proposals:
Zero Piraeus suggests that ~ (.__invert__ (normally bitwise)) would be better. I agree.
M.-A. Lemburg points out that neither of label = +'I like' + +'Python' label = -'I like' + -'Python' do not 'read well'. I do not know how common such concatentions are, but I agree that they do not look good.
He then suggests a new string prefix, such as i'Internationalized String'. ('_' could also be used as a prefix.) The compiler could map this to, for instance, sys.i18n('Internationalized String'), where initially sys.i18n = lambda s: s The above code would then become label = i'I like' + i'Python' # or label = _'I like' + _'Python' I like this even better except that it raises the issue of interaction with the existing r and b (and u) prefixes.
I think we can forget about any interaction with the b prefix. If you're internationalising, you're using Unicode (aren't you?).
And as for the u prefix, it's really only used for compatibility with Python 2, which won't have the i prefix anyway.
That leaves us with just i and ir.
Ron Adam suggests a str._ property, leading to label = 'I like'._ + 'Python'._ I prefer 1 char to 2. On the other hand, a 'suffix' makes a certain sense for indicating translation. Current string prefixes affect the translation of literal to object. To properly process a string literal containing '\'s, for instance, both compilers and people need to know whether it is to be interpreted 'raw' or 'cooked'. Both also need to know whether to read it as text or bytes. Translation is an afterthought, currently performed later.
Barry Warsaw pointed out that existing tools can go thru a file, written in whatever language, and extract literal strings inside _(...). For this, distinctive awkwardness is an advantage. A new syntax would work better if there were a script to translate back to the old.

On 13 Feb 2015, at 01:01, Terry Reedy tjreedy@udel.edu wrote:
On 2/11/2015 10:33 PM, Terry Reedy wrote:
A possible solution would be to give 3.x str a __pos__ or __neg__ method, so +'python' or -'python' would mean the translation of 'python' (the snake). This would be even *less* intrusive and easier to write than _('python').
Since () has equal precedence with . while + and - are lower, we would have the following equivalences for mixed expressions with '.':
_(snake.format()) == -snake.format() # format, then translate # or -(snake.lower()) _(snake).format() == (-snake).format() # translate, then format
The core idea of this proposal is to add a single prefix symbol as an alternative to _(...). Summarizing the alternate proposals:
Zero Piraeus suggests that ~ (.__invert__ (normally bitwise)) would be better. I agree.
M.-A. Lemburg points out that neither of label = +'I like' + +'Python' label = -'I like' + -'Python' do not 'read well'. I do not know how common such concatentions are, but I agree that they do not look good.
Please note that concatenating translatable strings like that is a really bad practice, and will lead to impossible situations. If you translate “I like” and “Python” separately, and then concatenate the results you are likely to get something that is quite awful, if not impossible, in many languages.
There are also other areas in which Python i18n support is currently lacking, and which would only get worse with this proposal: support for message contexts and plural forms. Both are critical for any non-trivial application. For what’s worth I am toying with the idea of spending pycon sprint time on that topic (unless the pyramid folks manage to grab all my attention again!).
Wichert.

The usual convention for unused results is to assign to the variable "_". That's actually two less characters than "...", and has the advantage of requiring no new syntax or explicit support. Is there any particular reason why that would not be suitable for these use cases? It looks like _ could be a drop in replacement for ... in your examples.
Stephan

On Tue, Feb 10, 2015 at 1:01 PM, Spencer Brown spencerb21@live.com wrote:
Basically, in any location where a variable name is provided for assignment (tuple unpacking, for loops, function parameters, etc) a variable name can be replaced by '...' to indicate that that value will not be used. This would be syntactically equivalent to del-ing the variable immediately after, except that the assignment never needs to be done.
The canonical way to do this is to use the variable "_" (some guides recommend "__" for various reasons) for those names. Note that it is perfectly valid to assign to the same name multiple times in a statement.
Examples:
tup = ('val1', 'val2', (123, 456, 789)) name, ..., (..., value, ...) = tup
instead of:
name = tup[0] value = tup[2][1]
This shows slightly more clearly what format the tuple will be in, and provides some additional error-checking - the unpack will fail if the tuple is a different size or format.
Or, as it already works: "name, _, (_, value, _) = tup". There is not really any benefit to the proposed syntax.
for ... in range(100): pass
This particular case could be optimised by checking to see if the iterator has a len() method, and if so directly looping that many times in C instead of executing the __next__() method repeatedly.
Same here. "for _ in range(100)". Note, however, this does not use an optimized form (_ could be referenced in the loop). I'm not sure how much gain you would have in many cases from the optimization, and attempting such an optimization could, in fact, slow stuff down in some cases (extra look-ups and branches). Ultimately, such would require profiling of the change, and also considerations as to whether it could result in unexpected behavior.
for i, ... in enumerate(object):
is equivalent to:
for i in range(len(object)):
The Ellipse form is slightly more clear and works for objects without len().
As above: "for i, _ in enumerate(object):" already works. Again, there is not really any benefit to the proposed syntax.
first, second, *... = iterator
In the normal case, this would extract the first two values, and exhaust the rest of the iterator. Perhaps this could be special-cased so the iterator is left alone, and the 3rd+ values are still available.
I would be much more tempted to use: first = next(iterator) second = next(iterator) for the case where I don't want to exhaust the iterator. I feel it is much clearer as to the meaning.
def function(param1, ..., param3, key1=True, key2=False, **...): pass
This could be useful when overriding functions in a subclass, or writing callback functions. Here we don't actually need the 2nd argument. The '**...' would be the only allowable form of Ellipse in keyword arguments, and just allows any other keywords to be given to the function.
Here is the first case that the "_" trick on its own does not work as you cannot use the same argument multiple times in a function definition. I would imagine this has to do with named argument passing. Similar tricks could still be used, however, by merely appending numbers: "def function(param1, _0, param3, key1=True, key2=False, **_1)".
In the case of matching signatures, I would be extremely cautious about renaming any arguments or eliminating keyword arguments due to the ability to pass any arguments by name.
For example, in the example provided (presuming logic in the naming of the parameters in the base class and eliminating the ** part), a valid call could look like: function(param3=a, param1=b, param2=c), which would result in errors if the parameters got renamed.

On Feb 10, 2015, at 13:01, Spencer Brown spencerb21@live.com wrote:
Basically, in any location where a variable name is provided for assignment (tuple unpacking, for loops, function parameters, etc) a variable name can be replaced by '...' to indicate that that value will not be used.
The idiomatic way to do this has always been to assign to _. All of your examples work today with _, and I don't think they look significantly better with .... (Of course _ has the problem that when it's being used for gettext in an app, it can't be used for the disposable variable in the same app, but people have dealt with that for decades without any major complaints.)
So the only real substance to your proposal is that it opens up the possibility for compiler optimizations. But most of these seem like pretty narrow possibilities. For example, you suggest that "for ... in range(100):" could be optimized to a simple C loop. But "for i in range(100):" could just as easily be optimized to a simple C loop. if you can prove that range is still the builtin and therefore this yields exactly 100 times so you can skip the __next__ calls, surely you can also prove that it yields exactly the first 100 ints, so you can still skip the __next__ calls even if you do want those ints.
But it's pretty hard for a static optimizer to prove that range is still range, so you really can't skip the __next__ even in the ellipsis case.
Either way, the only thing you're saving is an assignment--an extra addref/decref pair and a pointer copy. That's not _nothing_, but it's not that big a deal compared to, say, a __next__ call, or a typical loop body. And if you really need to remove those, you could pretty easily remove dead local assignments, which would optimize everyone's existing code automatically, instead of requiring them to write new code that's incompatible with 3.4 to get the benefit. Presumably the reason CPython doesn't do this is that the small benefit has never been worth the time it would take for anyone to implement and maintain the optimization.
This would be syntactically equivalent to del-ing the variable immediately after, except that the assignment never needs to be done.
Examples:
tup = ('val1', 'val2', (123, 456, 789)) name, ..., (..., value, ...) = tup
instead of:
name = tup[0] value = tup[2][1]
This shows slightly more clearly what format the tuple will be in, and provides some additional error-checking - the unpack will fail if the tuple is a different size or format.
for ... in range(100): pass
This particular case could be optimised by checking to see if the iterator has a len() method, and if so directly looping that many times in C instead of executing the __next__() method repeatedly.
for i, ... in enumerate(object):
is equivalent to:
for i in range(len(object)):
The Ellipse form is slightly more clear and works for objects without len().
first, second, *... = iterator
In the normal case, this would extract the first two values, and exhaust the rest of the iterator. Perhaps this could be special-cased so the iterator is left alone, and the 3rd+ values are still available.
def function(param1, ..., param3, key1=True, key2=False, **...): pass
This could be useful when overriding functions in a subclass, or writing callback functions. Here we don't actually need the 2nd argument. The '**...' would be the only allowable form of Ellipse in keyword arguments, and just allows any other keywords to be given to the function.
- Spencer
Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On 10.02.2015 22:01, Spencer Brown wrote:
Basically, in any location where a variable name is provided for assignment (tuple unpacking, for loops, function parameters, etc) a variable name can be replaced by '...' to indicate that that value will not be used. This would be syntactically equivalent to del-ing the variable immediately after, except that the assignment never needs to be done.
Examples:
tup = ('val1', 'val2', (123, 456, 789)) name, ..., (..., value, ...) = tup
instead of:
name = tup[0] value = tup[2][1]
This shows slightly more clearly what format the tuple will be in, and provides some additional error-checking - the unpack will fail if the tuple is a different size or format.
I don’t like that syntax at all. With _ it is much more readable. In that context, ... rather looks like what *_ would do: Leaving out many elements (even though that is not possible in python currently, at least not in (*_, foo, *_); that only makes things worse).
This may be arbitrarily confusing. As others have said, just use
tup = ('val1', 'val2', (123, 456, 789)) name, _, (_, value, _) = tup
regards, jwi

How about zero characters between commas? In ES6 destructing assignment you'd writes something like ,,c = (1,2,3)
On Wed, Feb 11, 2015 at 9:38 AM, Jonas Wielicki j.wielicki@sotecware.net wrote:
On 10.02.2015 22:01, Spencer Brown wrote:
Basically, in any location where a variable name is provided for assignment (tuple unpacking, for loops, function parameters, etc) a variable name can be replaced by '...' to indicate that that value will not be used. This would be syntactically equivalent to del-ing the variable immediately after, except that the assignment never needs to be done.
Examples:
tup = ('val1', 'val2', (123, 456, 789)) name, ..., (..., value, ...) = tup
instead of:
name = tup[0] value = tup[2][1]
This shows slightly more clearly what format the tuple will be in, and provides some additional error-checking - the unpack will fail if the tuple is a different size or format.
I don’t like that syntax at all. With _ it is much more readable. In that context, ... rather looks like what *_ would do: Leaving out many elements (even though that is not possible in python currently, at least not in (*_, foo, *_); that only makes things worse).
This may be arbitrarily confusing. As others have said, just use
tup = ('val1', 'val2', (123, 456, 789)) name, _, (_, value, _) = tup
regards, jwi
Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On 11/02/2015 20:06, Greg Ewing wrote:
Daniel Holth wrote:
How about zero characters between commas? In ES6 destructing assignment you'd writes something like ,,c = (1,2,3)
Wouldn't play well with the syntax for 1-element tuples:
c, = stuff
Is len(stuff) expected to be 1 or 2?
Does that matter? In either case the intent is to evaluate stuff and assign its first element to c. We could have a rule that when the left hand side of an assignment is a tuple that ends in a final comma then unpacking stops at the final comma, and it doesn't matter whether there are any more values to unpack. (Perhaps multiple final commas could mean "unpack until the last comma then stop, so c,,, = stuff would mean "raise an exception if len(stuff)<3; otherwise assign the first element of stuff to c".) It could even work for infinite generators!
I think it's a neat idea, and it would be good if it could be made to work. Admittedly it would be strictly backwards-incompatible, since c, = [1,2] would assign 1 to c rather than (as now) raising ValueError. But making something "work" instead of raising an exception is likely to break much less code that changing/stopping something from "working". Rob Cliffe

On 02/12/2015 06:58 AM, Rob Cliffe wrote:
On 11/02/2015 20:06, Greg Ewing wrote:
Daniel Holth wrote:
How about zero characters between commas? In ES6 destructing assignment you'd writes something like ,,c = (1,2,3)
Wouldn't play well with the syntax for 1-element tuples:
c, = stuff
Is len(stuff) expected to be 1 or 2?
Does that matter?
Yes, it matters. I have code that had better raise an exception if 'stuff' is not exactly one element.
In either case the intent is to evaluate stuff and assign its first element to c.
No, its intent is to assign the only element to c, and raise if there are more, or fewer, elements.
We could have a rule that when the left hand side of an assignment is a tuple that ends in a final comma then unpacking stops at the final comma, and it doesn't matter whether there are any more values to unpack. (Perhaps multiple final commas could mean "unpack until the last comma then stop, so c,,, = stuff
a) That's ugly. b) Special cases aren't special enough to break the rules.
would mean "raise an exception if len(stuff)<3; otherwise assign the first element of stuff to c".) It could even work for infinite generators!
Uh, you're kidding, right?
But making something "work" instead of raising an exception is likely to break much less code that changing/stopping something from "working".
It would break mine, so no thanks.
-- ~Ethan~

On 12/02/2015 18:15, Ethan Furman wrote:
On 02/12/2015 06:58 AM, Rob Cliffe wrote:
On 11/02/2015 20:06, Greg Ewing wrote:
Daniel Holth wrote:
How about zero characters between commas? In ES6 destructing assignment you'd writes something like ,,c = (1,2,3)
Wouldn't play well with the syntax for 1-element tuples:
c, = stuff
Is len(stuff) expected to be 1 or 2?
Does that matter?
Yes, it matters. I have code that had better raise an exception if 'stuff' is not exactly one element.
In either case the intent is to evaluate stuff and assign its first element to c.
No, its intent is to assign the only element to c, and raise if there are more, or fewer, elements.
Hm. With respect, that doesn't seem to me like a common use case. I would have thought that more often a mismatch between the number of elements to be unpacked and the number of target variables would be a bug. (OK, perhaps it is but you want the runtime to pick up such bugs.)
We could have a rule that when the left hand side of an assignment is a tuple that ends in a final comma then unpacking stops at the final comma, and it doesn't matter whether there are any more values to unpack. (Perhaps multiple final commas could mean "unpack until the last comma then stop, so c,,, = stuff
a) That's ugly.
That's subjective. (It may look like "grit on Tim's monitor", but it's *meaningful* grit, not grit required by overblown language syntax.)
b) Special cases aren't special enough to break the rules.
I don't understand this comment.
would mean "raise an exception if len(stuff)<3; otherwise assign the first element of stuff to c".) It could even work for infinite generators!
Uh, you're kidding, right?
No, I wasn't kidding. I was suggesting that only as many values as required by the LHS should be extracted from the generator. So there is no infinite loop even though the generator itself is (potentially or actually) non-terminating.
But making something "work" instead of raising an exception is likely to break much less code that changing/stopping something from "working".
It would break mine, so no thanks.
See above. Your use case doesn't strike me as typical.
-- ~Ethan~
Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
No virus found in this message. Checked by AVG - www.avg.com Version: 2014.0.4800 / Virus Database: 4257/9105 - Release Date: 02/13/15
participants (30)
-
Andrew Barnert
-
Antoine Pitrou
-
Barry Warsaw
-
Ben Finney
-
Chris Angelico
-
Chris Barker
-
Chris Kaynor
-
Daniel Holth
-
Eric V. Smith
-
Ethan Furman
-
Greg Ewing
-
Jonas Wielicki
-
M.-A. Lemburg
-
Masklinn
-
MRAB
-
Neil Girdhar
-
Nick Coghlan
-
Nikolaus Rath
-
Paul Moore
-
random832@fastmail.us
-
Rob Cliffe
-
Ron Adam
-
Serhiy Storchaka
-
Spencer Brown
-
Stephan Hoyer
-
Stephen J. Turnbull
-
Steven D'Aprano
-
Terry Reedy
-
Wichert Akkerman
-
Zero Piraeus