[Python-ideas] Short form for keyword arguments and dicts

Andrew Barnert abarnert at yahoo.com
Wed Jun 26 01:33:27 CEST 2013


From: Greg Ewing <greg.ewing at canterbury.ac.nz>

Sent: Tuesday, June 25, 2013 3:09 PM


> Andrew Barnert wrote:
> 
>>  What are the use cases you have in mind?


> Here's a simplified version of something
> that crops up in various places in my GUI libraries. I have
> a widget, let's say a Button, and I want to calculate a
> default size for it during construction. To do that I need
> to know its font, which is one of the things that can
> potentially be passed as an argument to the constructor.
> So I want to "peek" at the font argument as it goes by:
> 
>     class Button(Widget):
> 
>         def __init__(self, text = "Hello", font = system_font, 
> **kwds):
>             default_size = calc_default_size(text, font)
>             Widget.__init__(self, size = default_size, font = font, **kwds)


OK, I recognize this kind of thing. And I also recognize your uneasy feeling with it. 

Notice that in this case, you don't actually need to pull out font and pass it along:

        def __init__(self, text = "Hello", **kwds):
            default_size = calc_default_size(text, kwds.get('font', system_font))

            Widget.__init__(self, size = default_size, **kwds)


That also removes the need to copy the default value from the base class, and I think it gets across the idea of "peeking at the kwargs" more clearly than pulling one out into a positional-or-keyword arg.

However, I'm not sure it's actually more readable this way. And it's certainly more verbose, not less, and all those get calls would add up if I were peeking at a lot of values.

Also, that doesn't help if you want to do something with the value:

        def __init__(self, text = "Hello", font = system_font, **kwds):
            if os.sep in font: font = load_font_file(font)
            default_size = calc_default_size(text, font)
            Widget.__init__(self, size = default_size, font = font, **kwds)


> Now, it's not so bad when there are only one or two passed-on
> arguments, but if you have a handful it starts to feel a bit
> wanky.

I think the issue isn't how many passed-on arguments you have, but how many you're peeking at. If you've got 20 arguments to pass along, but only need to peek at 1 or 2, your code is fine; it's when you've got 6 arguments to pass along and need to peek at all 6 that it gets nasty.

> I think I've figured out why this seemingly-small amount of
> redundancy bothers me so much. It's not just that I feel I'm
> saying the same thing twice, but that I feel I'm not saying
> *anything at all*. If I were to write this as an ordinary
> assignment:
> 
>    font = font
> 
> then it would be completely redundant. Now I know full well
> that it's different with a keyword argument, because the two
> sides live in different namespaces. But some part of my brain
> still tries to tell me that I'm doing something silly

Actually, I think it's a different problem for me. My brain initially wonders why I'm trying to use the default-value hack:

    filters = [lambda x, modulus=modulus: x % modulus == 0 for modulus in range(2, 6)]

… on a function call instead of a function definition.

Anyway, now that I see your example, I'm definitely more sympathetic to the problem.

But I still don't like the proposed syntax, even if the problem were nearly compelling enough to add more syntax—which I don't think it is.


More information about the Python-ideas mailing list