[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Christopher Barker
I may get a chance to look carefully at this in a bit, but for now:

On Tue, Sep 1, 2020 at 6:38 PM Ricky Teachey  wrote:

> Sorry for all the replies but I'm honestly very unsure how do this
> correctly under Steven's proposal.
>

That's OK. It's going to be tricky, and keeping backward compatibility
makes that necessary.

And, in fact, the current sytax is pretty tricky as well. Say you want to
make a class that takes multiple indices -- like a Mtraix, for instance.

your __getitem__ looks like:

def __getitem__(self, index):

as they all do. But what might index be?

It could be one of:
 * an object with an __index__ method -- so a single index, simple
 * a slice object
 * a tuple, where each item in the tuple could be both of the above.

Or, of course, it could be  invalid, and you need to raise an Exception
with a meaningful message.

So there's a lot of logic there and we haven't even started in the keywords
:-)

But that's all OK, as the number of people that need to write these methods
is small, and the number of people that can use the feature is large.

-CHB

-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/2ORJJKUTW2LVCES52Q5LCCH6T3DTJFWL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Random832
On Tue, Sep 1, 2020, at 21:06, Ricky Teachey wrote:
> Here's my attempt, it is probably lacking. I'm five years into a 
> self-taught venture in python... If I can't get this right the first 
> time, it worries me a little. 
> 
> 
> MISSING=object()
> 
> def __getitem__(self, key=MISSING, time=MISSING, money=MISSING):
> if time is MISSING or money is MISSING:
> if time is not MISSING and key is not MISSING:
> money = key
> elif money is not MISSING and key is not MISSING:
> time = key
> else:
> time, money = key
> 
> Is this right? Wrong? The hard way? The slow way? 
> 
> What about when there are three arguments? What then?

I'm using () rather than a MISSING as the sentinel here because it makes the 
code simpler. For the same reason, if we need to choose a key to pass in by 
default for a[**kwargs only] without defining a () in __getitem__, I have 
consistently advocated using () for this. Likewise, *not* having a default [or 
requiring the method to define its own default] key presents a slight problem 
for __setitem__, illustrated below.

def __getitem__(self, key=(), /, **kwargs):
return self._getitem(*(key if isinstance(key, tuple) else (key,)), **kwargs)
def __setitem__(self, key=(), value=???, /, **kwargs):
return self._setitem(value, *(key if isinstance(key, tuple) else (key,)), 
**kwargs)
def _getitem(self, time, money):
...
def _setitem(self, value, time, money):
...
[delitem the same as getitem]

Basically, you can easily write code that leverages the existing function 
argument parsing, simply by performing a function call.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/EWJAKIBXQQJNMWT7EXZHAKOUP35YOREV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Brendan Barnwell

On 2020-09-01 07:24, Steven D'Aprano wrote:

Operator overloading is a thing, so if you want `a + b` to mean looking
up a database for `a` and writing it to file `b`, you can. But the
blessed use-cases for the `+` operator are numeric addition and sequence
concatenation.

Anything else is an abuse of the operator: permitted, possibly a*mild*
abuse, but at best it's a bit wiffy.


	I don't agree with that at all.  I see the operators as abstract 
symbols indicating vague areas of semantic space.  Any operation that 
involves "combining" of some sort is a fair and non-wiffy use of `+`. 
Any operation that involves "removal" of some sort is a fair and 
non-wiffy use of `-`.  And so on.  For instance, some parsing libraries 
use `+` or `>>` to indicate sequences of syntactic constructs, and 
that's great.  (I actually think that this flexibility should be more 
clearly expressed in the Python docs, but that's a separate "idea" that 
I'll have to post about another time.)


	For me the equally important (or more important) question is not what 
an individual operator in isolation means, but how a given type 
coherently organizes the operators.  In other words, it's not enough to 
have `+` defined to mean something sensible for a given type; the type 
must assign its operations to operators in such a way that you don't get 
confused about which ones is `+` and which one is `*` and which one is 
`>>` and so on.  Similarly, even if a particular use of `+` seems odd 
conceptually on its own, it can still be excellent if it fits in with 
the overall scheme of how operators work on that type.


--
Brendan Barnwell
"Do not follow where the path may lead.  Go, instead, where there is no 
path, and leave a trail."

   --author unknown
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/FFPE6MHLZOAVDGF2JUFSISIEI6P5B22E/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: On blessed abuse of operators [was: Changing item dunder ...]

2020-09-01 Thread Greg Ewing

On 2/09/20 8:35 am, Chris Angelico wrote:

Maybe
we need a different term for this kind of overloading, where we're not
even TRYING to follow the normal semantics for that operation, but are
just doing something because it "feels right".


Operator repurposing?

--
Greg
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/VWGMUWUER6QBJSVXOW5CZVUQPT62PTNB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread Greg Ewing

On 2/09/20 5:14 am, Stephan Hoyer wrote:
On Tue, Sep 1, 2020 at 9:59 AM David Mertz I think we need this for the same reason why we need **kwargs in normal 
function calls: it makes it possible to forward dictionaries of 
arguments to another method.


If we don't have dict unpacking, you'd have to write 
obj.__getitem__(**kwargs) rather than obj[**kwargs], which is much more 
verbose and goes against the principle that you shouldn't need to call 
double-underscore methods in normal Python code.


It's also not even quite correct! As another message posted recently
pointed out, if 'other' happens to be a class object, __class_getitem__
should be called instead, if it exists:

def __getitem__(self, index, **kwds):
g = None
if isinstance(other, type):
g = getattr(other, '__class_getitem__', None)
if g is None:
g = other.__getitem__
return g(index, **kwds)

This is getting pretty tricky and convoluted. (I'm not sure it's
completely correct even now, since it doesn't check whether
__class_getitem__ is a class method.) It certainly won't remain
correct if the rules for indexing method lookup change in the
future.

If a[**kwds] is allowed, on the other hand, it's easy to write
index forwarding code that is straightforward, obvious and
future-proof.

--
Greg
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/OS6QVLKTMRMCXIRZH76FPP3ZAIWVQXOG/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Ricky Teachey
On Tue, Sep 1, 2020, 9:20 PM Ricky Teachey  wrote:

> On Tue, Sep 1, 2020, 9:06 PM Ricky Teachey  wrote:
>
>> On Tue, Sep 1, 2020, 8:35 PM Guido van Rossum  wrote:
>>
>>> On Tue, Sep 1, 2020 at 4:57 PM Greg Ewing 
>>> wrote:
>>>
 On 2/09/20 2:24 am, Steven D'Aprano wrote:
 > On Sun, Aug 30, 2020 at 05:49:50PM +1200, Greg Ewing wrote:
 >> On 30/08/20 3:06 pm, Steven D'Aprano wrote:
 >>> On Thu, Aug 27, 2020 at 11:13:38PM +1200, Greg Ewing wrote:
 >>>
  a[17, 42]
  a[time = 17, money = 42]
  a[money = 42, time = 17]
  >
