I would like to double check the situation.
While @tim.one seems to be the big proponent of keymode solution, I am still doing my best to stay balanced, as I still see them both potentially valid depending on what turns out to be more important for the community.
Maybe there is no battle anymore and I am wasting my energy.
So I just want to get some input to see where we are.
So we have 2 solutions.
- Both are robust and satisfy constraints to sufficient degree.
- Both can be handled by
typing.
- Both are similarly easy to learn.
def keymode_sort(self, /, *,
key=None,
keymode='call',
reverse=False):
- Clear precedent in Python.
open(mode)
- 1 new argument
- Needs 2 arguments to make use of new functionality
def keyiter_keylist_sort(self, /, *,
key=None,
keyiter=None,
keylist=None,
reverse=False):
- Precedent in Python is arguably a bit rarer (although coincidentally same
open has similar aspects)
- 2 new arguments
- Needs 1 argument to make use of new functionality
Argsort with both:
# keymode
indices = sorted(range(len(keys)), key=keys, keymode='iter')
# keyiter_keylist
indices = sorted(range(len(keys)), keyiter=keys)
Accidental mutation:
keymode - no risk
keyiter_keylist - risk well within “consenting adults” range
keymode is a safe option.
However, keyiter_keylist has non-trivial advantages for user experience:
Discoverability is better.
keyiter argument can be guessed easily and unambiguously from signature.
For keylist usage, one would still need to read documentation.
In contrast to keymode, where nothing can be inferred from signature.
IDE / ipython suggestions are much better:
sorted(y, k<tab>
key=
keyiter=
keylist=
Both in signature and from POV of alphabetic priority, keyiter gets precedence over keylist due to recognition that this is more common.
Finally, let’s recap the journey that led us here:
|
keymode |
keyiter_keylist |
| @pf_moore has raised concerns about accidental mutations. I have taken them seriously - neiher of these 2 final contenders have this issue. |
No accidental mutation risk. |
Accidental mutation risk is minimal: keylist requires explicit parameter choice and is unlikely to be used without reading docs. Well within “consenting adults” territory. |
| @Stefan2 has pointed out the importance of user experience - frequent case (as seen in stack) is when the user just wants to source any iterable without the need for conversion and get the answer safely and easily. |
sorted(range(len(keys)), key=keys, keymode='iter') I would guess is a bit too verbose compared to what @Stefan2 is advocating for? |
sorted(range(len(keys)), keyiter=keys) is as good as it can get for those who just want to source any iterable without needing to think about inplace behaviours and other undesirable nuances. |
@tim.one has stressed the importance of keeping equivalence between sorted and list.sort signatures and behaviour. |
Equivalence between sorted and list.sort is kept. |
Equivalence between sorted and list.sort is kept. |
My concern is to keep unambiguous possibiliy to provide a list which gets mutated in-place - this has non-trivial performance benefits in many scenarios (including argsort, dict_sort, sort_many). |
All performance benefits that were initially intended are exposed. |
All performance benefits that were initially intended are exposed. |
- @pf_moore, in your opinion, does
keyiter_keylist sufficiently manages accidental mutation risk?
- @Stefan2, does
keymode provide sufficiently good user experience?
- @tim.one, how do advantages of
keyiter_keylist (the IDE discoverability coupled with 1 less argument on use) stand against advantages of keymode (1 less argument in argspec and a bit clearer precedence in Python) for you?
I believe both solutions are viable and would be happy to implement either.
I’m seeking clarity on which tradeoffs the community finds more acceptable.