diff --git a/advanced_topics/function_inputs_and_outputs.ipynb b/advanced_topics/function_inputs_and_outputs.ipynb index 335cb06842e88623183ecbf328f7736a3952e813..2306f9e16dfd572a37319684f830f5df1f748914 100644 --- a/advanced_topics/function_inputs_and_outputs.ipynb +++ b/advanced_topics/function_inputs_and_outputs.ipynb @@ -180,10 +180,66 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "> Pitfall: mutable argument values\n", - "\n", - "\n", - "You can see here that" + "__WARNING:__ _Never_ define a function with a mutable default value, such as a\n", + "`list`, `dict` or other non-primitive type. Let's see what happens when we do:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def badfunc(a=[]):\n", + " a.append('end of sequence')\n", + " output = ', '.join([str(elem) for elem in a])\n", + " print(output)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this function, all is well and good if we pass in our own value for `a`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "badfunc([1, 2, 3, 4])\n", + "badfunc([2, 4, 6])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But what happens when we let `badfunc` use the default value for `a`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "badfunc()\n", + "badfunc()\n", + "badfunc()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This happens because default argument values are created when the function is\n", + "defined, and will persist for the duration of your program. So in this\n", + "example, the default value for `a`, a Python `list`, gets created when\n", + "`badfunc` is defined, and hangs around for the lifetime of the `badfunc`\n", + "function!" ] } ], diff --git a/advanced_topics/function_inputs_and_outputs.md b/advanced_topics/function_inputs_and_outputs.md index 0a5ee9307a768298aa13369e301fa236458fa54c..5777da13c25c104419844245ff336042d92b7257 100644 --- a/advanced_topics/function_inputs_and_outputs.md +++ b/advanced_topics/function_inputs_and_outputs.md @@ -106,7 +106,39 @@ myfunc(c=300) ``` -> Pitfall: mutable argument values +__WARNING:__ _Never_ define a function with a mutable default value, such as a +`list`, `dict` or other non-primitive type. Let's see what happens when we do: -You can see here that +``` +def badfunc(a=[]): + a.append('end of sequence') + output = ', '.join([str(elem) for elem in a]) + print(output) +``` + + +With this function, all is well and good if we pass in our own value for `a`: + + +``` +badfunc([1, 2, 3, 4]) +badfunc([2, 4, 6]) +``` + + +But what happens when we let `badfunc` use the default value for `a`? + + +``` +badfunc() +badfunc() +badfunc() +``` + + +This happens because default argument values are created when the function is +defined, and will persist for the duration of your program. So in this +example, the default value for `a`, a Python `list`, gets created when +`badfunc` is defined, and hangs around for the lifetime of the `badfunc` +function! \ No newline at end of file