>>>
>>> I agree it's a fine use case. Using the currently prevailing proposal
>>> (which I steadfastly will refer to as "Steven's proposal") it's quite
>>> possible to implement this.
>>>
>>
>>> --
>>> --Guido van Rossum (python.org/~guido)
>>>
>>
>> Can someone tell me...
>>
>
>> Is this right? Wrong? The hard way? The slow way?
>>
>
> ...Still not sure if that is right.
>

Actually I suppose this is the best way to do it:

def _real_signature(time, money): ...

class C:
def __getitem__(self, key, **kwargs):
try:
_real_signature(*key, **kwargs)
except TypeError:
try:
_real_signature(key, **kwargs)
except TypeError:
raise TypeError() from None

Sorry for all the replies but I'm honestly very unsure how do this
correctly under Steven's proposal.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/MSENNTHMJSU25NOZ5TJ3S2S2VZHQWYRF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Ricky Teachey
On Tue, Sep 1, 2020, 9:06 PM Ricky Teachey  wrote:

> On Tue, Sep 1, 2020, 8:35 PM Guido van Rossum  wrote:
>
>> On Tue, Sep 1, 2020 at 4:57 PM Greg Ewing 
>> wrote:
>>
>>> On 2/09/20 2:24 am, Steven D'Aprano wrote:
>>> > On Sun, Aug 30, 2020 at 05:49:50PM +1200, Greg Ewing wrote:
>>> >> On 30/08/20 3:06 pm, Steven D'Aprano wrote:
>>> >>> On Thu, Aug 27, 2020 at 11:13:38PM +1200, Greg Ewing wrote:
>>> >>>
>>>  a[17, 42]
>>>  a[time = 17, money = 42]
>>>  a[money = 42, time = 17]
>>>  >
>>
>> I agree it's a fine use case. Using the currently prevailing proposal
>> (which I steadfastly will refer to as "Steven's proposal") it's quite
>> possible to implement this.
>>
>
>> --
>> --Guido van Rossum (python.org/~guido)
>>
>
> Can someone tell me...
>

> Is this right? Wrong? The hard way? The slow way?
>

Actually just realized I definitely did get it wrong:

def __getitem__(self, key=MISSING, time=MISSING, money=MISSING):
if time is MISSING or money is MISSING:
if time is not MISSING and key is not MISSING:
money, key = key, MISSING
elif money is not MISSING and key is not MISSING:
time, key = key, MISSING
elif time is MISSING and money is MISSING:
(time, money), key = key, MISSING
if key is not MISSING:
raise TypeError()

Still not sure if that is right.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/HISY3CUPKUBV6TJEHXNANIKJL4IGVUEW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Ricky Teachey
On Tue, Sep 1, 2020, 8:35 PM Guido van Rossum  wrote:

> On Tue, Sep 1, 2020 at 4:57 PM Greg Ewing 
> wrote:
>
>> On 2/09/20 2:24 am, Steven D'Aprano wrote:
>> > On Sun, Aug 30, 2020 at 05:49:50PM +1200, Greg Ewing wrote:
>> >> On 30/08/20 3:06 pm, Steven D'Aprano wrote:
>> >>> On Thu, Aug 27, 2020 at 11:13:38PM +1200, Greg Ewing wrote:
>> >>>
>>  a[17, 42]
>>  a[time = 17, money = 42]
>>  a[money = 42, time = 17]
>>  >
>
> I agree it's a fine use case. Using the currently prevailing proposal
> (which I steadfastly will refer to as "Steven's proposal") it's quite
> possible to implement this.
>

> --
> --Guido van Rossum (python.org/~guido)
>

Can someone tell me: what will be the canonical way to allow both named or
unnamed arguments under Steven's proposal?

With function call syntax, it is trivial:

def f(time, money): ...

The interpreter handles it all for us:

>>> f(17, 42)
>>> f(17, money=42)
>>> f(time=17, money=42)
>>> f(money=42, time=17)

But what is the way when we can't fully benefit from python function
signature syntax?

Here's my attempt, it is probably lacking. I'm five years into a
self-taught venture in python... If I can't get this right the first time,
it worries me a little.


MISSING=object()

def __getitem__(self, key=MISSING, time=MISSING, money=MISSING):
if time is MISSING or money is MISSING:
if time is not MISSING and key is not MISSING:
money = key
elif money is not MISSING and key is not MISSING:
time = key
else:
time, money = key

Is this right? Wrong? The hard way? The slow way?

What about when there are three arguments? What then?
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/DS4FBFZFPZPS3YSKC2L2ZAV72QBTSPB3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread Greg Ewing

On 2/09/20 3:44 am, Steven D'Aprano wrote:

(9) Keyword-only subscripts are permitted:

 obj[spam=1, eggs=2]
 # calls type(obj).__getitem__(spam=1, eggs=2)

 del obj[spam=1, eggs=2]
 # calls type(obj).__delitem__(spam=1, eggs=2)


An alternative is to pass an empty tuple as the index when there
are no positional args. That would make the following less of a
special case:


but note that the setter is awkward since the signature requires the
first parameter:

 obj[spam=1, eggs=2] = value
 # wants to call type(obj).__setitem__(???, value, spam=1, eggs=2)



Gotchas
---

 def __getitem__(self, index, direction='north')

if the caller uses this:

 obj[0, 'south']

they will probably be surprised by the method call:

>

 obj.__getitem__((0, 'south'), direction='north')

Solution: best practice suggests that keyword subscripts should be
flagged as keyword-only when possible:

 def __getitem__(self, index, *, direction='north')


Note that this will only help if the user looks at and takes careful
notice of the signature of the __getitem__ method -- it won't actually
prevent them from attempting to do obj[0, 'south'] and won't affect
the result if they do.

A better best practice would be to use a decorator such as the one
I posted earlier to convert the packed positional args into real
ones. Then they will get the expected result in most cases.

--
Greg
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/N7FXYFGIP2SAZ6BAGAI7LKCAHWC7SRQC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Guido van Rossum
On Tue, Sep 1, 2020 at 4:57 PM Greg Ewing 
wrote:

