[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