Keywords have to be strings
>>> def foo(**kwargs):
... pass
...
>>> foo(**{0:0})
TypeError: foo() keywords must be strings
But by some black magic, namespaces are able to bypass that
>>> from types import SimpleNamespace
>>> SimpleNamespace(**{0:0})
namespace()
Why? And how? Could you implement a Python function that can receive integers in the kwargs
mapping?
*args collects the positional arguments that are not explicitly defined and store them in a tuple. **kwargs does the same as *args but for keyword arguments. They are stored in a dictionary because keyword arguments are stored as name-value pairs.
Understanding **kwargs The double asterisk form of **kwargs is used to pass a keyworded, variable-length argument dictionary to a function. Again, the two asterisks ( ** ) are the important element here, as the word kwargs is conventionally used, though not enforced by the language.
Python **kwargs In the function, we use the double asterisk ** before the parameter name to denote this type of argument. The arguments are passed as a dictionary and these arguments make a dictionary inside function with name same as the parameter excluding double asterisk ** .
Passing Dictionary as kwargs “ kwargs ” stands for keyword arguments. It is used for passing advanced data objects like dictionaries to a function because in such functions one doesn't have a clue about the number of arguments, hence data passed is be dealt properly by adding “**” to the passing type.
Could you implement a Python function that can receive integers in the kwargs mapping?
No, you can't. The Python evaluation loop handles calling functions defined in Python code differently from calling a callable object defined in C code. The Python evaluation loop code that handles keyword argument expansion has firmly closed the door on non-string keyword arguments.
But SimpleNamespace
is not a Python-defined callable, it is defined entirely in C code. It accepts keyword arguments directly, without any validation, which is why you can pass in a dictionary with non-string keyword arguments.
That's perhaps a bug; you are supposed to use the C-API argument parsing functions, which all do guard against non-string keyword arguments. SimpleNamespace
was initially designed just as a container for the sys.implementation
data*, and wasn't really designed for other uses.
There might be other such exceptions, but they'll all be C-defined callables, not Python functions.
* The time.get_clock_info()
method also runs an instance of the SimpleNamespace
class; it's the only other place that the type is currently used.
SimpleNamespace now rejects integer keyword keys. As Martijn supposed, the original behavior was a bug. It seems that it was fixed by bpo-31655: Validate keyword names in SimpleNamespace constructor in v3.9.0b2, and then backported to 3.6.
No, kwargs cannot be integers. This answer, however, is designed as a (very) short history lesson rather than technical answer (for that, please see @MartijnPierter's answer).
The check was originally added in 2010, in issue 8419 (commit fb88636199c12f63d6c8c89f311cdafc91f30d2f) for Python 3.2 (and I believe Python 2.7.4 as well, but don't quote me on that), and simply checked that call kwargs were strings (and raised a value error if they weren't). It also added PyArg_ValidateKeywordArguments
to C-api, which simply performed the above check.
In 2017, issue 29951 changed the error text for Python 3.7 from "keyword arguments must be strings" to "keywords must be strings" in PR 916 (commit 64c8f705c0121a4b45ca2c3bc7b47b282e9efcd8). The error remained a ValueError
and it did not change the behaviour in any way, and was simply a small change to the error descriptor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With