> On 2/09/20 2:24 am, Steven D'Aprano wrote:
> > On Sun, Aug 30, 2020 at 05:49:50PM +1200, Greg Ewing wrote:
> >> On 30/08/20 3:06 pm, Steven D'Aprano wrote:
> >>> On Thu, Aug 27, 2020 at 11:13:38PM +1200, Greg Ewing wrote:
> >>>
>  a[17, 42]
>  a[time = 17, money = 42]
>  a[money = 42, time = 17]
>  >
> > Compares to the majority of realistic examples given in this discussion
> > and the PEP, your example doesn't look to me like an item or key lookup.
> > It looks more like a function call of some sort.
> >
> > I know that, in a sense, subscript lookups are like function calls, and
> > I also acknowledge that I don't know your intended semantics of that
> > example.
>
> It was a reference to earlier discussions of pandas and xarray, where
> there is a notion of axes having names, and a desire to be able to
> specify index values by name, for the same reasons that we sometimes
> want to specify function arguments by name.
>
> It's true that you can't tell just by looking at an indexing expression
> what the semantics of the keywords are, but the same is true of function
> calls. We rely on contextual knowledge about what the function does in
> order to interpret the keywords.
>
> Likewise here. If you know from context that a is an array-like object
> with axes named 'time' and 'money', then I think the meaning of the
> indexing expression will be quite clear. I also think that it's
> something people will naturally expect to be able to use index keywords
> for -- to the point that if they can't, their reaction will be
> "Why the flipping heck not?"
>
> Which is why I was somewhat perplexed when it was suggested that we
> should discount this use case purely because it wasn't cited in the
> original proposal (which turned out to be wrong anyway).
>

I agree it's a fine use case. Using the currently prevailing proposal
(which I steadfastly will refer to as "Steven's proposal") it's quite
possible to implement this.

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/HJFXL6QJRED4DOIFGYDXDH3VZDBBEAE5/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP-0472 revisited - draft

2020-09-01 Thread Greg Ewing

On 2/09/20 3:20 am, Christopher Barker wrote:
I think that type hints are used in specific places, and thus the 
interpreter could know if a given [] was a type hint or an indexing 
operation, and thus could dispatch it differently.


I don't think so. We need to be able to do things like

WibbleCollection = List[Wibble]

def f(wibs : WibbleCollection):
...

--
Greg
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/KSAPAEF7ARPYRCLWL6T7MYZCAVFOWNCD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Greg Ewing

On 2/09/20 2:24 am, Steven D'Aprano wrote:

On Sun, Aug 30, 2020 at 05:49:50PM +1200, Greg Ewing wrote:

On 30/08/20 3:06 pm, Steven D'Aprano wrote:

On Thu, Aug 27, 2020 at 11:13:38PM +1200, Greg Ewing wrote:


a[17, 42]
a[time = 17, money = 42]
a[money = 42, time = 17]

>

Compares to the majority of realistic examples given in this discussion
and the PEP, your example doesn't look to me like an item or key lookup.
It looks more like a function call of some sort.

I know that, in a sense, subscript lookups are like function calls, and
I also acknowledge that I don't know your intended semantics of that
example.


It was a reference to earlier discussions of pandas and xarray, where
there is a notion of axes having names, and a desire to be able to
specify index values by name, for the same reasons that we sometimes
want to specify function arguments by name.

It's true that you can't tell just by looking at an indexing expression
what the semantics of the keywords are, but the same is true of function
calls. We rely on contextual knowledge about what the function does in
order to interpret the keywords.

Likewise here. If you know from context that a is an array-like object
with axes named 'time' and 'money', then I think the meaning of the
indexing expression will be quite clear. I also think that it's
something people will naturally expect to be able to use index keywords
for -- to the point that if they can't, their reaction will be
"Why the flipping heck not?"

Which is why I was somewhat perplexed when it was suggested that we
should discount this use case purely because it wasn't cited in the
original proposal (which turned out to be wrong anyway).

--
Greg
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/Z2GOU65V2EU27FVQDFF3EJUZRGOIS6TD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: On blessed abuse of operators [was: Changing item dunder ...]

2020-09-01 Thread Chris Angelico
On Wed, Sep 2, 2020 at 3:48 AM Stephen J. Turnbull
 wrote:
