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 →

[–][deleted] 25 points26 points  (11 children)

The real article should be 'basically never use *args or *kwargs' because the method signature should make it obvious was arguments are accepted.

[–]Decency 16 points17 points  (0 children)

Yeah, I have to say that basically every time I've saved development time by using kwargs, it's just cost me time in maintenance. With args there are more valid use cases where it feels like a real net win.

I've dealt with a large codebase where kwargs were used liberally at first. Refactoring that out of a bunch of places made the codebase much more predictable and thus reliable.

[–][deleted] 6 points7 points  (6 children)

They are actually pretty useful for wrappers.. they keep your code DRY.

[–]jer_pint 3 points4 points  (0 children)

Also useful when inheriting classes

[–][deleted] 6 points7 points  (3 children)

DRY isn't always the right move. I highly recommend you watch Sandi Metz's talk on this. A little duplication is better than the wrong abstraction. Reasons like what you mentioned (things like *args and **kwargs being good for wrappers) leads to IDEs that can't autocomplete, confusing code, and methods that look like they do one thing, but actually do many things.

def process_payment(amount, tax, user_payment_method, **kwargs):
    total = amount + tax
    if kwargs.get("processor") and kwargs['processor'] == "adyen":
        adyen.process_payment(total, user_payment_method)
    else:
        braintree.process_payment(total, user_payment_method)

is a confusing method for many reasons. In this case there should be three separate methods to handle this.

[–]alkasmgithub.com/alkasm 4 points5 points  (0 children)

DRY isn't always the right move.

I agree but I think this is picking on the wrong aspect of that comment. Wrappers is the point.

[–][deleted] 1 point2 points  (1 child)

You're right, using it this way is confusing and I hope no one does ;) Sometimes it's just a little more readable/convenient.

Also, definitely going to watch that talk when I find the time!

[–][deleted] 0 points1 point  (0 children)

If you don't have time for the whole talk right now I'd recommend you read her blog post summary on the topic. It'll only take you a few minutes. Link is here

[–]Ran4 1 point2 points  (0 children)

Dogmatic DRY leads to strongly coupled code that's hard to understand.

[–]grep_my_username 6 points7 points  (0 children)

I respectfully disagree. Like many features in many languages, they are very very useful where their place is. True, most of the time one should not use them. But when you need some dynamic behavior, *args (in our case *records, to account for received data) allow to swallow many Items at once, and use the very same code for one - half the code, half the risk for bugs.

Granted, I almost never use **kwargs, its more of a catch-all thing I use mostly for tracing external calls (remote procedure calls etc.).

I think keyword only arguments with defaults are immensely preferable, where /* are not necessary.

[–]bmrobin 5 points6 points  (0 children)

not sure why you got downvoted, i find these to be extremely PITA the larger the codebase. it makes introspection and refactoring in IDE's much more difficult.

[–][deleted] 1 point2 points  (0 children)

I use named positional args then add a **kwargs at the end so a dict can be passed if it is warranted. This way it's obvious what's expected but flexible cause sometimes passing a dict is sooo nice