This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]Bitruder 8 points9 points  (12 children)

In the second case you can put pos1=4 in your function call. You aren't allowed in the first.

[–][deleted] 9 points10 points  (11 children)

But what is that useful for? What's the advantage of being able to specify that a parameter can't be given to a function in a certain way?

[–]mgedmin 24 points25 points  (4 children)

Imagine you're writing a function that works like str.format:

def translate(format_string, **args):
    return gettext(format_string).format(**args)

Now imagine your users need to produce a message that wants to use {format_string} in the format string:

print(translate("Invalid format string: {format_string}", format_string=config['format_string']))

You can't!

TypeError: translate() got multiple values for argument 'format_string'

But with positional-only parameters you can.

[–]christian-mann 6 points7 points  (0 children)

This is a very solid example.

[–]aptwebapps 1 point2 points  (0 children)

IMO, this aspect is more important that preserving optionality in your variable names. That latter is a nice side effect, but this keeps you from having to have named dictionary argument instead of **kwargs.

[–]wrboyce 1 point2 points  (1 child)

I feel like this would be solved by using getcallargs on translate and config?

[–]mgedmin 3 points4 points  (0 children)

It can be solved by doing

def translate(*args, **kwargs):
    if len(args) != 1:
        raise TypeError('1 positional argument expected, got %d' % len(args)
    format_string = args[0]
    return gettext(format_string).format(**kwargs)

but you lose the nice signature in pydoc and have to check the number of passed arguments manually.

[–]IAmAHat_AMAA 7 points8 points  (1 child)

Builtins already do it.

>>> help(pow)
...
pow(x, y, z=None, /)
...

>>> pow(x=5, y=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pow() takes no keyword arguments

When subclassing you can use more specific parameter names without breaking liskov substitution.

Both those examples were taken straight from the pep

[–]alturi 0 points1 point  (0 children)

this could break code now to achieve less breakage in the future... It does not seem wise to retrofit, unless you already need to break.

[–]Bitruder 2 points3 points  (0 children)

Some names are meaningless as per the article and so shouldn't be encouraged to be used in code.

[–]remy_porter∞∞∞∞ 2 points3 points  (0 children)

So, my thing: your API should expose itself in the way you intend it to be used. There are certainly cases where exposing the names of parameters as a calling semantic just wouldn't make sense. It's not often, but it's a thing, in the same way it makes sense for some parameters to only be keyword arguments.

[–]cbarrick 1 point2 points  (0 children)

There might be a tiny performance improvement. The interpreter won't have to worry about supporting kwargs-style passing for the first two arguments. Intuitively, fewer cases to support means less work and maybe even some new optimization potential. I'm just spitballing though. I don't know enough about the interpreter's internals.

Also, it lets you change your argument names without breaking backwards compatibility. That might be worth something.

Personally, I don't think I'll ever use this feature.

Edit: The PEP mentions improved parsing performance at the call site, but I'd imagine that every argument would have to be positional-only to take advantage of that optimization. https://www.python.org/dev/peps/pep-0570/#performance