>
> A digression on abuse of operators, notation, and "abuse of notation".
>
> Steven D'Aprano writes:
>  > On Sun, Aug 30, 2020 at 05:49:50PM +1200, Greg Ewing wrote:
>
>  > > I don't see why we need to pick one use case to bless as the
>  > > official "true" use case.
>  >
>  > We do that for every other operator and operator-like function.
>  >
>  > Operator overloading is a thing, so if you want `a + b` to mean
>  > looking up a database for `a` and writing it to file `b`, you
>  > can. But the blessed use-cases for the `+` operator are numeric
>  > addition and sequence concatenation.
>
> Of course the example is abusive.  But not being "blessed" isn't the
> reason.  (And shouldn't the notation be "b += a" for that operation? ;-)
>

Possibly a better example would be path division in Python, or stream
left/right shift in C++. What does it mean to divide a path by a
string? What does it mean to left-shift std::cout by 5? Those uses
don't make a lot of sense based on the operations involved, but people
accept them because the symbols look right:

>>> pathlib.Path("/") / "foo" / "bar" / "quux"
PosixPath('/foo/bar/quux')

Is that abuse of notation or something else? Whatever it is, it's not
"operator overloading" in its normal sense; division is normally the
inverse of multiplication, but there's no way you can multiply that by
"quux" to undo that last operation, and nobody would expect so. Maybe
we need a different term for this kind of overloading, where we're not
even TRYING to follow the normal semantics for that operation, but are
just doing something because it "feels right".

ChrisA
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/ZAV7YEBWDL3KBXM2VI6QYV66H4AIV5JW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP-0472 revisited - draft

2020-09-01 Thread Christopher Barker
On Tue, Sep 1, 2020 at 9:51 AM Guido van Rossum  wrote:

> On Tue, Sep 1, 2020 at 8:20 AM Christopher Barker 
> wrote:
>
>> Question: it strikes me that the use case of [] for type hints is
>> logically quite different than for indexing. So do they need to use the
>> same syntax / dunder?
>>
>> I think that type hints are used in specific places, and thus the
>> interpreter could know if a given [] was a type hint or an indexing
>> operation, and thus could dispatch it differently.
>> ...
>> If it's not technically possible to make the distinction, then it's a
>> non-issue, but if it is, it may be worth considering.
>>
>
> Type hints are indeed dispatched differently, but this is done based on
> information that is only available at runtime. Since PEP 560, for `x[y]`,
> if no `__getitem__` method is found, and `x` is a type (class) object, and
> `x` has a class method `__class_getitem__`, that method is called.
> Extending this with keyword args is straightforward. Modifying the compiler
> to generate different bytecode for this case is essentially impossible.
>

Thanks -- then that answers my question -- no it's not technically
possible. Oh well.

-CHB


-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/TXDAWNYUPIVR7Z6UOPY5ESYWVKACWNCA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Christopher Barker
very related to this conversation -- isn't the use of [] for indexing and
its use in Type hinting functionally very different as well?

-CHB



On Tue, Sep 1, 2020 at 9:55 AM David Mertz  wrote:

> > On 30/08/20 3:06 pm, Steven D'Aprano wrote:
>
>> (There are a few gray areas, such as array/matrix/vector addition, which
>> sneak into the "acceptable" area by virtue of their long usage in
>> mathematics.)
>>
>
> >>> a / b/ c
> 0.01
> >>> home / 'git' / 'pip'
> PosixPath('/home/dmertz/git/pip')
>
> But yes, it's just another example. And when I teach it I always say "this
> is a funny but intuitive overloading."
>
> --
> The dead increasingly dominate and strangle both the living and the
> not-yet born.  Vampiric capital and undead corporate persons abuse
> the lives and control the thoughts of homo faber. Ideas, once born,
> become abortifacients against new conceptions.
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/5Y6ST6HFIOYIAPMKXQ4VZT4AT2MZWX6Y/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/I7J6VASHOTCVFGFGZD3DON3NSLF5SLXJ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread Dominik Vilsmeier

On 01.09.20 17:44, Steven D'Aprano wrote:


(9) Keyword-only subscripts are permitted:

 obj[spam=1, eggs=2]
 # calls type(obj).__getitem__(spam=1, eggs=2)

 del obj[spam=1, eggs=2]
 # calls type(obj).__delitem__(spam=1, eggs=2)

but note that the setter is awkward since the signature requires the
first parameter:

 obj[spam=1, eggs=2] = value
 # wants to call type(obj).__setitem__(???, value, spam=1, eggs=2)

Proposed solution: this is a runtime error unless the setitem method
gives the first parameter a default, e.g.:

 def __setitem__(self, index=None, value=None, **kwargs)

Note that the second parameter will always be present, nevertheless, to
satisfy the interpreter, it too will require a default value.

(Editorial comment: this is undoubtably an awkward and ugly corner case,
but I am reluctant to prohibit keyword-only assignment.)


Why does the signature require the first `index` parameter? When I see
`obj[spam=1, eggs=2] = value` there's no positional index and so I
wouldn't expect one to be passed. Similar to how the following works:

    >>> def foo():
    ... pass
    ...
    >>> foo(*())

If there's nothing to unpack nothing will be assigned to any of the
parameters.

So the following signature would work with keyword-only subscripts:

    def __setitem__(self, value, **kwargs):

I don't how the `[] =` operator is translated to `__setitem__` at the
implementation level, so perhaps the no-positional-index case would
require yet another opcode, but thinking of it in the following way it
would definitely be possible:

    obj.__setitem__(*(pos_index + (value,)), **kwargs)

where `pos_index` is the positional index collected from the `[]`
operator as a tuple (and if no such index is given it defaults to the
empty tuple). This matches the above no-index signature of
`__setitem__`. This is also the signature of the corresponding
`__getitem__` and `__delitem__` methods.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/DDNIG6AWODEMEU22IG4BKLXLXX26YZL4/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] On blessed abuse of operators [was: Changing item dunder ...]

2020-09-01 Thread Stephen J. Turnbull
A digression on abuse of operators, notation, and "abuse of notation".

Steven D'Aprano writes:
 > On Sun, Aug 30, 2020 at 05:49:50PM +1200, Greg Ewing wrote:

 > > I don't see why we need to pick one use case to bless as the
 > > official "true" use case. 
 > 
 > We do that for every other operator and operator-like function.
 > 
 > Operator overloading is a thing, so if you want `a + b` to mean
 > looking up a database for `a` and writing it to file `b`, you
 > can. But the blessed use-cases for the `+` operator are numeric
 > addition and sequence concatenation.

Of course the example is abusive.  But not being "blessed" isn't the
reason.  (And shouldn't the notation be "b += a" for that operation? ;-)

 > Anything else is an abuse of the operator: permitted, possibly a *mild* 
 > abuse, but at best it's a bit wiffy.

I don't agree.  The reasons for picking a "blessed" use case for
operators do not include "to exclude other uses".  Rather, they are to
help the language designer decide things like precedence and
associativity, to give developers some guidance in choosing an
operator to overload for a two-argument function, and to provide
readers with a familiar analog for the behavior of an operator.

For example, sequence concatenation is not "blessed because it's
blessed".  It's blessed because it just works.  What does "5 * 'a' +
'b'" mean to the reader?  Is the result 'ab', or 'ababababab'?
The reader knows it's the former, and that is the right answer for the
developer because 'ababababab' == 5 * 'ab' -- there's another way to
construct that without parenthesis.  Why is 5 * 'a' == 'a'?
Because 5 * 'a' == 'a' + 'a' + 'a' + 'a' + 'a'.  None of this is an
accident.  There's nothing wiffy about it.

Recall that some people don't like the use of '+' for sequence
concatenation because the convention in abstract algebra is that '+'
denotes an commutative associative binary operation, while '*' need
not be commutative.  But I think you don't want to use '*' for
sequence concatenation in Python because 5 * 'a' * 'b' is not
associative: it matters which '*' you execute first.

Where things get wiffy is when you have conflicting requirements, such
as if for some reason you want '*' to bind more tightly than '+' which
in turn should bind at least as tightly as '/'.  You can swap the
semantics of '+' and '/' but that may not "look right" for the types
involved.  You may want operator notation badly for concise expression
of long programs, but it will always be wiffy in this circumstance.
And use of "a + b" to denote "looking up a database for `a` and
writing it to file `b`" is abusive, but not of notation.  It's an
abuse because it doesn't help the reader remember the semantics, and I
don't think that operation is anywhere near as composable as
arithmetic expressions are.

 > If you don't like the term "abuse", I should say I am heavily
 > influenced by its use in mathematics where "abuse of notation" is
 > not considered a bad thing:
 > 
 > https://en.wikipedia.org/wiki/Abuse_of_notation

I think operator overloading and abuse of notation are quite different
things, though.

Using '*' to denote matrix multiplication or "vertical composition of
morphisms in a category" is not an abuse of notation.  It's
overloading, using the same symbol for a different operation in a
different domain.  Something like numpy broadcasting *is* an abuse of
notation, at least until you get used to it: you have nonconforming
matrices, so the operation "should" be undefined (in the usual
treatment of matrices).  If you take "undefined" *literally*, however,
there's nothing to stop you from *defining* the operation for a
broader class of environments, and it's not an abuse to do so.

So if you have a class Vector and a function mean(x: Vector) ->
Vector,

v = Vector(1, 2, 3)
m = mean(v)# I Feel Like a Number, but I am not
variance = (v - m) * (v - m) / len(v)

"looks like" an abuse of notation to the high school student targeted
by the "let's have a Matrix class in stdlib" thread.  But as Numpy
arrays show, that's implementable, it's well-defined, and once you get
used to it, the meaning is clear, even in the general case.  You could
do the same computation with lists

v = [1, 2, 3]
m = sum(v)/len(v)
variance = (v - len(v) * [m]) * (v - len(v) * [m]) / len(v)

but I don't think that's anywhere near as nice.

To call definitions extending the domain of an operator "abuse of
notation" is itself an abuse of language, because abuse of notation
*can't happen* in programming!  Abuse of notation is synecdoche (use of
a part to denote the whole) or metonymy (use of a thing to represent
something related but different).  But do either in programming, and
you get an incorrect program.  No matter how much you yell at Guido,
the Python translator is never going to "get" synecdoche or metonymy
-- it's just going to do what you don't want it to do.
___
Python-ide

