1

The question is asked in the context of Python, but it is also relevant for any languages with named parameters support.

If some entity in my code (e.g. a pubsub implementation) or even a simple function accepts a callback, does it make more sense to call it with positional arguments or with named arguments?

def foo(on_foo_ended):
    foo_result = await ...

    # Call with positional argument:
    on_foo_ended(foo_result)

    # Call with named argument:
    on_foo_ended(result=foo_result)

A call with positional arguments does not require any arbitrary parameter naming from the user, but may instead impose arbitrary parameter ordering. Named arguments require matching parameter names, but are (to some extent) self-documenting and do not force the user to order them.

Assuming we are developing a library, it would be preferable to use the most common convention if there is one. If there is none, would it make sense to prefer one way over the other? I suppose complex strategies like "pass positional argument when there is only one and named arguments when there are two or more" would be too arbitrary and probably difficult to use.

4

Either choice is fine, as long as you clearly document how you're calling the callback. I've found that an example invocation works very well, i.e. show this in your docs:

on_foo_ended(result=foo_result)

I tend to prefer positional arguments for callbacks, since this avoids forcing a particular parameter name on my users. This is particularly the case if your problem domain is different from your user's problem domain. If a result is always a result for your users, this is fine, but what if it is a confirmationRequest, trade_counterparty, download_link, or completely ignored _?

Another reason to prefer positional arguments is if you are using the typing module. The typing.Callable type can only represent positional arguments, not named arguments. That is quite annoying, but in some use cases it is more valuable to accept the restrictions of the static type system.

Of course these reasons aren't very strong since users can always provide a simple adapter lambda result: actual_function(result), so it still boils down to: do whatever you are willing to document.

  • Thanks, it looks like with differing problem domains positional parameters make more sense. As for types, inability to express named parameters feels more like a restriction of particular type system (which may be lifted in the future). – interphx Mar 1 '17 at 6:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.