[Tutor] **kw and self

Willi Richert w.richert@gmx.net
Thu, 21 Jun 2001 10:12:17 +0200


Hi, thanks again. But one question just arrived ;-)

Why can't I just pass a dictionary? Why do I have to put ** before it?

Thanks,
willi
On Wed, 20 Jun 2001, you wrote:
> On  0, Willi Richert <w.richert@gmx.net> wrote:
> > as a bloody newbie (who as reverted already some others to Python) I walked 
> > 34 times through the whole web and did not get the real meaning of **kw and 
> > self.
> 
> *breathe in deeply*
> 
> Ok.
> 
> PART I: THE HEDGEHOG
> --------------------
> 
> No wait, that's wrong.
> 
> PART I, edited: KEYWORD ARGUMENTS
> ----------------------------------
> 
> (this has become quite long. probably the best way to understand it
> completely is to enter all the examples into an interpreter and play around
> with them).
> 
> Do you know what a default argument to a function is? Say we have a function
> like
> 
> def and_now_for(s = "something completely different"):
>    print "And now for...", s
> 
> It takes one argument, in principle:
> >>> and_now_for("more shrubberies")
> And now for... more shrubberies
> 
> But you can also take the argument off, so that the default is used:
> >>> and_now_for()
> And now for... something completely different
> 
> This is obviously useful. Now say we have a function that takes several
> arguments:
> 
> def recipe(ingr1="spam", ingr2="spam", ingr3="eggs", ingr4="spam"):
>    print ingr1, ingr1, ing3, "and", ingr4
> 
> It works fine when called with no arguments, or with some:
> >>> recipe()
> spam spam eggs and spam
> >>> recipe("beans")
> beans spam eggs and spam
> 
> But what if we want to leave all the default arguments in, except for the
> *last*? You can't give an argument except when you also enter all the ones
> before it, or Python doesn't know what you want. Enter keyword arguments:
> 
> >>> recipe(ingr4="shrubberies")
> spam spam eggs and shrubberies
> 
> Again, useful. You can fill in any argument like this. For instance in
> Tkinter GUIs, functions have lots and lots of default arguments and you
> usually only want to enter one or two, so you use keyword arguments.
> 
> Now this can be made even more general, with the **arguments construct.
> You don't bother to list the arguments and their defaults anymore, but let
> the user give any keyword arguments it wants, and they're passed in as a 
> *dictionary*. Consider:
> 
> def kwarg_demo(**kwargs):
>    print kwargs
> 
> >>> kwarg_demo(first="bla", second="whee")
> {'first': 'bla', 'second': 'whee'}
> 
> The function gets a dictionary, it can see which values were filled in
> (using kwargs.has_key or kwargs.keys(), for instance). It's flexible.
> 
> That's using **kwargs when you *define* a function. Since 2.0 it can also be
> used to pass in values. Say you have a function like
> 
> def two_arguments(first, second):
>    print "first =", first
>    print "second =", second
> 
> Now we know that the arguments are called first and second, and we've got
> some values for them in a dictionary:
> 
> dict = {
>    'first': 'silly party',
>    'second': 'very silly party'
>    }
> 
> Now, we can call the function using the dictionary, with
> >>> two_arguments(**dict)
> first = silly party
> second = very silly party
> 
> What that actually does is fill in the values from the dictionary, like
> two_arguments(first='silly party', second='very silly party')
> 
> So both when defining and calling a function, you can use the **arguments
> syntax to fake keyword arguments with a dictionary.
> 
> 
> (pause. you may reread that a few times. i think i laid out the reasoning
> sufficiently)
> 
> 
> There's a related syntax, with a single *. This is used for giving a
> function a variable number of arguments, that don't need their own names.
> 
> Say, we have some functions for adding numbers:
> 
> def add2(x,y): return x+y
> 
> def add3(x,y,z): return x+y+z
> 
> def add4(w,x,y,z): return w+x+y+z
> 
> Doesn't really look Pythonic, does it? We need a seperate function for every
> amount of numbers. In comes the * argument:
> 
> def add(*args):
>    sum = 0
>    for number in args:
>       sum += number
>    return sum
> 
> Now we can call it with as many numbers as we like!
> 
> >>> add(3,4,5,6)
> 18
> 
> The number are passed into the function as a tuple, and we can use a for
> loop to go through them. The other way around works as well, since Python 2.0;
> you can have any sequence, put a * in front and it passes them as individual
> arguments to the function:
> 
> >>> l = [1,2,3,4,5]
> >>> add(*l)
> 15
> >>> add(5, *l)
> 20
> >>> add(5, *l, 6)
>                ^
> SyntaxError: invalid syntax
> 
> Unfortunately, that one doesn't work. Any normal arguments must always come
> before the *args, and those must come before the **kwargs.
> 
> So if you want to make a function that takes a function as argument, plus
> any number of arguments and also keyword arguments, if any, and calls the
> function with it, you do it like this, in Python 2.0+:
> 
> def apply(f, *args, **kwargs):
>    return f(*args, **kwargs)
> 
> In older versions, you can't write this - but this apply() function is a
> builtin! And that's how you'd do it in older version, use apply().
> 
> >>> apply(add, (3,4,5))  # is equivalent to...
> 12
> >>> add(*(3,4,5))        # in newer versions.
> 
> Well, that was quite some text. Have to leave again now, hopefully someone
> else writes a tome on 'self' or otherwise I'll do that myself later tonight.
> 
> -- 
> Remco Gerlich
> 
> _______________________________________________
> Tutor maillist  -  Tutor@python.org
> http://mail.python.org/mailman/listinfo/tutor
-- 
Make laugh not war!