this is interesting

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

this is interesting

michel paul-2
>> def f(n, history = []):
  history.append(n)
  return history

>>> f(1)
[1]
>>> f(2)
[1, 2]
>>> f(3)
[1, 2, 3]
>>> f(2)
[1, 2, 3, 2]
>>> f(1)
[1, 2, 3, 2, 1]
>>> f(1,[])
[1]

A student wrote me wondering why his function wouldn't 'clear' after being called.  He meant to create an empty list and ended up with something like this.

What's a good way to explain what's going on?

- Michel



--
==================================
"What I cannot create, I do not understand."

- Richard Feynman
==================================
"Computer science is the new mathematics."

- Dr. Christos Papadimitriou
==================================


_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: this is interesting

Corey Richardson
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 06/08/2011 12:51 AM, michel paul wrote:

>>> def f(n, history = []):
>   history.append(n)
>   return history
>   [...]
> A student wrote me wondering why his function wouldn't 'clear' after being
> called.  He meant to create an empty list and ended up with something like
> this.
>
> What's a good way to explain what's going on?
>

It's a very, *very* common newbie mistake. When the function object is
created, the "history=[]" is evaluated and it refers to the same object
during each run of the function. The proper idiom is:

def f(n, history=None):
    if history is None:
        history = []
    # Do stuff

I probably explained that poorly but it's essentially what's going on.
- --
Corey Richardson
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (GNU/Linux)

iQEcBAEBAgAGBQJN7wF7AAoJEAFAbo/KNFvpm+cH/jd/7t3/ShChjwskEL/93pz0
qzIEm+ZhJX2+Y/4IQGznuxn7SFnhx9NpjG77zUCVGO0uscfks6b1MpcU+7LBuDcO
N2qaTbQsJf5oy83Y9CCjJr6KUcqZVcr0/2cA7dmFkAnAmizB5/q+N1KVI/KcCDcj
rdy9P/l4tVG/HmJjPgoNGQAcfZALL/5DmkHzf5evgy6aCttdDX3G6tjRneU4Vn9c
f7OE8A7t1/uyHLh6tV0S1F2skuJIig4BVXsvCuOCCXw/dPpqnwoTPrhbdOA085tJ
Payd/CrM2gZPRSnnOybVJSZGFR2rv9w+91iAsBGIYYCT3BEHMDvImFiNfLOZFus=
=dk4m
-----END PGP SIGNATURE-----
_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: this is interesting

Kirby Urner-6
In reply to this post by michel paul-2
On Tue, Jun 7, 2011 at 9:51 PM, michel paul <[hidden email]> wrote:
>> def f(n, history = []):
  history.append(n)
  return history

>>> f(1)
[1]
>>> f(2)
[1, 2]
>>> f(3)
[1, 2, 3]
>>> f(2)
[1, 2, 3, 2]
>>> f(1)
[1, 2, 3, 2, 1]
>>> f(1,[])
[1]

A student wrote me wondering why his function wouldn't 'clear' after being called.  He meant to create an empty list and ended up with something like this.

What's a good way to explain what's going on?

- Michel


Yeah good example.

I talk about the "function mouth" as likewise a "castle gate" where "guards" (the parameters) show up to take the values passed to them (as arguments).  

Some guards aren't met with a value and so go maybe over to this closet (of default objects) and haul out whatever they're supposed to work with by default.  

They might append to it (like your history above). 

Any time a value (object) comes in as an argument, they use that instead, but the thing in the closet is always there.

In a primitive way, functions get to have state between calls in this way, a hint that generators are to come, when the fish will finally walk upon land (generators evolve from functions in this story).

Kirby

 


--
==================================
"What I cannot create, I do not understand."

- Richard Feynman
==================================
"Computer science is the new mathematics."

- Dr. Christos Papadimitriou
==================================


_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig



_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: this is interesting

Laura Creighton-2
In reply to this post by michel paul-2
In a message of Tue, 07 Jun 2011 21:51:31 PDT, michel paul writes:

>>> def f(n, history = []):
>  history.append(n)
>  return history

<snip>

>
>What's a good way to explain what's going on?
>
>- Michel

Assuming that you have already taught about the difference between
mutable and immutable objects, ask the student to make a different
version, with the signature

def f2(n, history=())

and see if that gives the expected result.

Then get the student to _explain to you_ what's the difference between
tuples and lists that could result in this difference in behaviour.
This will move the discussion one of two ways.  Either to "why using
default values for mutable objects in function signatures is almost
never what you want to do, and a discussion of what we can do about
this (use sentinels)" :-) or "lists are a bad idea, use tuples for
everything" :-(.  If you are in conversation 2, you need to detour
through 'then why do we have a list datatype?  What is it good for?"

Laura
_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig