{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Function call\n",
"What happens if you call a function? A familiar example:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def square(L):\n",
" new_L = []\n",
" for i in L:\n",
" new_L.append(i*i)\n",
" return new_L\n",
"\n",
"numbers = [5, 1, 8]\n",
"squared_numbers = square(numbers)\n",
"\n",
"print numbers\n",
"print squared_numbers"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we make a new list out of the squared values of the original list.\n",
"\n",
"What happens if you square the elements in the original L
directly?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def square(L):\n",
" for i in range(len(L)):\n",
" L[i] = L[i] * L[i]\n",
" return L\n",
"\n",
"numbers = [5, 1, 8]\n",
"squared_numbers = square(numbers)\n",
"\n",
"print numbers\n",
"print squared_numbers"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The original numbers
list has changed also.\n",
"An other example:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def square(n):\n",
" n = n * n\n",
" return n\n",
"\n",
"number = 5\n",
"squared_number = square(number)\n",
"\n",
"print number\n",
"print squared_number"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now the original number is unchanged.\n",
"To understand this mechanism, we have to go deeper."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Value vs. reference\n",
"Some data types are stored as a concrete value, like int(5)
, float(3.14)
. They are the __primitive data types__.\n",
"\n",
"* `int`\n",
"* `bool`\n",
"* `float`\n",
"\n",
"Other data types are stored as a __reference to an actual memory location__.\n",
"* `list`\n",
"* `dict`\n",
"* `str`\n",
"* any other class\n",
"\n",
"In this case: `l = [1,2,3]` the variable `l` is a reference to the actual triplet of numbers."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Copy\n",
"All of this becomes interesting when you want to copy an object.\n",
"\n",
"If you make a copy of a primitive type, then a new number is created which is the copy of the original.\n",
"Modifying the copy does not effect the original one.\n",
"\n",
"If you copy of a reference, only the reference itself is copied and both the original and the new reference refer to the same thing. In this case modifying the copy modifies the original too.\n",
"\n",
"### Primitive"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"x = 5\n",
"y = x\n",
"y = 6\n",
"print x, y"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Reference"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L1 = [1, 5, 2]\n",
"L2 = L1\n",
"\n",
"L2.sort()\n",
"print L1\n",
"print L2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can force a copy of a list in this way:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = [1,2,3]\n",
"M = L[:]\n",
"M[1] = 9\n",
"print L\n",
"print M"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But it's more complicated in deeper structures. Here I only copy the outermost list, not the inner lists."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"M1 = [[1, 2], [3, 4]]\n",
"M2 = M1[:]\n",
"\n",
"M2[0][0] = 5\n",
"\n",
"print M1\n",
"print M2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"M1 = [[1, 2], [3, 4]]\n",
"M2 = M1[:]\n",
"\n",
"M2[0] = [5, 2]\n",
"\n",
"print M1\n",
"print M2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To copy this properly, you need to copy it recursively. But you have a function for that."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import copy\n",
"\n",
"M1 = [[1, 2], [3, 4]]\n",
"M2 = copy.deepcopy(M1)\n",
"\n",
"M2[0][0] = 5\n",
"\n",
"print M1\n",
"print M2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Pass argument by value\n",
"In python (and many other languages) the function gets a copy of its arguments.\n",
"\n",
"But this means different things in case of primitive and reference types.\n",
"\n",
"In the second `square` example the list `L` was a copy of a reference, therefore we were able to modify the original `numbers` also.\n",
"\n",
"In the third `square` example the `number` was a primitive type, so the copy `n` does not interfere with the original one.\n",
"\n",
"If you don't want to modify the original variables then it is a good practice to deepcopy them inside a function and modify the copies.\n",
"Or create a whole new variable like in the first `square` example."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Not that modifying the reference itself does not change the refered object, only that the reference will refer to some new object."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = [1,2,5]\n",
"def erase(L):\n",
" L = []\n",
" \n",
"erase(L)\n",
"print L"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This would be a correct erase:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def erase(L):\n",
" while len(L) > 0:\n",
" del L[0]\n",
"\n",
"erase(L)\n",
"print L"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is also a bit more tricky for immutable objects. Even if you get a reference to a string, the `str` type is immutable,\n",
"meaning that you cannot change its value, even if it is a reference."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def MakeCapital(s):\n",
" s[0] = s[0].upper() # it works neither inside a function nor outside\n",
"\n",
"a = \"abc\"\n",
"MakeCapital(a)\n",
"print a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Extra function arguments\n",
"\n",
"### Optional\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def passed(students, limit):\n",
" L = []\n",
" for name in students:\n",
" if students[name] >= limit:\n",
" L.append(name)\n",
" return L\n",
"\n",
"students = {'ABCDEF': 50, 'BATMAN': 23, '123ABC': 67}\n",
"print passed(students, 40)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can set the `limit` parameter to default `40`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def passed(students, limit=40):\n",
" L = []\n",
" for name in students:\n",
" if students[name] >= limit:\n",
" L.append(name)\n",
" return L\n",
"\n",
"students = {'ABCDEF': 50, 'BATMAN': 23, '123ABC': 67}\n",
"print passed(students)\n",
"print passed(students, 60)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can specify more optional parameters but only from the right."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def passed(students, limit=40, sort=True):\n",
" L = []\n",
" for name in students:\n",
" if students[name] >= limit:\n",
" L.append(name)\n",
" if sort:\n",
" return sorted(L)\n",
" else:\n",
" return L\n",
"\n",
"students = {'ABCDEF': 50, 'BATMAN': 23, '123ABC': 67}\n",
"print passed(students)\n",
"print passed(students, 40, False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The following is wrong, because you set the `limit` to `False` not the `sort` parameter."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print passed(students, False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Pass parameter by name\n",
"\n",
"You can substitute the optional parameters by name, not only by place."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print passed(students, sort=False)\n",
"print passed(students, sort=False, limit=40)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print \"P({x}, {y})\".format(y=3, x=4)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Variadic function\n",
"\n",
"Lets take a function that multiples numbers."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def product(L):\n",
" result = 1\n",
" for i in L:\n",
" result *= i\n",
" return result\n",
"\n",
"print product([1,2,3])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can make a multi-variate function instead of a function with one list parameter. You can call this function with either 0,1,2 or 3 parameters."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def product2(x=1, y=1, z=1):\n",
" return x*y*z\n",
"\n",
"print product2()\n",
"print product2(1)\n",
"print product2(1, 2)\n",
"print product2(1, 2, 3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Instead, you can make a function with __arbitrary many parameters__. [variadic function](https://en.wikipedia.org/wiki/Variadic_function)\n",
"\n",
"See that the only difference is the *
"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def product3(*L):\n",
" result = 1\n",
" for i in L:\n",
" result *= i\n",
" return result\n",
"\n",
"print product3(1,2,3)\n",
"print product3(1, 2, 3, 4, 5, 6)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this case the parameters are copied into a tuple, that can be any long."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def variadic(*x):\n",
" return type(x)\n",
"\n",
"print variadic(3,2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Calling a variadic function\n",
"Let's say you have a list but you wanto to multiply them with a variadic function.\n",
"\n",
"This is not correct:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = [1, 2, 3]\n",
"print product3(L)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Correct\n",
"print product3(*L)\n",
"\n",
"# equivalent to this\n",
"print product3(L[0], L[1], L[2])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Scope\n",
"wikipedia\n",
"\n",
"There can be more than one variable with the same name, but it matters where."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def function(L):\n",
" # i is different\n",
" for i in L:\n",
" if i <> 0:\n",
" return True\n",
" return False\n",
"i = [0, 1, -1]\n",
"print function(i)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def something(L):\n",
" # i is mixed up\n",
" i = 0\n",
" for i in L:\n",
" i = i+i\n",
" return i\n",
"print something([1, 2, 3])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def something2(L):\n",
" i = 0\n",
" for j in L:\n",
" i = i+j\n",
" return i\n",
"\n",
"# i is unchanged outside of the function\n",
"i = 10\n",
"print something2([1, 2, 3])\n",
"print i"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A variable defined inside a function is __local to that function__ and does not interfere with the same named variable outside of the function.\n",
"\n",
"If you call that function many times, the values between runs are not connected in any way.\n",
"\n",
"If you define a variable outside of any function, then it can be seen anywhere in the code: __global__."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"i = 10\n",
"def f(x):\n",
" # i = 0 # this would create a local i\n",
" print i\n",
" \n",
"f(None)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Mind that an if
branch can introduce a variable and some variables can be present in some cases and undefined in other cases."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def f(x):\n",
" if x:\n",
" i = 0\n",
" return i\n",
" \n",
"print f(True)\n",
"print f(False)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.15"
}
},
"nbformat": 4,
"nbformat_minor": 1
}