[Python-ideas] Re: Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread Stephan Hoyer
On Tue, Sep 1, 2020 at 9:59 AM David Mertz  wrote:

> On Tue, Sep 1, 2020 at 11:45 AM Steven D'Aprano 
> wrote:
>
>> (8) Dict unpacking is permitted:
>>
>> items = {'spam': 1, 'eggs': 2}
>> obj[index, **items]
>> # equivalent to obj[index, spam=1, eggs=2]
>>
>
> I would prefer to disallow this, at least initially.  None of the use
> cases I've seen have an actual need for dict unpacking, and it generally
> just seems to follow from the analogy with function calls.  I think not
> allowing that encourages use of index-related operations rather than
> "another spelling of `.__call__()`.
>

I think we need this for the same reason why we need **kwargs in normal
function calls: it makes it possible to forward dictionaries of arguments
to another method.

In particular, indexing methods with a signature like __getitem__(self,
value=None, /, **kwargs) will be useful for indexing on "labeled arrays",
where dimension names are determined dynamically. Then assuredly someone
(e.g., in library code) is going to want to build up these kwargs with
dynamic keys.

If we don't have dict unpacking, you'd have to write
obj.__getitem__(**kwargs) rather than obj[**kwargs], which is much more
verbose and goes against the principle that you shouldn't need to call
double-underscore methods in normal Python code. It's also more error
prone, particularly in the mixed positional/keyword argument case, because
you have to reverse engineer Python's syntax to figure out tuple packing.


>
> --
> The dead increasingly dominate and strangle both the living and the
> not-yet born.  Vampiric capital and undead corporate persons abuse
> the lives and control the thoughts of homo faber. Ideas, once born,
> become abortifacients against new conceptions.
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/DZLDC5ET5UUGFBOXJ534L4NWFHPQQDG6/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/ZM6TFWVHBJ6OV5TBTEXQ5622OAKZPIAB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread David Mertz
Thank you Steven,

This exactly matches what my goal would be, except the below.

On Tue, Sep 1, 2020 at 11:45 AM Steven D'Aprano  wrote:

> (8) Dict unpacking is permitted:
>
> items = {'spam': 1, 'eggs': 2}
> obj[index, **items]
> # equivalent to obj[index, spam=1, eggs=2]
>

I would prefer to disallow this, at least initially.  None of the use cases
I've seen have an actual need for dict unpacking, and it generally just
seems to follow from the analogy with function calls.  I think not allowing
that encourages use of index-related operations rather than "another
spelling of `.__call__()`.

-- 
The dead increasingly dominate and strangle both the living and the
not-yet born.  Vampiric capital and undead corporate persons abuse
the lives and control the thoughts of homo faber. Ideas, once born,
become abortifacients against new conceptions.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/DZLDC5ET5UUGFBOXJ534L4NWFHPQQDG6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP-0472 revisited - draft

2020-09-01 Thread Guido van Rossum
On Tue, Sep 1, 2020 at 8:20 AM Christopher Barker 
wrote:

> Thanks -- good to get this written down!
>
> Question: it strikes me that the use case of [] for type hints is
> logically quite different than for indexing. So do they need to use the
> same syntax / dunder?
>
> I think that type hints are used in specific places, and thus the
> interpreter could know if a given [] was a type hint or an indexing
> operation, and thus could dispatch it differently.
>
> Would that be desirable? I'm not sure -- but as type hints' use of [] is
> logically quite different, it might make sense to have it use different
> rules.
>
> There is precedent -- after all, () used to create a tuple follows
> different rules than () used to call a function.
>
> If it's not technically possible to make the distinction, then it's a
> non-issue, but if it is, it may be worth considering.
>

Type hints are indeed dispatched differently, but this is done based on
information that is only available at runtime. Since PEP 560, for `x[y]`,
if no `__getitem__` method is found, and `x` is a type (class) object, and
`x` has a class method `__class_getitem__`, that method is called.
Extending this with keyword args is straightforward. Modifying the compiler
to generate different bytecode for this case is essentially impossible.

