Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #103083 > unrolled thread

Python keyword args can be any string

Started bySteven D'Aprano <steve+comp.lang.python@pearwood.info>
First post2016-02-18 16:42 +1100
Last post2016-02-19 03:41 -0800
Articles 8 — 7 participants

Back to article view | Back to comp.lang.python


Contents

  Python keyword args can be any string Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2016-02-18 16:42 +1100
    Re: Python keyword args can be any string Chris Angelico <rosuav@gmail.com> - 2016-02-18 16:57 +1100
    Re: Python keyword args can be any string Ben Finney <ben+python@benfinney.id.au> - 2016-02-18 16:59 +1100
    Re: Python keyword args can be any string Terry Reedy <tjreedy@udel.edu> - 2016-02-18 01:31 -0500
    Re: Python keyword args can be any string Mark Lawrence <breamoreboy@yahoo.co.uk> - 2016-02-18 07:55 +0000
      Re: Python keyword args can be any string Steven D'Aprano <steve@pearwood.info> - 2016-02-19 11:03 +1100
        Re: Python keyword args can be any string Ben Finney <ben+python@benfinney.id.au> - 2016-02-19 11:58 +1100
    Re: Python keyword args can be any string Rustom Mody <rustompmody@gmail.com> - 2016-02-19 03:41 -0800

#103083 — Python keyword args can be any string

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2016-02-18 16:42 +1100
SubjectPython keyword args can be any string
Message-ID<56c559c2$0$2916$c3e8da3$76491128@news.astraweb.com>
Today I learned that **kwargs style keyword arguments can be any string:


py> def test(**kw):
...     print(kw)
... 
py> kwargs = {'abc-def': 42, '': 23, '---': 999, '123': 17}
py> test(**kwargs)
{'': 23, '123': 17, '---': 999, 'abc-def': 42}


Bug or feature?



-- 
Steve

[toc] | [next] | [standalone]


#103084

FromChris Angelico <rosuav@gmail.com>
Date2016-02-18 16:57 +1100
Message-ID<mailman.231.1455775046.22075.python-list@python.org>
In reply to#103083
On Thu, Feb 18, 2016 at 4:42 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> Today I learned that **kwargs style keyword arguments can be any string:
>
>
> py> def test(**kw):
> ...     print(kw)
> ...
> py> kwargs = {'abc-def': 42, '': 23, '---': 999, '123': 17}
> py> test(**kwargs)
> {'': 23, '123': 17, '---': 999, 'abc-def': 42}
>
>
> Bug or feature?

Probably neither. It's something that can't hurt, so there's no point
specifically blocking it. You can do the same thing with other
dictionaries:

>>> globals()["abc-def"] = 42
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'abc-def']
>>> class Blob: pass
...
>>> b = Blob()
>>> b.__dict__[""] = 23
>>> dir(b)
['', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
'__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__']

I suppose it's possible for this to be a vulnerability, eg if you
build up an XML node using keyword arguments for attributes, and end
up accepting something with a space in it. But most of the time, the
only consequence is that you use a dict to create a situation that can
only be handled with another dict. Doesn't seem worth the hassle of
preventing it, but I would also see this as a bizarre thing to
deliberately exploit.

ChrisA

[toc] | [prev] | [next] | [standalone]


#103085

FromBen Finney <ben+python@benfinney.id.au>
Date2016-02-18 16:59 +1100
Message-ID<mailman.232.1455775197.22075.python-list@python.org>
In reply to#103083
Steven D'Aprano <steve+comp.lang.python@pearwood.info> writes:

> Today I learned that **kwargs style keyword arguments can be any string:
>
>
> py> def test(**kw):
> ...     print(kw)
> ... 
> py> kwargs = {'abc-def': 42, '': 23, '---': 999, '123': 17}
> py> test(**kwargs)
> {'': 23, '123': 17, '---': 999, 'abc-def': 42}
>
>
> Bug or feature?

Incidental feature, I think.

If the caller is deliberately unpacking a dict, it's on them to ensure
the keys are valid identifiers or wear the consequences.

If the function cares so little about the keys in its kwargs that (as in
your example) any string will do for each key, then it's a consenting
actor IMO.

The times when it's a problem – i.e. that the function is trying to use
items from that dictionary as name bindings – the errors will be raised
to the caller that unpacked that mapping. That's where the errors belong.

