Using the Python function syntax def f(**kwargs)
, in the function a keyword argument dictionary kwargs
is created, and dictionaries are mutable, so the
It is always safe. As the spec says
If the form “**identifier” is present, it is initialized to a new ordered mapping receiving any excess keyword arguments, defaulting to a new empty mapping of the same type.
Emphasis added.
You are always guaranteed to get a new mapping-object inside the callable. See this example
def f(**kwargs):
print((id(kwargs), kwargs))
kwargs = {'foo': 'bar'}
print(id(kwargs))
# 140185018984344
f(**kwargs)
# (140185036822856, {'foo': 'bar'})
So, although f
may modify an object that is passed via **
, it can't modify the caller's **
-object itself.
Update: Since you asked about corner cases, here is a special hell for you that does in fact modify the caller's kwargs
:
def f(**kwargs):
kwargs['recursive!']['recursive!'] = 'Look ma, recursive!'
kwargs = {}
kwargs['recursive!'] = kwargs
f(**kwargs)
assert kwargs['recursive!'] == 'Look ma, recursive!'
This you probably won't see in the wild, though.