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

Joshua Landau joshua.landau.ws at gmail.com
Wed Jun 26 16:46:26 CEST 2013


On 26 June 2013 09:04, Ethan Furman <ethan at stoneleaf.us> wrote:
> On 06/26/2013 12:48 AM, Greg Ewing wrote:
>>
>> Ron Adam wrote:
>>>
>>> And I don't like the '=' with nothing on the right.
>>
>>
>> Expanding on the suggestion someone made of having a
>> single marker of some kind in the argument list, I
>> came up with this:
>>
>>      def __init__(self, text, font = system_font, style = 'plain'):
>>         default_size = calc_button_size(text, font, style)
>>         Widget.__init__(self, size = default_size, pass font, style)
>
>
> I don't care for it.
>
> A word doesn't stand out like a character does, plus this usage of pass is
> completely different from its normal usage.
>
> We're already used to interpreting '*' as a coin with two sides, let's stick
> with it:
>
>     def apply_map(map, target, *, frobble):  # '*' means frobble is keyword
> only
>        ...
>
> and later:
>
>     frobble = some_funny_stuff_here()
>     .
>     .
>     .
>     apply_map(map=kansas, target=toto, *, frobble) # '*' means frobble maps
> to keyword frobble

Whilst Greg Ewing has made me also much more sympathetic to this view,
I feel that:

1) This is nearly unreadable - it does not say what it does in the slightest

2) It's added syntax - that's a high barrier. I'm not convinced it's
worth it yet.

3) It still feels like hackery; I might prefer something explicitly
hackery like this:

    apply_map(map=kansas, target=toto, **locals("frobble"))

where locals is:

    def locals(*args):
        if args:
            return {arg:original_locals()[arg] for arg in args}
        else:
            return original_locals()

For Greg's he'd use:

   def __init__(self, text="Hello", font=system_font, **kwds):
            default_size = calc_default_size(text, font)
            Widget.__init__(self, size=default_size, **locals("font"), **kwds)

or even

   def __init__(self, text = "Hello", font = system_font, **kwds):
            default_size = calc_default_size(text, font)
            Widget.__init__(self, **locals("size", "font"), **kwds)

under the asumption that http://bugs.python.org/issue2292 does get
implemented first.

For reference, he is using (respaced for consistency):

        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)

Note that this is only a way to suggest that *there might be another
way*; maybe something involving objects.

3 cont.) The reason I think it feels like hackery is simply that I
don't feel like Python is ever "reference by name"; objects don't know
what they are called (some know what they *were* named; but they have
no guarantee it's true) it feels *very wrong* to give "foobar" to
function and have that function somehow extract the name! I know it's
not doing that, but it's ever-so-close.

However; maybe:

    class AttrDict(dict):
        def __init__(self, mapping, **defaults):
            super().__init__(defaults, **mapping)
            self.__dict__ = self

    def __init__(self, **kwds):
        kwds = AttrDict(kwds, text="Hello", font=system_font)

        kwds.size = calc_default_size(kwds.text, kwds,font)

        Widget.__init__(self, **kwds)

and a decorator could even make this:

    @dynamic_kwds(text="Hello", font=system_font)
    def __init__(self, kwds):
        kwds.size = calc_default_size(kwds.text, kwds,font)
        Widget.__init__(self, **kwds)

which would have the same run-time effect as the original (the second
keeps re-evaluating the signature).


Again; I mention these only to show people not to have a restricted
idea on what the solution looks like - don't just try and fix the
symptoms of the problem.


More information about the Python-ideas mailing list