See
https://github.com/python/cpython/blob/6844b56176c41f0a0e25fcd4fef5463bcdbc7d7c/Objects/abstract.c#L181-L198
for the code (it's part of PyObject_GetItem).

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/76QVVMKDCLEO5OUXKCHZV34YI4HZ7BKG/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread David Mertz
> On 30/08/20 3:06 pm, Steven D'Aprano wrote:

> (There are a few gray areas, such as array/matrix/vector addition, which
> sneak into the "acceptable" area by virtue of their long usage in
> mathematics.)
>

>>> a / b/ c
0.01
>>> home / 'git' / 'pip'
PosixPath('/home/dmertz/git/pip')

But yes, it's just another example. And when I teach it I always say "this
is a funny but intuitive overloading."

-- 
The dead increasingly dominate and strangle both the living and the
not-yet born.  Vampiric capital and undead corporate persons abuse
the lives and control the thoughts of homo faber. Ideas, once born,
become abortifacients against new conceptions.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/5Y6ST6HFIOYIAPMKXQ4VZT4AT2MZWX6Y/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread Guido van Rossum
On Tue, Sep 1, 2020 at 8:45 AM Steven D'Aprano  wrote:

> This is slightly revised version of something I sent to Stefano two
> weeks ago. I hope he is planning to use this, or something similar, in
> the PEP, but for what it's worth here it is for discussion.
>

Excellent. Could you add some cases that show how `d[1]` differs from
`d[1,]`? (And perhaps explain the reason why `d[1, k=2]` follows `d[1]`
instead of `d[1,]`. I know the answer, but it's worth being clear about
this particular edge case because it has tripped up various attempts.)

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/H4HUOASRBPUNWFZKU6QWFHVJVEM4YFGK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread Guido van Rossum
On Tue, Sep 1, 2020 at 9:34 AM Jonathan Fine  wrote:

> Hi Steven
>
> Thank you, for reviewing and combining your previous statements into a
> single message. This is a great help, for the creation and editing of the
> revised PEP.
>
> I intend to do something similar myself. Perhaps others might also want to
> do something similar.
>

A point of order here: I dislike PEPs that lay out multiple options for the
reader. (This was one of the flaws of PEP 472, and IMO it's held up PEP
505.) If you have a competing proposal, you should write it up in a
separate PEP and find a separate sponsor.

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/FPKIWENVFVYECKXLHC3NGTJJL6PG6357/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread Jonathan Fine
Hi Steven

Thank you, for reviewing and combining your previous statements into a
single message. This is a great help, for the creation and editing of the
revised PEP.

I intend to do something similar myself. Perhaps others might also want to
do something similar.

-- 
Jonathan
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/RVSVOXQINASUMOBA24UK43ZAN6JTKD2P/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP-0472 revisited - draft

2020-09-01 Thread Ricky Teachey
On Tue, Sep 1, 2020 at 11:21 AM Christopher Barker 
wrote:

> Thanks -- good to get this written down!
>
> Question: it strikes me that the use case of [] for type hints is
> logically quite different than for indexing. So do they need to use the
> same syntax / dunder?
>

How would we differentiate what the caller means by the subscript
invocation?

Put another way: would the distinction be:

A) between 1. objects of the type `type` (class objects), and 2. non-type
objects...?
B) between WHERE the innovation occurs in the code?

To explain further, A) looks like:

dict[ x, y ]

...calls:

dict.__type_subscript__( ( x, y ) )

...because dict is a class object, but:

d = dict(0
d[ x, y ]

...calls:

d.__getitem__( ( x, y ) )

...because d is not a class object?

Or B), so that for either of these:

d: dict[x, y]

...or this:

def f() -> dict[ x, y ]: ...

...the type checker calls (no effect at runtime):

dict.__type_subscript__( ( x, y ) )

...but this would still call __getitem__ at runtime:

class C: ...

>>> C[ x, y ]

...simply calls:

C.__getitem__(( x, y ))

...because the C[x,y] invocation occurs outside of a type hint location...?

B) at least seems like it isn't an option, since it's probably impossible
to determine what things are type hints and what things aren't simply based
on where they appear in code:

>>> MyType = C[x,y]  # this will be a type hint
>>> my_value = C[x,y]  # looking up a key on object C

---
Ricky.

"I've never met a Kentucky man who wasn't either thinking about going home
or actually going home." - Happy Chandler
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/QRY6VOQRQAGUHW7YCCROOIPFN36UX4XI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread Christopher Barker
Thanks Steve, it's good to see this so clearly laid out.

And indeed, v=fior backward compatibility, while also being as similar to
function call behavior as possible, this is pretty much the only option.

One request:

# Comma-separated indices with keywords:
>
> obj[foo, bar, spam=1, eggs=2]
> # calls type(obj).__getitem__((foo, bar), spam=1, eggs=2)
>
> and *mutatis mutandis* for the set and del cases.
>

The set case is non-trival (which you do discuss later), but could you
provide an example or two here as well?

I think:

obj[foo, bar, spam=1, eggs=2] = a_value
# calls type(obj).__getitem__((foo, bar), a_value, spam=1, eggs=2)

Is that right? good to lay it out.

The setitem case is particularly awkward, but fortunately, only for the
writers of classes that use these features, not the users of those classes.
So manageable complexity.

I like your gotchas section -- and we do want to have this well documented,
along with the "best practices" that you suggest. In fact, I've never been
able to find a good source of best practices for writing a class that takes
multiple positional indexes -- and it's pretty awkward.

-CHB

-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/AZ3WDDSLCKS4265U3LPEOTISULU4N7PJ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Proposed new syntax for subscripting (was PEP 472)

2020-09-01 Thread Steven D'Aprano
This is slightly revised version of something I sent to Stefano two 
weeks ago. I hope he is planning to use this, or something similar, in 
the PEP, but for what it's worth here it is for discussion.

This is, as far as I can tell, the minimum language change needed to 
support keywords in subscripts, and it will support all the desired 
use-cases.


* * * 


(1) An empty subscript is still illegal, regardless of context.

obj[]  # SyntaxError


(2) A single subscript remains a single argument:

obj[index]
# calls type(obj).__getitem__(index)

obj[index] = value
# calls type(obj).__setitem__(index, value)

del obj[index]
# calls type(obj).__delitem__(index)

(This remains the case even if the index is followed by keywords; see 
point 5 below.)


(3) Comma-seperated arguments are still parsed as a tuple and passed as 
a single positional argument:

obj[spam, eggs]
# calls type(obj).__getitem__((spam, eggs))

obj[spam, eggs] = value
# calls type(obj).__setitem__((spam, eggs), value)

del obj[spam, eggs]
# calls type(obj).__delitem__((spam, eggs))


Points (1) to (3) mean that classes which do not want to support keyword 
arguments in subscripts need do nothing at all. (Completely backwards 
compatible.)


(4) Keyword arguments, if any, must follow positional arguments.

obj[1, 2, spam=None, 3)  # SyntaxError

This is like function calls, where intermixing positional and keyword
arguments give a SyntaxError.


(5) Keyword subscripts, if any, will be handled like they are in 
function calls. Examples:

# Single index with keywords:

obj[index, spam=1, eggs=2]
# calls type(obj).__getitem__(index, spam=1, eggs=2)

obj[index, spam=1, eggs=2] = value
# calls type(obj).__setitem__(index, value, spam=1, eggs=2)

del obj[index, spam=1, eggs=2]
# calls type(obj).__delitem__(index, spam=1, eggs=2)


# Comma-separated indices with keywords:

obj[foo, bar, spam=1, eggs=2]
# calls type(obj).__getitem__((foo, bar), spam=1, eggs=2)

and *mutatis mutandis* for the set and del cases.


(6) The same rules apply with respect to keyword subscripts as for 
keywords in function calls:

- the interpeter matches up each keyword subscript to a named parameter 
  in the appropriate method;

- if a named parameter is used twice, that is an error;

- if there are any named parameters left over (without a value) when the 
  keywords are all used, they are assigned their default value (if any);

- if any such parameter doesn't have a default, that is an error;

- if there are any keyword subscripts remaining after all the named
  parameters are filled, and the method has a `**kwargs` parameter,
  they are bound to the `**kwargs` parameter as a dict;

