So, when someone does: atleast_1d(*l), they get Array | list[Array] even if they know that l has length one. If one were part of the standard library, they could do atleast_1d(one(l)), and they would get Array as desired.
I use unpacking for this quite often but I worry about its meaning being cryptic if I use it in demonstrations that I am showing to others. It can also be awkward just because you need to break something out into a statement rather than being able to do it inline as an expression:
y = func(one(x))
[z] = x
y = func(z)
Having a function also means that you can use it with other functional things like map(one, ...) etc.
This is one of those cases where I would use it somewhat regularly if it was a builtin and was something that was a well-known Python idiom that others could be expected to recognise but at the other extreme I certainly would not depend on a library for it. In between having a builtin or needing an external library there is the possibility of writing a function or of it being in the stdlib. Often I want this in an interactive context and in that situation I don’t really want to make a function and also am less likely to use something that I would need to import from anywhere even it was in the stdlib.
I like @tim.one’s comment from there about adding functions that are easy enough to write yourself:
functional language people don’t hesitate to “build in” any number of
functions easily implemented in terms of other ones. This started
already with LISP, which very quickly, e.g., added (CADR x) for (CAR
(CDR x)), (CADDR x) for (CAR (CDR (CDR x))) and so on - then went on
to also add additional spellings (FIRST, SECOND, NTH, etc). The point
in that context is to have common spelling and endcase behavior for
things - no matter how simple - that are reinvented every day
I feel similarly about stuff like this, but I’m leery of cluttering up builtins with a lot of fairly niche functions.
Idly thinking about this conflict, I wonder if it would be helpful to have namespaced “builtins”. Basically a stdlib module that’s always imported, but not in your global namespace if you don’t need it. Or perhaps lazily imported, if that’s possible.
Nope, no difference. You can think of the first one as a tuple-like syntax and the second as list-like syntax. The only real difference is with the one-element unpack, where you have a trailing comma in the tuple variant but can omit it in the list variant, which is why I prefer the brackets in that situation.
target ::= identifier
| "(" [target_list] ")"
| "[" [target_list] "]"
Assignment of an object to a target list, optionally enclosed in parentheses or square brackets, is
recursively defined as follows.
People should really learn assignment unpacking as it is also used, just as frequently, in for statements.
>>> for a, in (, [1,2]): print(a)
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
for a, in (, [1,2]): print(a)
ValueError: too many values to unpack (expected 1)