Default method arguments

Martin Miller ggrp1.20.martineau at dfgh.net
Thu Nov 17 15:29:10 EST 2005


Mike Meyer wrote, in part::
> "Gregory Petrosyan" <gregory.petrosyan at gmail.com> writes:
> ...
> > 2) Is 'foo.s = n' a correct solution? It seems to be a little more
> > elegant.  (I tested it, and it worked well)
>
> It's basically the same solution. You're replacing binding a variable
> with mutating an object bound to a name in an outer scope. In one case
> the container is named s and is a list that you're setting an element
> of. In the other case, the container is named foo and is an object
> that you're setting an attribute on.

Well, perhaps the same in the sense of name binding, but there's a
subtle difference in replacing the 's = [n]'  with 'foo.s = n'.  Namely
that in the former case (with the essay's original code) a separate
container is created when foo() is first called and is what is used in
subsequent calls to the function returned.  Whereas in the latter case
where the foo object itself is used as the container, there's only a
single container used by all returned objects -- which would cause
problems if you try accumulating two or more different totals
simultaneously.

Here's a very contrived test case which illustrates the point I'm
trying to make:

def foo(n):
    foo.s = n
    def bar(i):
         foo.s += i
         return foo.s
    return bar

a1 = foo(0)
a2 = foo(0)
print "before a1(0):", a1(0)
print "before a2(0):", a2(0)
a1(1)
a2(1)
print "after a1(0):", a1(0)
print "after a2(0):", a2(0)

>>>> outputs
before a1(0): 0
before a2(0): 0
after a1(0): 2
after a2(0): 2

Notice that it even though each was only incremented by 1 once, they
interacted, and show the effects of two calls.  This doesn't happen in
in Paul Graham's version, where the two 'after' calls would correctly
retrun a value of 1.

-Martin




More information about the Python-list mailing list