- but if no `**kwargs` parameter is defined, it is an error.


(7) Sequence unpacking remains a syntax error inside subscripts:

obj[*items]

Reason: unpacking items would result it being immediately repacked into 
a tuple. Anyone using sequence unpacking in the subscript is probably 
confused as to what is happening, and it is best if they receive an 
immediate syntax error with an informative error message.


(8) Dict unpacking is permitted:

items = {'spam': 1, 'eggs': 2}
obj[index, **items]
# equivalent to obj[index, spam=1, eggs=2]


(9) Keyword-only subscripts are permitted:

obj[spam=1, eggs=2]
# calls type(obj).__getitem__(spam=1, eggs=2)

del obj[spam=1, eggs=2]
# calls type(obj).__delitem__(spam=1, eggs=2)

but note that the setter is awkward since the signature requires the 
first parameter:

obj[spam=1, eggs=2] = value
# wants to call type(obj).__setitem__(???, value, spam=1, eggs=2)

Proposed solution: this is a runtime error unless the setitem method 
gives the first parameter a default, e.g.:

def __setitem__(self, index=None, value=None, **kwargs)

Note that the second parameter will always be present, nevertheless, to 
satisfy the interpreter, it too will require a default value.

(Editorial comment: this is undoubtably an awkward and ugly corner case, 
but I am reluctant to prohibit keyword-only assignment.)


Comments


(a) Non-keyword subscripts are treated the same as the status quo, 
giving full backwards compatibility.


(b) Technically, if a class defines their getter like this:

def __getitem__(self, index):

then the caller could call that using keyword syntax:

obj[index=1]

but this should be harmless with no behavioural difference. But classes 
that wish to avoid this can define their parameters as positional-only:

def __getitem__(self, index, /):


(c) If the method is declared with no positional arguments (aside from 
self), only keyword subscripts can be given:

def __getitem__(self, *, index)
# requires obj[index=1] not obj[1]

Although this is unavoidably awkward for setters:

# Intent is for the object to only support keyword subscripts.
def __setitem__(self, i=None, value=None, 

[Python-ideas] Re: PEP-0472 revisited - draft

2020-09-01 Thread Christopher Barker
Thanks -- good to get this written down!

Question: it strikes me that the use case of [] for type hints is logically
quite different than for indexing. So do they need to use the same syntax /
dunder?

I think that type hints are used in specific places, and thus the
interpreter could know if a given [] was a type hint or an indexing
operation, and thus could dispatch it differently.

Would that be desirable? I'm not sure -- but as type hints' use of [] is
logically quite different, it might make sense to have it use different
rules.

There is precedent -- after all, () used to create a tuple follows
different rules than () used to call a function.

If it's not technically possible to make the distinction, then it's a
non-issue, but if it is, it may be worth considering.

-CHB




On Tue, Sep 1, 2020 at 12:40 AM Stefano Borini 
wrote:

> For those interested in the new draft of ex PEP-0472 (which has joined
> the choir invisible), I opened a draft PR
>
> https://github.com/python/peps/pull/1579
>
> This first draft contains only the revisited motivation and
> background. I'll add the technical decisions etc in the upcoming
> nights.
>
>
>
> --
> Kind regards,
>
> Stefano Borini
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/PMSOJNLNEHOPD3VPDDAN4NJTDK5FGKAB/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/AXPADOHTLDCTHEUUJ33XESG6XT5K32P2/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Steven D'Aprano
On Sun, Aug 30, 2020 at 05:49:50PM +1200, Greg Ewing wrote:
> On 30/08/20 3:06 pm, Steven D'Aprano wrote:
> >On Thu, Aug 27, 2020 at 11:13:38PM +1200, Greg Ewing wrote:
> >
> >>a[17, 42]
> >>a[time = 17, money = 42]
> >>a[money = 42, time = 17]
> >
> >I don't think that something like that is exactly the intended use-case
> >for the feature,
> 
> I don't see why we need to pick one use case to bless as the
> official "true" use case. 

We do that for every other operator and operator-like function.

Operator overloading is a thing, so if you want `a + b` to mean looking 
up a database for `a` and writing it to file `b`, you can. But the 
blessed use-cases for the `+` operator are numeric addition and sequence 
concatenation.

Anything else is an abuse of the operator: permitted, possibly a *mild* 
abuse, but at best it's a bit wiffy.

(There are a few gray areas, such as array/matrix/vector addition, which 
sneak into the "acceptable" area by virtue of their long usage in 
mathematics.)

If you don't like the term "abuse", I should say I am heavily influenced 
by its use in mathematics where "abuse of notation" is not considered a 
bad thing:

https://en.wikipedia.org/wiki/Abuse_of_notation

In any case, as you say (and agreeing with me) people will want to do 
something like this, and it is not my intent to stop them.


> Plus we have at least one real-world use case, i.e. xarray,
> where it would be a very obvious thing to do.

Indeed, and I can think of at least two use-cases where I would 
immediately use it myself, if I could.


> >But I'm sure people will want to do it, so
> >we should allow it even if it is an (ever-so-slight) abuse of
> >subscript notation.
> 
> How is it an abuse? To me it seems less of an abuse than other
> uses where the keyword args *don't* represent index values.

Compares to the majority of realistic examples given in this discussion 
and the PEP, your example doesn't look to me like an item or key lookup.
It looks more like a function call of some sort.

I know that, in a sense, subscript lookups are like function calls, and 
I also acknowledge that I don't know your intended semantics of that 
example. It might even be that you intended it as a lookup of some kind 
of record with time=17 and money=42. But let's not get too bogged down 
into not-picking. We agree that people should be allowed to do this.


[...]
> >"Starting in version 3.10 subscript parsing changes and item dunders
> >should change their signature ..."
> >
> > class X:
> > if sys.version_info >= (3, 10):
> > # New signatures
> > def __getitem__(self, ...):
> > else:
> > # Old signatures
> 
> Are you volunteering to rewrite all existing Python code that
> defines item dunders? :-)

Of course not. This is why we ought to be cautious about introducing 
backwards-incompatible changes.

I don't think that we should care about this "problem" that subscripting 
only takes a single subscript. But if we do "fix" it, I'd rather the 
straight-forward future directive (and a long, long deprecation period 
for the old behaviour) than two sets of confusingly similar getters and 
setters.

> >Having to remember which name goes with which version is going to be
> >annoying and tricky,
> 
> I'm not wedded to the name __getindex__. It can be called
> __newgetitem__ or __getitemwithfancyparemeterpassing__ if
> people thought that would be less confusing.

The trouble with naming anything "new" is that in ten years time it's 
not new any more, and you could end up needing a "new new" method too.



