
Something I maybe hadn't been clear on before cramming for a workshop: Even functions with purely positional parameters may be passed a dict, in which case the positional parameters will be treated like named ones, i.e. the dict will map to them. I'll use the new formating protocol:
from __future__ import print_function
def f(a, b, c): print("a={0}, b={1}, c={2}".format(a,b,c))
f(1,2,3) a=1, b=2, c=3
Here's what I'm illustrating:
thedict = dict(c=5,a=10,b='cat')
f(**thedict) a=10, b=cat, c=5
Now what if we try to sneak in an argument that doesn't map:
thedict = dict(c=5,a=10,b='cat', d='dog') f(**thedict)
Traceback (most recent call last): File "<pyshell#11>", line 1, in <module> f(**thedict) TypeError: f() got an unexpected keyword argument 'd' The d is caught, an exception is raised. So here we might add the all purpose "pooper scooper" (yeah, scatological -- sometimes effective pedagogy):
def f(a, b, c, **kwargs): print("a={0}, b={1}, c={2}".format(a,b,c))
The d now gets through, though nothing echoes:
f(**thedict) a=10, b=cat, c=5
Lets make sure we see what's in "overflow":
def f(a, b, c, **kwargs): print("a={0}, b={1}, c={2}".format(a,b,c)) print(kwargs)
f(**thedict) a=10, b=cat, c=5 {'d': 'dog'}
Is an all purpose pooper scooper allowed to have defaults? No, default arguments are what turn parameters into named parameters. *args and **kwargs (often so named by convention) are not named parameters so much as "collectors" of "overflow" arguments (made-up terminology).
def f(a, b, c, d='dog', *e): print("a={0}, b={1}, c={2} d={3} e={4}".format(a,b,c,d,e))
f(**thedict) a=10, b=cat, c=5 d=dog e=()
Speaking of made-up terminology, when I pass **thedict as an argument, I tend to think of the ** as "explode". If you don't double-star it, it goes through as just the one argument and an exception gets raised:
f(thedict)
Traceback (most recent call last): File "<pyshell#31>", line 1, in <module> f(thedict) TypeError: f() takes at least 3 arguments (1 given) The same "explode" operator works for tuples in that it "unpacks" the one argument into len(tuple) arguments. The typical use is to make (x,y,z)-tuples map to some function that expects x, y and z as separate arguments. The error messages remind us when we fail to "explode" one argument into many:
def f(x, y, z): return x**2 + y**2 + z**2
f(1,2,3) 14 coords = (1,2,3) f(coords)
Traceback (most recent call last): File "<pyshell#38>", line 1, in <module> f(coords) TypeError: f() takes exactly 3 arguments (1 given)
f(*coords) 14 f(dict(y=2,x=1,z=3))
Traceback (most recent call last): File "<pyshell#40>", line 1, in <module> f(dict(y=2,x=1,z=3)) TypeError: f() takes exactly 3 arguments (1 given)
f(**dict(y=2,x=1,z=3)) 14
Kirby

Hey Kirby!! This is the best explanation I've seen of Python's argument passing subtleties. If you don't mind I would like to post it on our PyKata website in a section "Tips from the Masters", with you as author, of course. We could also put a link to a page on your website, if you prefer. -- Dave ************************************************************ * * David MacQuigg, PhD email: macquigg at ece.arizona.edu * * * Research Associate phone: USA 520-721-4583 * * * * ECE Department, University of Arizona * * * * 9320 East Mikelyn Lane * * * * http://purl.net/macquigg Tucson, Arizona 85710 * ************************************************************ * kirby urner wrote:
...
Even functions with purely positional parameters may be passed a dict, in which case the positional parameters will be treated like named ones, i.e. the dict will map to them.
I'll use the new formating protocol:
from __future__ import print_function
def f(a, b, c):
print("a={0}, b={1}, c={2}".format(a,b,c))
f(1,2,3)
a=1, b=2, c=3
Here's what I'm illustrating:
thedict = dict(c=5,a=10,b='cat')
f(**thedict)
a=10, b=cat, c=5
Now what if we try to sneak in an argument that doesn't map:
thedict = dict(c=5,a=10,b='cat', d='dog') f(**thedict)
Traceback (most recent call last): File "<pyshell#11>", line 1, in <module> f(**thedict) TypeError: f() got an unexpected keyword argument 'd'
The d is caught, an exception is raised.
So here we might add the all purpose "pooper scooper" (yeah, scatological -- sometimes effective pedagogy):
def f(a, b, c, **kwargs):
print("a={0}, b={1}, c={2}".format(a,b,c))
The d now gets through, though nothing echoes:
f(**thedict)
a=10, b=cat, c=5
Lets make sure we see what's in "overflow":
def f(a, b, c, **kwargs):
print("a={0}, b={1}, c={2}".format(a,b,c)) print(kwargs)
f(**thedict)
a=10, b=cat, c=5 {'d': 'dog'}
Is an all purpose pooper scooper allowed to have defaults? No, default arguments are what turn parameters into named parameters. *args and **kwargs (often so named by convention) are not named parameters so much as "collectors" of "overflow" arguments (made-up terminology).
def f(a, b, c, d='dog', *e):
print("a={0}, b={1}, c={2} d={3} e={4}".format(a,b,c,d,e))
f(**thedict)
a=10, b=cat, c=5 d=dog e=()
Speaking of made-up terminology, when I pass **thedict as an argument, I tend to think of the ** as "explode".
If you don't double-star it, it goes through as just the one argument and an exception gets raised:
f(thedict)
Traceback (most recent call last): File "<pyshell#31>", line 1, in <module> f(thedict) TypeError: f() takes at least 3 arguments (1 given)
The same "explode" operator works for tuples in that it "unpacks" the one argument into len(tuple) arguments. The typical use is to make (x,y,z)-tuples map to some function that expects x, y and z as separate arguments.
The error messages remind us when we fail to "explode" one argument into many:
def f(x, y, z):
return x**2 + y**2 + z**2
f(1,2,3)
14
coords = (1,2,3) f(coords)
Traceback (most recent call last): File "<pyshell#38>", line 1, in <module> f(coords) TypeError: f() takes exactly 3 arguments (1 given)
f(*coords)
14
f(dict(y=2,x=1,z=3))
Traceback (most recent call last): File "<pyshell#40>", line 1, in <module> f(dict(y=2,x=1,z=3)) TypeError: f() takes exactly 3 arguments (1 given)
f(**dict(y=2,x=1,z=3))
14
Kirby _______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
participants (2)
-
David MacQuigg
-
kirby urner