[Python-ideas] Re: Type checking for **kwargs based on its use

2022-06-17 Thread Alex Waygood
Hi Mauricio,

I'd advise starting a discussion on typing-sig (
https://mail.python.org/archives/list/typing-...@python.org/) or creating
an issue on the python/typing repo (https://github.com/python/typing). The
folks interested in typing generally hang out in those places, so those are
usually the best places to discuss new typing features.

Best wishes,
Alex

On Fri, Jun 17, 2022 at 2:18 PM Mauricio Villegas via Python-ideas <
python-ideas@python.org> wrote:

> Look at the following example:
>
> ```
> def some_function(f1: int):
> assert isinstance(f1, int)
>
> def other_function(f0: str, **kwargs):
> assert isinstance(f0, str)
> some_function(**kwargs)
>
> other_function(f0='a', f1='b')
> ```
>
> I would expect a static type checker to warn that f1='b' is wrong because
> the type should be int. There shouldn't be a need to add a type to **kwargs
> since what is accepted can be deduced from how it is used. Note that
> some_function could be defined in another module and be used in multiple
> places, thus the "don't repeat yourself" and "separation of concerns"
> principles apply. Better to have the type for f1 be only in the definition
> of some_function and not in the **kwargs.
>
> I created a github issue in pyright (
> https://github.com/microsoft/pyright/issues/3583) and the response was
> that PEP 484 forbids this. I have seen that there are discussions about
> TypedDict for more precise typing of **kwargs. However, requiring to use
> TypedDict for the cases in which it is possible to derive what **kwargs
> accepts based on its use, seems over-complicating things, which is yet
> another principle "keep it simple, stupid".
>
> I would think that it wouldn't be too problematic to have a PEP stating
> that static type checkers when **kwargs has not type annotation are allowed
> to analyze the source code to identify what **kwargs accepts. I would even
> say that when **kwargs has a type, checkers are allowed to analyze how it
> is used. Also that the type annotation for **kwargs be not necessary if it
> is possible to deduce what it accepts. Anyway, I am just giving out this
> idea to see what happens.
>
> As a side note, I have been developing jsonargparse which can be used for
> automatically creating complex parsers based on signatures (
> https://jsonargparse.readthedocs.io/en/stable/#classes-methods-and-functions).
> I do plan to support identifying what **kwargs accepts based on its use.
> See all the cases currently supported
> https://jsonargparse.readthedocs.io/en/latest/#ast-resolver.
> ___
> 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/TEDDC7FU7TR6AESZT2NLHUYCKIJYFZTD/
> 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/NI4DXOYCTA3TICFUT2MI4R7Y7MBDWV3E/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Adding pep8-casing-compliant aliases for the entire stdlib

2021-11-11 Thread Alex Waygood
I'm a -1 on this proposal, as I don't see any way of doing it that wouldn't 
cause a huge amount of disruption. Yes, the situation — especially with regard 
to unittest and logging — is far from ideal. But, it's what we've got.However 
I'm -100 on doing something like this while there already exist a large number 
of camelcase typing-module aliases for classes found elsewhere in the stdlib. 
It's already confusing enough to have `builtins.list` and `typing.List` be 
different objects. Under this proposal, we'd have `builtins.list`, 
`builtins.List`, and `typing.List`. Two of these objects would have the same 
identity, but it wouldn't be the two that are spelt the same. To my mind, this 
would be appalling.Yes, the aliases in the typing module are all deprecated, 
but they're still very widely used.Best, Alex
 Original message From: Matt del Valle  
Date: 11/11/2021  13:44  (GMT+00:00) To: Python-Ideas  
Subject: [Python-ideas] Adding pep8-casing-compliant aliases for the entire 
stdlib So I was reading the docs for the `threading` module and I stumbled upon 
this little note:

Note:
In the Python 2.x series, this module contained camelCase names
for some methods and functions. These are deprecated as of Python 3.10,
but they are still supported for compatibility with Python 2.5 and lower.And it 
got me thinking.Given that there is some precedent, would it be feasible to 
make a concerted effort to add aliases across the board for all public-facing 
stdlib types and functions that don't follow pep8-recommended casing?I realize 
that large chunks of the stdlib predates pep8 and therefore use various 
non-uniform conventions. For example, the logging module is fully camelCased, 
and many core types like `str` and `list` don't use PascalCase as pep8 
recommends. The `collections` module is a veritable mosaic of casing 
conventions, with some types like `deque` and `namedtuple` being fully 
lowercased while others like `Counter` and `ChainMap` are PascalCased.My 
motivation for this twofold:1) I'll confess that this has just always been a 
wart that has bothered me way more than it has any right to. I just hate it. 
Somewhere deep inside my lizard-brain it makes me unhappy to have disparate 
naming conventions in my code. I realize this isn't a good reason in and of 
itself but I wonder if this might not be the case for others as well. While 
I've come to accept it because that's just how it is, maybe it doesn't have to 
be this way?2) It's always been an extra thing to explain when teaching python 
to someone. I always try to cover pep8 very early to discourage people I'm 
training from internalizing bad habits, and it means you have to explain that 
the very standard library itself contains style violations that would get 
flagged in most modern code reviews, and that they just have to keep in mind 
that despite the fact that the core language does it, they should not.So the 
scope of my suggestion is as follows:- lowercase types become PascalCase (e.g., 
`str` -> `Str`, `collections.defaultdict` -> `collections.DefaultDict`)- 
lowercase attributes/functions/methods become snake_case (no changes for names 
that only contain a single word, so `str.lower()` would be unaffected, but 
`str.removeprefix()` would get the alias `str.remove_prefix()`)- pep8 and the 
python docs are updated to state that the pep8-compliant forms of stdlib names 
should be strongly preferred over the legacy names, and that IDEs and linters 
should include (configurable?) weak warnings to discourage the use of 
legacy-cased stdlib names- `help()` would be special-cased for builtin types to 
no longer display any current non-pep8-compliant names, and the python docs 
would also no longer show them, instead only making a note at the top of the 
page as with the `threading` module.Given the horrors of the python 2.7 schism 
I don't think there's any rush to officially deprecate or remove the current 
non-pep8 names at all. I think that's the sort of thing that can happily and 
fully be kicked down the road. If we add aliases and they see widespread 
adoption to the point where the non-pep8 forms are barely ever even seen out in 
the wild then maybe in 10 or 20 years time when the steering council is 
deliberating on a new major python version they can consider rolling the 
removal of legacy badly-cased names into it. And if not then no big deal.So 
yeah, thoughts?



___
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/6667GUFX36JTGD433KPPOPWVQV444GNW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Type-hinting dictionaries for an arbitrary number of arbitrary key/value pairs? Counterpart to PEP 589?

2021-10-16 Thread Alex Waygood
Indeed — we essentially lie to mypy about the method resolution order for 
list, dict, etc (mypy thinks that list directly inherits from 
collections.abc.MutableSequence — see the typeshed stub here: 
https://github.com/python/typeshed/blob/32bc2161a107db20c2ebc85aad31c29730db3e38/stdlib/builtins.pyi#L746),
 but numeric ABCs are not special-cased by typeshed in the same way as 
collections ABCs. Fundamentally, mypy has no knowledge about virtual 
subclassing.

Again, I covered this very comprehensively on StackOverflow ;) 
https://stackoverflow.com/questions/69334475/how-to-hint-at-number-types-i-e-subclasses-of-number-not-numbers-themselv/69383462#69383462

Best,
Alex 

> On 16 Oct 2021, at 13:54, Steven D'Aprano  wrote:
> 
> On Sat, Oct 16, 2021 at 09:54:13AM +0100, Alex Waygood wrote:
>>>> On 16 Oct 2021, at 06:13, Steven D'Aprano  wrote:
>>> Be careful about believing what you are told.
>> Indeed, MyPy will correctly raise errors if you assign {None: []} to a
>> variable annotated with dict[str, Number]. However, you'll find that
>> MyPy also raises an error if you assign {'foo': 4} to a variable
>> annotated with dict[str, Number]:
> 
> Hah, serves me right for not testing it for both positive and negative 
> cases.
> 
> In my very limited testing now, I see that the problem appears to be 
> with the Number type. mypy correctly accepts this:
> 
>   Data = Dict[str, int]
>   a: Data = {'spam': 42}
> 
> (no errors), but if you change the annotation to use Number instead of 
> int, it wrongly flags that as a type error.
> 
> Possibly mypy doesn't know that ints and floats are instances of Number?
> 
> ___
> 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/FJY3QKAUJOJYTODMZH72X2ZS63GKT6AN/
> 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/JFS65SMVETZ7W4KARJYJUNP6KA5XOFPL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Type-hinting dictionaries for an arbitrary number of arbitrary key/value pairs? Counterpart to PEP 589?

2021-10-16 Thread Alex Waygood
> On 16 Oct 2021, at 06:13, Steven D'Aprano  wrote:
> Be careful about believing what you are told.

Indeed, MyPy will correctly raise errors if you assign {None: []} to a variable 
annotated with dict[str, Number]. However, you'll find that MyPy also raises an 
error if you assign {'foo': 4} to a variable annotated with dict[str, Number]:

https://mypy-play.net/?mypy=latest=3.10=de7faea3b4d6a0ffefc64acf3bfa7b77

The issue isn't a matter of false negatives from Mypy; it's a matter of false 
positives. For more, see the (rather long — sorry!) answer I gave Sebastian to 
a previous question of his on Stack Overflow:

https://stackoverflow.com/questions/69334475/how-to-hint-at-number-types-i-e-subclasses-of-number-not-numbers-themselv/69383462#69383462

Having said that, I absolutely agree that type-hinting doesn't seem to have 
much to do with this specific problem, and that a UserDict subclass is probably 
the way to go here.

Best,
Alex 

> On 16 Oct 2021, at 06:13, Steven D'Aprano  wrote:
> 
> On Fri, Oct 15, 2021 at 06:17:12PM +0200, Sebastian M. Ernst wrote:
> 
>> Data = Dict[str, Number]
>> 
>> @typechecked
>> def foo(bar: Data):
>>print(bar)
>> ```
>> 
>> Yes, this is using run-time checks (typeguard), which works just fine.
>> Only strings as keys and Number objects as values are going through. (I
>> was told that MyPy does not get this at the moment.)
> 
> Be careful about believing what you are told.
> 
> 
>[steve ~]$ cat test.py 
>from numbers import Number
>from typing import Dict
>Data = Dict[str, Number]
>a: Data = {None: []}
> 
>[steve ~]$ mypy test.py 
>test.py:4: error: Dict entry 0 has incompatible type "None": 
>"List[]"; expected "str": "Number"
>Found 1 error in 1 file (checked 1 source file)
> 
> 
>> The issue is that `bar` itself still allows "everything" to go in (and out):
>> 
>> ```python
>> @typechecked
>> def foo2(bar: Data):
>>bar[1.0] = b'should not be allowed'
>> ```
> 
> The Python interpreter intentionally doesn't know or care about 
> typing annotations. The interpreter should absolutely allow that.
> 
> However mypy correctly flags that assignment as a type error.
> 
> How about typeguard? That's for the typeguard developers to answer, but 
> my guess is that they will say that the typechecked decorator can 
> enforce type checking of the input parameters and perhaps even the 
> return result, but there is nothing they can do about what happens 
> inside the body of the function.
> 
> 
>> PEP 589 introduces typed dictionaries, but for a fixed set of predefined
>> keys (similar to struct-like constructs in other languages). In
>> contrast, I am looking for an arbitrary number of typed keys/value pairs.
> 
> Something like this?
> 
>from numbers import Number
>from collections import UserDict
> 
>class RestrictedDict(UserDict):
>def __setitem__(self, key, value):
>if not isinstance(key, str):
>raise TypeError('key must be a string')
>if not isinstance(value, Number):
>raise TypeError('value must be a number')
>super().__setitem__(key, value)
> 
> 
> (I think that is the only method that needs to be overloaded.)
> 
> 
> -- 
> 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/HLGDIWGHSIG3LDSBN7RDARK6E7VYTXQT/
> 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/NJQD6TKI5EIWBIAFKOL5L7SNHJX2KK7A/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Structure Pattern for annotation

2021-10-14 Thread Alex Waygood
I agree with Steven. I very much like Abdulla's proposed syntax for dicts, 
TypedDicts and sets. But I'm not sure that the idea for `Annotated` is 
workable, and the proposal for lists seems too prone to ambiguity, given how 
extensively square brackets are already used in typing syntax.

One question about the proposals, however: how would we represent other 
mappings apart from dicts? Would `collections.abc.Mapping` and 
`types.MappingProxyType` still be spelled as `Mapping[str, int]` and 
`MappingProxyType[str, int]`? If so, that would be a slightly annoying 
inconsistency.

I do also quite like the idea of an improved syntax for tuples specifically. 
Tuples are already very different types to lists/strings/etc in the context of 
typing, essentially representing heterogeneous structs of fixed length rather 
than homogenous sequences of unspecified length. As such, I think it "makes 
sense" to special-case tuples without special-casing other sequences such as 
list, `collections.abc.Sequence` or `collections.deque`.

def foo() -> tuple[list[list[str]], list[list[str]]]

would become

def foo() -> (list[list[str]], list[list[str]])

That feels quite readable and natural, to me.

Best,
Alex 

> On 14 Oct 2021, at 09:25, Steven D'Aprano  wrote:
> On Thu, Oct 14, 2021 at 12:32:57AM +0400, Abdulla Al Kathiri wrote:
> 
>> Today I found myself write a function that returns a tuple of list of 
>> list of strings (tuple[list[list[str]], list[list[str]]]). Wouldn’t it 
>> easier to read to write it like the following:
>> ([[str]], [[str]])?
> 
> Not really. Your first example is explicit and I can get the meaning by 
> just reading it out loud:
> 
>tuple[list[list[str]], list[list[str]]]
> 
>"tuple (of) list (of) list (of) str, list (of) list (of) str
> 
> Your abbreviated version:
> 
>([[str]], [[str]])
> 
> is too terse. I have to stop and think about what it means, not just 
> read it out loud. Without the hint of named types (tuple and list), my 
> first reaction to seeing [str] is "is this an optional string?".
> 
> And then I wonder why it's not written:
> 
>([[""]], [[""]])
> 
> Why abbreviate list and tuple but not string?
> 
> Code is read more than it is written, and can be too terse as well as 
> too verbose.
> 
> On the other hand:
> 
>> Similarly for TypedDict, replace the following..
>> class Movie(TypedDict):
>>name: str
>>year: int
>> with 
>> {‘name’: str, ‘year’: int}
> 
> To my eye, that one does work. As far as I know, curly brackets {} 
> aren't otherwise used in annotations (unlike square brackets), and they 
> don't look like "optional" to me. They look like a dict.
> 
> So on first glance at least, I think that:
> 
>{'name': str, 'year': int}
> 
> is better than the class syntax we already have.
> 
> 
> Likewise:
> 
>> dict[str, int] will be {str: int} 
>> set[int] will be {int}.
> 
> work for me too.
> 
> 
>> Also, Annotated[float, “seconds”] can be replaced with something like 
>> float #seconds indicating whatever comes after the hashtag is just 
>> extra information similar to a normal comment in the code.
> 
> No, because the # indicates that the rest of the line is a comment. This 
> is already legal:
> 
>def func(d: {str  # this is an actual comment
> : int}) -> Any: ...
> 
> so this would be ambiguous between a real comment and an annotation.
> 
> Even if we agreed to change the behaviour of comments, you suggested:
> 
>func(d: {str # product label: [float] # prices from 2000 to 2015})
> 
> How is the interpreter to know that the first annotation is just
> 
>"product label"
> 
> rather than this?
> 
>"product label: [float] # prices from 2000 to 2015"
> 
> So I don't think this works.
> 
> 
> -- 
> 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/T7E54DZW6EENRT373ZMCTU5WWRQ5M2TN/
> 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/YUPJNZVGYDANDHFD5VI54GRRNLGUAFBP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: dict_items.__getitem__?

2021-10-12 Thread Alex Waygood
>
> If one DID write a first() function, it maybe or maybe not should raise a
> different exception, but it should certainly provide a better error message


For reference, the more-itertools package on PyPI has `first()` and
`last()` functions:
https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/more.html#first.
(Not endorsing details of their implementations -- just providing a
reference to a piece of prior art.)

On Tue, Oct 12, 2021 at 4:41 PM Christopher Barker 
wrote:

> On Tue, Oct 12, 2021 at 4:51 AM Chris Angelico  wrote:
>
>> > Exactly: simple usage of next is often a bug. We need to be careful
>> about this every time someone suggests that it's straight-forward to do
>> next(iter(obj)).
>>
> 
>
>> Please give a real example of where calling first() and getting
>> ValueError is safer than calling next(iter(x)) and getting
>> StopIteration. So far, I am undeterred in believing that the two
>> exceptions have equivalent effect if the caller isn't expecting them.
>>
>
> I don't know about safer, but it is a clear example of why using
> next(iter(obj)) requires a pretty complete knowledge of the iteration
> protocol.
>
> I can guarantee you I'd get some questions from my students when they got
> a StopIterationError!
>
> If one DID write a first() function, it maybe or maybe not should raise a
> different exception, but it should certainly provide a better error message:
>
> >>> next(iter([]))
> Traceback (most recent call last):
>   File "", line 1, in 
> StopIteration
>
> Is not very helpful.
>
> -CHB
>
>
>
>
>
>> 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/2AL5FE3KZI4EBTRMJ7O5EL6MBVN7RUYF/
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>
>
> --
> Christopher Barker, PhD (Chris)
>
> 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/VQFAQMAKKQ6BG3VIP6BLZ6Q6RBB4V4CR/
> 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/ODGZXXYBBXJOJRQIP6TRIFXY6A7VRSMO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: dict_items.__getitem__?

2021-10-10 Thread Alex Waygood
>
> here is the thread from the last time that this was brought up:
>
> https://mail.python.org/archives/list/python-ideas@python.org/thread/S7UMTWK65X6BJDYZ3SSU7I7HOIASDMMJ/#S7UMTWK65X6BJDYZ3SSU7I7HOIASDMMJ


Thanks, that's very helpful. Sounds like Guido is right, and the short
answer is "while there would be ways of making it fast (and faster than the
status quo) for small dicts, there is probably no way of making it O(1), as
indexing is for lists and tuples".

For me, that's a deal-breaker. I think if you're adding in a way to get the
*n*th key of a dict by sequence-style indexing, it's going to be very
surprising for newbies if they find out that getting the 8743rd key of the
dict takes a lot longer than getting the 1st key of the dict, given that
that's not at all the behaviour of lists and tuples.

Best,
Alex

On Sun, Oct 10, 2021 at 7:26 PM Christopher Barker 
wrote:

> here is the thread from the last time that this was brought up:
>
>
> https://mail.python.org/archives/list/python-ideas@python.org/thread/S7UMTWK65X6BJDYZ3SSU7I7HOIASDMMJ/#S7UMTWK65X6BJDYZ3SSU7I7HOIASDMMJ
>
> It was very thoroughly discussed then.
>
> -CHB
>
>
> On Sun, Oct 10, 2021 at 8:33 AM Guido van Rossum  wrote:
>
>> You have to check the C code to be sure, but IIRC the latest dict
>> implementation has a dense array of the values in insert order, and the
>> hash table (which has gaps) contains indexes into the values array. So you
>> could easily index into the values array (which I believe also has the
>> keys) in O(1) time.
>>
>> Though what happens to the dense array when a key is deleted? It must
>> leave a gap there too. So, never mind, you’d have to walk through the array
>> counting items but not gaps, and that’s O(n). Which explains why we don’t
>> have such an API. But please check the C code!
>>
>> —Guido
>>
>> On Sun, Oct 10, 2021 at 07:18 Alex Waygood 
>> wrote:
>>
>>> Should `dict.items()` be indexable now that dicts are ordered? I say
>>> yes. Why shouldn't it?
>>>
>>>
>>> Would there be a way to ensure that this had the same time complexity as
>>> indexing of sequences? If "yes", I would support this — I think it would be
>>> useful in some situations, and it would be more efficient than existing
>>> mechanisms to obtain the *n*th key from a dictionary. If (as I
>>> presume), the answer is "no", then I would not support this — I think it
>>> would give the misleading impression that obtaining the  *n*th
>>> key/value from a dictionary is just as efficient as obtaining the *n*th
>>> item from a list or tuple.
>>>
>>> Best,
>>> Alex
>>>
>>> On 10 Oct 2021, at 05:05, Finn Mason  wrote:
>>>
>>> 
>>>
>>> On Sat, Oct 9, 2021, 9:56 PM Steven D'Aprano 
>>> wrote:
>>>
>>>> [Snip...]
>>>
>>>
>>> Newbies won't know first() lives in itertools, and those experienced
>>>> enough to know it is there probably won't bother to use it.
>>>>
>>>
>>> A very good point.
>>>
>>> Let's get back to the original topic. Should `dict.items()` be indexable
>>> now that dicts are ordered? I say yes. Why shouldn't it?
>>>
>>>
>>> --
>>> Finn Mason
>>>
>>>> ___
>>> 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/OOR2AUMA7UMHHVW7XLLUXHTNKGRXTPU4/
>>> 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/RHNNAZR2ZBYZFQ75VHR3FUMVY6GWDDB6/
>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>
>> --
>> --Guido (mobile)
>> ___
>> 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/archi

[Python-ideas] Re: dict_items.__getitem__?

2021-10-10 Thread Alex Waygood
> Should `dict.items()` be indexable now that dicts are ordered? I say yes. Why 
> shouldn't it?


Would there be a way to ensure that this had the same time complexity as 
indexing of sequences? If "yes", I would support this — I think it would be 
useful in some situations, and it would be more efficient than existing 
mechanisms to obtain the nth key from a dictionary. If (as I presume), the 
answer is "no", then I would not support this — I think it would give the 
misleading impression that obtaining the  nth key/value from a dictionary is 
just as efficient as obtaining the nth item from a list or tuple.

Best,
Alex

> On 10 Oct 2021, at 05:05, Finn Mason  wrote:
> 
> 
>> On Sat, Oct 9, 2021, 9:56 PM Steven D'Aprano  wrote:
> 
>> [Snip...]
> 
> 
> 
>> Newbies won't know first() lives in itertools, and those experienced 
>> enough to know it is there probably won't bother to use it.
> 
> 
> A very good point.
> 
> Let's get back to the original topic. Should `dict.items()` be indexable now 
> that dicts are ordered? I say yes. Why shouldn't it?
> 
> 
> --
> Finn Mason
> ___
> 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/OOR2AUMA7UMHHVW7XLLUXHTNKGRXTPU4/
> 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/RHNNAZR2ZBYZFQ75VHR3FUMVY6GWDDB6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: dict_items.__getitem__?

2021-10-10 Thread Alex Waygood
> The problem is that first() does not return the first item of the
> iterator, but the *next item still available*.
> 
>a = list('12345')
>b = iter('12345')
> 
>first(a) == first(a)  # True
>first(b) == first(b)  # False

This is an excellent point, and something I hadn't considered. Unless someone 
can think of a good workaround that doesn't make the implementation hideously 
complex, I retract my support for adding `first()` and `last()` to itertools.

> On 10 Oct 2021, at 05:09, Steven D'Aprano  wrote:
> 
> On Wed, Oct 06, 2021 at 03:42:28PM +0100, Alex Waygood wrote:
> 
>>> Whether they are added to dict or itertools, there are still nine of 
>>> them
>> 
>> No, the suggestion was to add two functions to itertools (first() and 
>> last(), which would work with any iterable, not just dicts), rather 
>> than adding nine methods to the dict interface. This was precisely why 
>> I was saying that I liked the itertools solution more.
> 
> Okay.
> 
> In another post, I've explained why I don't think that putting first() 
> in itertools would actually be useful (TL;DR: newbies wouldn't know it 
> was there, and to people experienced enough to know it was there, it's 
> likely easier to just use next() directly).
> 
> When I started writing this post, I was going to argue that we should 
> put first() and last() in itertools as recipes, for their pedagogical 
> value:
> 
>def first(iterable):
>return next(iter(iterable))
> 
>def last(iterable):
>return next(reversed(iterable))
> 
> I had got so far as to open bugs.python.org to create a ticket.
> 
> But I've convinced myself that they aren't even worthwhile as recipes. 
> The problem is that if we are being precise and accurate, and we should 
> be, the names are simply *wrong* and the behaviour will be confusing to 
> those we're supposedly trying to help.
> 
> The problem is that first() does not return the first item of the
> iterator, but the *next item still available*.
> 
>a = list('12345')
>b = iter('12345')
> 
>first(a) == first(a)  # True
>first(b) == first(b)  # False
> 
> If that behaviour makes sense to you, and is what you expected, then
> congratulations, you're probably a very sophisticated Pythonista who
> understands that iterators mutate after each item is retrieved, in
> which case you probably aren't going to get any benefit at all from a
> named first() function.
> 
> But if you are one of those newbies who (we're told) need a named 
> function, then you will probably be totally gobsmacked that sometimes 
> first() will return the first item, and always the first item, and 
> sometimes it will return the first, second, third... items in sequence.
> 
> If we are to be precise and accurate, *sequences* have a first item, but
> iterators only have a next item.
> 
> 
> 
> -- 
> 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/F6TG5EW3SKKMN6D6F7UBRRUNG2KYMMK5/
> 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/K3UUIZOW7NDSSR5ZJMHWTMQBDHKFWZX6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: dict_items.__getitem__?

2021-10-06 Thread Alex Waygood
> Whether they are added to dict or itertools, there are still nine of 
> them

No, the suggestion was to add two functions to itertools (first() and last(), 
which would work with any iterable, not just dicts), rather than adding nine 
methods to the dict interface. This was precisely why I was saying that I liked 
the itertools solution more.

> On 6 Oct 2021, at 15:01, Steven D'Aprano  wrote:
> 
> On Wed, Oct 06, 2021 at 11:11:09AM +0100, Alex Waygood wrote:
>>> The temptation to insist "see, YAGNI!" at this point I shall resist.
>> 
>> *You* might not need it, but I've seen it come up a lot on Stack 
>> Overflow, and all too often people end up going for the much less 
>> efficient solution. I personally have also written code with practical 
>> applications using `next(iter(mydict))`.
> 
> Under what circumstances do you care what the first key in a dict is, 
> without going on to care about the second, third, fourth etc?
> 
> They are surely extremely niche, or artificial, or both, e.g. the 
> Stackoverflow problem you link to: "find the first non-repeating 
> character in a string -- using only one loop". Why the *first* rather 
> than any, or all?
> 
> In any case, the presence of one or two uses for a piece of 
> functionality doesn't mandate that we make this a builtin. Your solution 
> with next() is perfectly adequate.
> 
> The other suggested methods are even more obscure. Why have a method 
> for returning the first value, without knowing the key?
> 
> "I don't know what the first key is, and I don't care, but I know that 
> whatever it is, it maps to the value 17."
> 
> Now what are you going to do with that knowledge? This seems like a 
> method in desperate need of a use-case.
> 
> 
> [...]
>> I agree that it's a lot of methods to add. That's precisely why I 
>> prefer Inada Naoki's suggestion of additions to itertools
> 
> Whether they are added to dict or itertools, there are still nine of 
> them, and they are pretty much near clones of each other:
> 
># first_ and last_ whatsits 
>next([iter|reversed](obj.[keys|values|items]()))
> 
> if you will excuse the misuse of hybrid Python/BNF syntax :-)
> 
> 
> 
> -- 
> 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/T3TOFAFBPGY44LOVKSMVZJGBNQ7MUNEL/
> 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/OCVRRJPZQCQ6UKVKR4GQRJFWAUJNDFK6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: dict_items.__getitem__?

2021-10-06 Thread Alex Waygood
> The temptation to insist "see, YAGNI!" at this point I shall resist.

*You* might not need it, but I've seen it come up a lot on Stack Overflow, and 
all too often people end up going for the much less efficient solution. I 
personally have also written code with practical applications using 
`next(iter(mydict))`.

> I was +0 sympathetic to that until you posted this obvious extension
> of the idea

I don't see these dict methods as an "obvious extension" of the idea; I see 
them as unneeded/irrelevant *if* a more general way of doing this is added to 
itertools.

> That's an awful lot of new methods to take advantage of what for many
> applications of dict (in fact, *all* of my applications ever[1]) is an
> irrelevant ordering.


I agree that it's a lot of methods to add. That's precisely why I prefer Inada 
Naoki's suggestion of additions to itertools, and why I've never bothered 
starting a thread on the subject myself. But since the topic was being 
discussed after Erik started this thread, I thought I might mention the 
alternative solution that's been in the back of my head for a while.

> [A]nyone who wants it can do it themselves:


As I said in my previous message, the existing idiom (`next(iter(mydict))`) 
appears to be extremely non-obvious for beginners in Python, causing them to 
often go for much more inefficient options. No one is claiming "there is no way 
to do this" at present; the argument is that the best way to do this is, at 
present, *not sufficiently obvious*.

> These defs do something undefined on unordered mappings (ie, not based
> on dict), and may be dangerous in that sense.

Excellent point (though note that my suggestion was to extend the dict 
interface, not the interface for all mappings).

> In the current implementation, positional indexing is time-expensive

Yes, that's exactly why I don't support Erik's original suggestion of 
positional indexing for dict.keys(), dict.values() and dict.items(), and why I 
*only* support easy ways of fetching the first/last object from the view.

> I wonder if any code is being written obscurely to ensure that
> keys get added to dicts in the "right" order

I personally have used dictionaries as ordered sets in the past (skip to the 
last code snippet in this answer: 
https://codereview.stackexchange.com/a/264437/24517), and would object to this 
being called an "obscure" use of the data structure. It is, by now, both 
well-known and well-advertised in the documentation that dictionaries are 
guaranteed to maintain insertion order. It's obviously not how the data 
structure has historically been used, but I don't see how that makes it an 
invalid use of the data structure *now*. Why shouldn't users be expected to 
exploit an advertised feature of the language?

> On 6 Oct 2021, at 10:29, Stephen J. Turnbull  
> wrote:
> 
> Alex Waygood writes:
> 
>> Whereas obviously,
> 
> The temptation to insist "see, YAGNI!" at this point I shall resist.
> 
>> a much better way (especially if it's a very large dictionary) is
>> to do:
>>   first_key = next(iter(mydict))
> 
>> [Inada Naoki]
>>> I think we can add `itertools.first()` for this idiom, and
>>> `itertools.last()` for `next(iter(reversed(x)))` idiom.
> 
> I was +0 sympathetic to that until you posted this obvious extension
> of the idea:
> 
>> I like this idea, a lot. Another possibility I've been wondering
>> about was whether several methods should be added to the dict
>> interface:
>> dict.first_key = lambda self: next(iter(self))
>> dict.first_val = lambda self: next(iter(self.values()))
>> dict.first_item = lambda self: next(iter(self.items()))
>> dict.last_key = lambda self: next(reversed(self))
>> dict.last_val = lambda self: next(reversed(self.values()))
>> dict.last_item = lambda self: next(reversed(self.items()))
> 
> That's an awful lot of new methods to take advantage of what for many
> applications of dict (in fact, *all* of my applications ever[1]) is an
> irrelevant ordering.
> 
> And anyone who wants it can do it themselves:
> 
> def first_key(dct): return next(iter(dct))
> def first_val(dct): return next(iter(dct.values()))
> def first_item(dct): return next(iter(dct.items()))
> def last_key(dct): return next(reversed(iter(dct)))
> def last_val(dct): return next(reversed(iter(dct.values(
> def last_item(dct): return next(reversed(iter(dct.items(
> 
> These defs do something undefined on unordered mappings (ie, not based
> on dict), and may be dangerous in that sense.  OTOH, I suspect the
> methods will do the wrong thing with many ordered mappings based on
> dict that support orders other than insertion order.
> 
>> But I think I like a lot more the idea of addi

[Python-ideas] Re: dict_items.__getitem__?

2021-10-05 Thread Alex Waygood
I think there definitely should be a more obvious way to do this 
(specifically the first and last keys/values/items of a dictionary — I'm 
ambivalent about the others, since they won't always be fast, as discussed). An 
anti-pattern you see quite often on Stack Overflow to get the first key of a 
dictionary is something like the following:

first_key = list(mydict.keys())[0]

Whereas obviously, a much better way (especially if it's a very large 
dictionary) is to do:

first_key = next(iter(mydict))

[Christopher Barker]
> I'll leave it exercise for the reader to find that thead

For reference, the (very long) previous thread is here: 
https://mail.python.org/archives/list/python-ideas@python.org/thread/S7UMTWK65X6BJDYZ3SSU7I7HOIASDMMJ/.

[Inada Naoki]
> I think we can add `itertools.first()` for this idiom, and
> `itertools.last()` for `next(iter(reversed(x)))` idiom.

I like this idea, a lot. Another possibility I've been wondering about was 
whether several methods should be added to the dict interface:
dict.first_key = lambda self: next(iter(self))
dict.first_val = lambda self: next(iter(self.values()))
dict.first_item = lambda self: next(iter(self.items()))
dict.last_key = lambda self: next(reversed(self))
dict.last_val = lambda self: next(reversed(self.values()))
dict.last_item = lambda self: next(reversed(self.items()))
But I think I like a lot more the idea of adding general ways of doing these 
things to itertools.

Best,
Alex

> On 5 Oct 2021, at 05:30, Christopher Barker  wrote:
> 
> On Mon, Oct 4, 2021 at 5:46 PM Erik Demaine  wrote:
>> Have folks thought about allowing indexing dictionary views as in the 
>> following code, where d is a dict object?
>> 
>> d.keys()[0]
>> d.keys()[-1]
>> d.values()[0]
>> d.values()[-1]
>> d.items()[0]
>> d.items()[-1]  # item that would be returned by d.popitem()
> 
> since dicts were made order-preserving, indexing the keys, items, etc does 
> make some sense.
> 
> 
> > I've also often wanted to get an arbitrary item/key from a dictionary, and 
> 
> This is indeed one of the use cases identified.
> 
>> I found some related discussion in 
>> https://mail.python.org/archives/list/python-ideas@python.org/thread/QVTGZD6USSC34D4IJG76UPKZRXBBB4MM/
>> but not this exact idea.
> 
> That's a pretty different idea but this exact idea has been discussed on this 
> list relatively recently. I still like it, but there wan't much general 
> support.
> 
> I'll leave it exercise for the read to find that thead, but it is there, and 
> I suggest you look for it if you want to further pursue this idea.
> 
> -CHB
> 
> 
> -- 
> Christopher Barker, PhD (Chris)
> 
> 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/RAEDZPUTNABJLX3ESU32PZQBJ25DDOPK/
> 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/DY6JFKMZESHOXEHNO5I6A5GMEKFBUUSN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax Sugar for __name__ == "__main__" boilerplate?

2021-10-02 Thread Alex Waygood
I disagree that "it teaches a lot about how Python works" is a good reason to 
keep things the way they are. If you applied this principle more broadly, it 
would seem to be an argument in favour of complexity in most situations, that 
would imply we should keep syntactic sugar to a bare minimum at all times.

Learning about how Python works under the hood is extremely valuable for 
becoming a more advanced programmer. However, not everybody needs to be a 
mechanic to drive a car. We should surely make it as easy as possible for 
beginners to write fully functional scripts that conform to best practices.

I love this proposal. "if__name__ == '__main__'" has always felt, to me, as 
though it flies in the face of the simplicity and elegance Python generally 
prizes in other parts of the language.

Best wishes,
Alex

> On 2 Oct 2021, at 11:00, Abdur-Rahmaan Janhangeer  
> wrote:
> 
> 
> Greetings list,
> 
> I am -1 on this proposition.
> 
> I can relate that if name == main is very confusing to teach.
> However, it teaches a lot about how Python works.
> If you know Python it is very clear. So if it's confusing, you
> wrongly taught Python (I myself was in this situation)
> 
> The simplification idea is to coerce Python to use patterns forged elsewhere. 
> The tools are here if you wish to use it.
> 
> But, specifically pointing a pattern for it and adding additional layers to 
> make it
> work is an enforcement of the main function. Something python is not bound to
> and does not need to run.
> 
> Kind Regards,
> 
> Abdur-Rahmaan Janhangeer
> about | blog 
> github
> Mauritius
> ___
> 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/VHZK76RSXE3WIL2ZJ75WHCZ5OWQPE2QL/
> 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/H52A65WBSOPGLJ4YAJBRLKFIFW5VED46/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: os.workdir() context manager

2021-09-15 Thread Alex Waygood
I also really like this idea. Though I wonder if it might be a better fit for 
`contextlib` rather than `os`? Can see arguments both ways (and it's a minor 
detail, anyway).

Alex

> On 14 Sep 2021, at 20:55, Paul Moore  wrote:
> 
> On Tue, 14 Sept 2021 at 20:44, Marc-Andre Lemburg  wrote:
>> 
>> I sometimes write Python scripts which need to work in specific
>> work directories.
>> 
>> When putting such code into functions, the outer function typically
>> does not expect the current work dir (CWD) to be changed, so wrap the
>> code which need the (possibly) modified CWD using a simply context
>> manager along the lines of:
>> 
>> class workdir:
>>def __init__(self, dir):
>>self.dir = dir
>>def __enter__(self):
>>self.curdir = os.getcwd()
>>os.chdir(self.dir)
>>def __exit__(self, *exc):
>>os.chdir(self.curdir)
>>return False
>> 
>> Would there be interest in adding something like this to the os module
>> as os.workdir() ?
> 
> I've needed (and implemented my own version of) this often enough that
> I'd be in favour of it. Of course, as you show, it's not hard to write
> it yourself, so I can live with it not getting implemented, too :-)
> 
> Paul
> ___
> 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/I6YFWYNUAV7G6DNPZTBJ6T3SGJDPGBJL/
> 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/B2DICGY5Q65IFWPSBVFYCYNJBGJ7KNGY/
Code of Conduct: http://python.org/psf/codeofconduct/