-- 
Steve
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/MOAITAIZDIXRIJUAV6EODU25ZCUKWJMA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Changing item dunder method signatures to utilize positional arguments (open thread)

2020-09-01 Thread Ricky Teachey
On Sun, Aug 30, 2020 at 6:19 PM Stefano Borini 
wrote:

> 2. pandas has this exact problem with column names, and while they
> have a workaround, in my opinion it is suboptimal
>

What is the workaround? 

---
Ricky.

"I've never met a Kentucky man who wasn't either thinking about going home
or actually going home." - Happy Chandler
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/V3WGLXIXL6HRTI5HVWLDUNJZ74JKJVPH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Access (ordered) dict by index; insert slice

2020-09-01 Thread Inada Naoki
On Mon, Aug 31, 2020 at 9:30 PM  wrote:
> I have a use case which relates to this request: iterating over a dict 
> starting from a given key. I would like to achieve this without having to pay 
> the full O(n) cost if I'm going to be iterating over only a few items. My 
> understanding is that this should be achievable without needing to iterate 
> through the entire dict, since the dict's internal key lookup points to a 
> particular index of dk_entries anyway.
>
[snip]
> Doing this efficiently would require either the addition of indexing to dicts 
> as well as some sort of get_key_index operation, or else could be done 
> without knowing indices if an iter_from_key operation were introduced (which 
> used the internal dk_indices to know where to start iterating over 
> dk_entries). I think this thread touches on the same sorts of debates however 
> so I'm mentioning this here.
>

Note that proposed index access is O(n), not O(1). So `get_key_index`
doesn't match your use case.

On the other hand, iter_from_key is possible idea.

Another API idea is `d.next_item(key)` and `d.prev_item(key)`. They
return None if the key is left/right end. They raise KeyError if key
not found. Other wise, they return (key, item) pair.


> I also think that even if adding new features to the built-in dict is 
> undesirable, adding a collections.IndexableDict would be very useful 
> (sortedcollections.IndexableDict exists but sorting is not acceptable for 
> many use cases).

Maybe, OrderedDict can have od.next_item(key) and od.prev_item(key).

Regards,

-- 
Inada Naoki  
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/2BIYAHUZTPRR5P6Y3MDVFBVY7PEECEDE/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Access (ordered) dict by index; insert slice

2020-09-01 Thread Dominik Vilsmeier

On 01.09.20 11:22, Zig Zigson wrote:


I believe I described my case poorly, the process to get from one state (key) 
to the next is an external (slow) process; the value stored is not the next 
state but a value calculated while advancing the state. This dict serves as a 
way to quickly skip steps of the external process when it has repeated itself, 
and thus calculating the next key would be exorbitantly slower than iterating 
through the whole dict.
In any case as a poster pointed out above, my example is not as compelling in 
terms of a speedup as I thought, the dict key iteration is not very long in 
practice compared to other operations I need to do.


What I meant is that you *could* store the next state, e.g. alongside
that computed value, as a tuple. So you would have `state, value =
states[state]`. This increases the memory usage but it saves you from
iterating the whole dict, if that is what you want.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/TUOTSOMBHESPGZKCAMLOKA5TUAOQVXT3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Access (ordered) dict by index; insert slice

2020-09-01 Thread Zig Zigson
I believe I described my case poorly, the process to get from one state (key) 
to the next is an external (slow) process; the value stored is not the next 
state but a value calculated while advancing the state. This dict serves as a 
way to quickly skip steps of the external process when it has repeated itself, 
and thus calculating the next key would be exorbitantly slower than iterating 
through the whole dict.
In any case as a poster pointed out above, my example is not as compelling in 
terms of a speedup as I thought, the dict key iteration is not very long in 
practice compared to other operations I need to do.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/GZIIFVMRQDQLPNCZAYM4HHZ3HAHGXD2H/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Access (ordered) dict by index; insert slice

2020-09-01 Thread Zig Zigson
Having gotten to an implementation, you are correct, the dict iteration does 
not take the lion's share, or at least there are several other steps in my 
application which dwarf the dict traversal operations in any case.
I don't think I in practice have a compelling case here, so all I'm left with 
is the vagueism that there must exist use cases where this would be the 
bottleneck, which is admittedly a cop-out.
I mostly feel that the new dict internals are so convenient in enabling this 
that it would be a shame not to be able to have this performance improvement 
for the obscure case (which I can't think of) where creating a list copy would 
be undesirable for some reason other than the (as you point out) small memory 
increase.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/PRC2EGRSN6JJME4WBNA4PLB2YFXKNO7K/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Access (ordered) dict by index; insert slice

2020-09-01 Thread Dominik Vilsmeier

On 31.08.20 06:01, junkneno...@gmail.com wrote:


I have a use case which relates to this request: iterating over a dict starting 
from a given key. I would like to achieve this without having to pay the full 
O(n) cost if I'm going to be iterating over only a few items. My understanding 
is that this should be achievable without needing to iterate through the entire 
dict, since the dict's internal key lookup points to a particular index of 
dk_entries anyway.

My sample use case at a high level is when the dict stores values uniquely 
representing the state of a process (say, the hash of a changing object), and 
the values represent some outcome of a step in that process. The process can 
contain loops, so at each step we check if the current state's outcome is 
already stored (thus we want a dict for O(1) lookup), and when a matching state 
is found we'd like to stop and loop over the in-between states performing some 
operation on their values (say, summing their outcome values).
We may continue the process and find state-loops many times (the actual use 
case involves non-deterministic branches and thus possibly many loops), and the 
state-dict might reach a very large size, so iterating over the entire dict 
every time we find a matching key is undesirable, as is storing keys in an 
associated list as this would ~double the memory used.


Unless I'm misunderstanding the task, it sounds like this could be
solved by repeated lookups of cycle elements. It seems to be a special
case anyway that all cycles are inserted in order into the dict. I.e.
instead of iterating from one key to another you would just iterate the
cycle:

    if outcome in states:
    cycle = [outcome]
    while (state := states[cycle[-1]]) != outcome:
        cycle.append(state)
    result = sum(cycle)

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/R2MIVDA3Y5QYYO25HTGKUTZ74MAUNCRL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] PEP-0472 revisited - draft

2020-09-01 Thread Stefano Borini
For those interested in the new draft of ex PEP-0472 (which has joined
the choir invisible), I opened a draft PR

https://github.com/python/peps/pull/1579

This first draft contains only the revisited motivation and
background. I'll add the technical decisions etc in the upcoming
nights.



-- 
Kind regards,

Stefano Borini
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/PMSOJNLNEHOPD3VPDDAN4NJTDK5FGKAB/
Code of Conduct: http://python.org/psf/codeofconduct/