3 ms·
I read the PEP and understand the argument (no pun intended). I'm just not convinced. I don't find the justifications given in the PEP at all persuasive. Rarely
by js2 8y ago
I read the PEP and understand the argument (no pun intended). I'm just not convinced. I don't find the justifications given in the PEP at all persuasive. Rarely have I ever needed to enforce positional over keyword arguments and the rare times I've needed to, I can use:
*args, **kwargs
as needed, and again, don't find the PEP's arguments against doing so convincing.
Also, I mean, come on, if a function signature is:
ord(c)
It's pretty damn obvious not to use "c" as a keyword argument. And as hard as it is for programmers to name things, I can't recall ever struggling to name a function parameter.
If you need to rename a parameter that it's likely someone might be calling as a keyword, then bite the bullet and break backwards compatibility or just introduce a new function name if backwards compat is truly that important. (And besides, this has to be one of the more trivial checks for a static analyzer to find.)
> the number (and optionality) of positional parameters is completely invisible and implicit rather than readable and explicit
It's invisible in the function signature, but it should be in the function documentation or as a last resort, read the source. I find myself reading Python library source code not infrequently because it's not unusual to need to understand a function's behavior. Getting the function call correct is like the least hard part? But again, this really feels like an edge case.
> it requires various non-trivial assertions repeated every time.
In fact, that's a pretty trivial assertion if you ask me. ¯\_(ツ)_/¯.
FWIW, I don't find:
(arg=None, /)
to be a legible syntax for declaring "this function takes a single optional positional argument". And in its full form, this is truly ugly:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
Seriously, WTF. The library author couldn't make up their mind about pos_or_kwd? Why even allow that? This is no better:
def f(pos1, pos2, /, *, kwd1, kwd2):
Just no.
Maybe I'd be more convinced with a cleaner syntax. I think the Per-Argument Marker option proposed in the PEP is a lot more obvious (not sure about using a '.' though) and think the argument against it is pretty weak: "While this approach may be easier to read, it has been rejected because / as an explicit marker is congruent with ∗∗ for keyword-only arguments and is less error-prone."
I note that "less error-prone" is stated without evidence and that "is congruent with ∗∗" is definitely against the zen.
But generally, as I said, the entire PEP is not convincing to me. Anyway, I'm sure I'm repeating the arguments against the PEP others have made and Guido has ruled in favor anyway, so I'm just screaming at the ocean.
- ben509 8y agoOn one of the threads, they suggest destructuring syntax. Taking that a bit further and ignoring backwards compatibility entirely: def foo([po1, po2], pk1, pk2, *args, {kw1, kw2, kwd1=default, kwd2=default, **kw}): pass And it implies some obvious shortcuts: def all_pos_only[po1, po2, po3=default, *args]: pass def all_kw_only{kw1, kw2, kw3=default, **kw}: pass
- gizmo385 8y agoAs a fan of Clojure, I would love for Python to get rid of most of strange and archaic (IMO) unpacking syntax and just switch wholesale to Clojure-style destructuring. In my opinion, it's a single solution for all of those problems and it ends up looking a lot cleaner. It's also just a lot easier to work with if you're trying to unpack a single value from a nested structure or define a flexible API.
- js2 8y agoIf I ever saw this in real life: foo([po1, po2], pk1, pk2, *args, {kw1, kw2, kwd1=default, kwd2=default, **kw}) I'd think... that function is trying to do too much with its parameters and should be multiple functions. Now yes, I realize an author could already do that with ∗args and ∗∗kwds, but the fact that the author would need to handle the argument parsing is sufficient disincentive to prevent most people from doing so.
- ben509 8y agoBut if you had to refactor the above function, you wouldn't have to reverse-engineer some argument parsing. You'd know how it must be called anywhere in the project, just by looking. And generally, I think the disincentive rationale is self-defeating: * the premise behind disincentive is you're dealing with someone who is (at least in the moment) careless * now they're going to have to write more code to do a thing they've set out to do * but we've already selected for an individual who is writing carelessly In this case, it can only work if extra argument checks are the last straw that causes this individual to say "enough" and refactor that function. For what my experience is worth, I think this is unlikely.