-- 
 \      “There's a fine line between fishing and standing on the shore |
  `\                            looking like an idiot.” —Steven Wright |
_o__)                                                                  |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#103087

FromTerry Reedy <tjreedy@udel.edu>
Date2016-02-18 01:31 -0500
Message-ID<mailman.233.1455777087.22075.python-list@python.org>
In reply to#103083
On 2/18/2016 12:59 AM, Ben Finney wrote:
> Steven D'Aprano <steve+comp.lang.python@pearwood.info> writes:
>
>> Today I learned that **kwargs style keyword arguments can be any string:
>>
>>
>> py> def test(**kw):
>> ...     print(kw)
>> ...
>> py> kwargs = {'abc-def': 42, '': 23, '---': 999, '123': 17}
>> py> test(**kwargs)
>> {'': 23, '123': 17, '---': 999, 'abc-def': 42}
>>
>>
>> Bug or feature?
>
> Incidental feature, I think.

The was discussed on pydev some years ago.  Guido says leave as is. This 
and similar cases of allowing non-identifier is string-dicts does not 
seem to cause a problem and apparently has a few rare legitimate  usages.

> If the caller is deliberately unpacking a dict, it's on them to ensure
> the keys are valid identifiers or wear the consequences.
>
> If the function cares so little about the keys in its kwargs that (as in
> your example) any string will do for each key, then it's a consenting
> actor IMO.
>
> The times when it's a problem – i.e. that the function is trying to use
> items from that dictionary as name bindings – the errors will be raised
> to the caller that unpacked that mapping. That's where the errors belong.
>


-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#103093

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2016-02-18 07:55 +0000
Message-ID<mailman.237.1455782186.22075.python-list@python.org>
In reply to#103083
On 18/02/2016 05:42, Steven D'Aprano wrote:
> Today I learned that **kwargs style keyword arguments can be any string:
>
> py> def test(**kw):
> ...     print(kw)
> ...
> py> kwargs = {'abc-def': 42, '': 23, '---': 999, '123': 17}
> py> test(**kwargs)
> {'': 23, '123': 17, '---': 999, 'abc-def': 42}
>
> Bug or feature?
>

I'm not sure, but what on earth got you to this in the first place?

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#103156

FromSteven D'Aprano <steve@pearwood.info>
Date2016-02-19 11:03 +1100
Message-ID<56c65be5$0$1590$c3e8da3$5496439d@news.astraweb.com>
In reply to#103093
On Thu, 18 Feb 2016 06:55 pm, Mark Lawrence wrote:

> On 18/02/2016 05:42, Steven D'Aprano wrote:
>> Today I learned that **kwargs style keyword arguments can be any string:
>>
>> py> def test(**kw):
>> ...     print(kw)
>> ...
>> py> kwargs = {'abc-def': 42, '': 23, '---': 999, '123': 17}
>> py> test(**kwargs)
>> {'': 23, '123': 17, '---': 999, 'abc-def': 42}
>>
>> Bug or feature?
>>
> 
> I'm not sure, but what on earth got you to this in the first place?


A work colleague wanted to pass an argument starting with "-" to a function.

Apparently he didn't have a specific argument in mind. He just wanted to
test the function to breaking point by passing invalid argument names.


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#103159

FromBen Finney <ben+python@benfinney.id.au>
Date2016-02-19 11:58 +1100
Message-ID<mailman.28.1455843544.2289.python-list@python.org>
In reply to#103156
Steven D'Aprano <steve@pearwood.info> writes:

> A work colleague wanted to pass an argument starting with "-" to a
> function.
>
> Apparently he didn't have a specific argument in mind. He just wanted
> to test the function to breaking point by passing invalid argument
> names.

That seems a reasonable test.

    >>> kwargs = {
    ...         'spam': 13,
    ...         'eggs': 17,
    ...         '-beans': 11,
    ...         }
    >>> foo(**kwargs)    # Should this fail?

It exposes a design smell; by capturing ‘**kwargs’, a function has
deiberately not specified which keyword arguments it will accept.

    >>> def foo_captures_kwargs(*args, **kwargs):
    ...     for (name, value) in kwargs.items():
    ...         print("Got argument {name}={value!r}".format(
    ...                 name=name, value=value))
    ... 
    >>> foo_captures_kwargs(**kwargs)
    Got argument eggs=17
    Got argument spam=13
    Got argument -beans=11

Still not a bug in Python IMO. It may be a bug in the program; the
design of the function doesn't provide any way to know.

Perhaps the design can be improved by not using ‘**kwargs’ at all, and
instead using a specific set of keyword-only arguments.

    >>> def foo_names_every_argument(*, spam="Lorem", eggs="ipsum"):
    ...     print("Got argument {name}={value!r}".format(
    ...             name='spam', value=spam))
    ...     print("Got argument {name}={value!r}".format(
    ...             name='eggs', value=eggs))
    ... 
    >>> foo_names_every_argument(**kwargs)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: foo_names_every_argument() got an unexpected keyword argument '-beans'

This is IMO another good reason to migrate ASAP to Python 3; better
design is easier that before.

-- 
 \          “Judge: A law student who marks his own papers.” —Henry L. |
  `\                                                           Mencken |
_o__)                                                                  |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#103186

FromRustom Mody <rustompmody@gmail.com>
Date2016-02-19 03:41 -0800
Message-ID<95706d9d-1e34-4686-b928-146a66341711@googlegroups.com>
In reply to#103083
On Thursday, February 18, 2016 at 11:12:45 AM UTC+5:30, Steven D'Aprano wrote:
> Today I learned that **kwargs style keyword arguments can be any string:
> 
> 
> py> def test(**kw):
> ...     print(kw)
> ... 
> py> kwargs = {'abc-def': 42, '': 23, '---': 999, '123': 17}
> py> test(**kwargs)
> {'': 23, '123': 17, '---': 999, 'abc-def': 42}
> 

Hoo boy!
Namespaces are a honking great idea though sometimes the honk is too loud

> 
> Bug or feature?

Dunno...
I dont like it

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web