forked from ninas/umonya_notes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunctions.html
580 lines (473 loc) · 22.3 KB
/
functions.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Introductory Programming in Python: Flow Control: Functions</title>
<link rel='stylesheet' type='text/css' href='style.css' />
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
<script src="animation.js" type="text/javascript">
</script>
</head>
<body onload="animate_loop()">
<div class="page">
<h1>Introductory Programming in Python: Lesson 12<br />
Flow Control: Functions</h1>
<div class="centered">
[<a href="strings.html">Prev: Strings in Depth</a>] [<a href="index.html">Course Outline</a>] [<a href="problems.html">Next: Problem Solving Session</a>]
</div>
<h2>Abstracting Common Tasks with Functions</h2>
<p>So now we've been programming nearly two days, you've just started to come
across a number of tedious tasks that we must 'program repeatedly', as
opposed to 'program to repeat'; e.g. looping until a blank line is
entered. Often these common tasks are similar, but not exactly the
same, e.g. different things need to be done in the loop until a blank
line is reached. Ideally we want a labour saving device, and thus we
turn to the <a class="doclink" href=
'http://olympiad.cs.uct.ac.za/docs/python-docs-2.6/reference/compound_stmts.html#function'>function</a>. We have
already been introduced to the use of functions by calling various
built in functions, but ultimately we want to be able to make our own
functions.</p>
<h2>Defining New Functions</h2>
<p>We define a new function using the <strong>def statement</strong>,
which takes the form</p>
<pre class='definition'>
def <funcname>([parameter name][, parameter name][, ...]):
statement
[statement]
[...]
</pre>
<p>When this 'def' statement is executed, a new object with the name
'funcname' is created. Whenever this object is used followed by pair of
round braces, the statements listed in the 'def' statement, commonly
called the <strong>function definition</strong>, are executed, and once
completed, execution continues from where it was before the function
statements were entered. This process is known as <strong>calling a
function</strong>.</p>
<p>It is important to understand that functions provide us with a
radically different way to influence the sequence or flow in which our
programs execute. Conditions and loops still progress in a roughly top
to bottom fashion, but functions allow us to 'dive into' a small block
of statements, and come back up to where we were just prior to our
dive, more of an in and out form of control.</p>
<p>Of great use is that functions can return a value. In fact in
python, all functions return a value, even if not given a value to
return (in which case the return value is None). This is done by the
use of the <strong>return statement</strong>. The return statement,
when used within a function definition, simply causes that function to
return the value of the expression immediately following the 'return'.
Formally, return statements take the form</p>
<pre class='definition'>
return <expression>
</pre>
<p>As an example, here is the definition of a simple function to print
a triangle of height 3.</p>
<pre class='listing'>
def triangle3():
print "*"
print "**"
print "***"
</pre>
<p>Henceforth, whenever python encounters <code>triangle3()</code> the
three print statements will be executed. Note the brackets! They
indicate triangle3 should be called, rather than treated as a variable.
Looking at triangle three, there's nothing we couldn't do without cut
and paste, so why bother? Well recall that way back in the Basic Input
section we said that functions are like mini-programs, in that they
take input and produce output. Well that would mean a function would
produce different output depending on its input, but how do we give a
function input?</p>
<h2>Passing and Receiving Parameters by Position</h2>
<p>Functions receive their input from parameters, which are values
given in a comma separated list (i.e. a tuple) when calling the
function, and are unpacked within the function automatically. We have
to define how many parameters a function takes, and what each ones
names would be, so we can give a function appropriate parameters later
on. For example let's define a function that accepts one parameter,
called 'seconds' and returns how many complete minutes are in that many
seconds, and then call it...</p>
<pre class='listing'>
Python 2.6.4 (r264:75706, Dec 7 2009, 18:43:55) [MSC v.1310 32 bit (Intel)] on win32
[GCC 3.4.6 (Gentoo 3.4.6-r1, ssp-3.4.5-1.0, pie-8.7.9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def minutes(seconds):
... print seconds
... return seconds/60
...
>>> minutes
<function minutes at 0xb7cfcdbc>
>>> minutes(71)
71
1
>>> minutes(71.0)
71.0
1.1833333333333333
>>> minutes("bob")
bob
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in minutes
TypeError: unsupported operand type(s) for /: 'str' and 'int'
>>>
</pre>
<p>In the above example we can already see a number of things about
functions and how they handle parameters. Firstly, the 'def statement'
is executed and 'minutes' is created as a function 'object', as
evidenced by the value returned after typing in 'minutes'. Note however
when we call it by typing 'minutes(71)', instead python actually
executes the statements in the definition of the function 'minutes'.
The first statement in the definition prints out the value of seconds
as 71. But where did the value 71 come from?</p>
<p>Well, thinking back to tuples, let's treat everything between the
open and close brackets in a function call as if it were forming a
tuple, so in the case of the function call <code>minutes(71)</code> we
have formed a tuple '(71, )'. Before the first statement of the
function definition is executed, the tuple created by calling the
function is unpacked using the names in the function definition's
parameter list <strong>in order</strong>. In our case this creates an
implicit line before <code>print seconds</code> which looks like</p>
<pre class='listing'>
seconds, = 71,
</pre>
<p>Note in the example transcript how the type of the parameter
'seconds' changes according to the type of the value used in the
function. In fact in the third function call made, the type used
actually causes an error, which makes sense since we cannot divide a
string by an integer (60). In the error case, we see that the first
statement in the function definition (<code>print seconds</code>) is
executed without error, and that the error occurs later, meaning we are
able to differentiate where within a particular function execution
flows, and the functions are not treated as atomic.</p>
<p>The concepts of parameter passing are best illustrated in the case
of multiple parameters. For example, if we define a function which
takes two parameters, prints out both (solely for the purpose of
example), and returns the smaller of the two parameters ...</p>
<pre class='listing'>
>>> def minimum(a, b):
... print a
... print b
... if a < b:
... return a
... else:
... return b
...
>>> minimum(9, 3)
9
3
3
>>>
</pre>
<p>Okay, we're taking a few extra baby steps here... let's look at what
we've done. We've defined a new function called 'minimum', it has two
parameters, 'a' and 'b'. By virtue of putting <code>a, b</code> in the
parameter list in the function definition, we are implicitly putting
the line <code>a, b = <passed in tuple></code> in as the first
line, where the passed in tuple is formed by the function call itself,
rather than the function definition. Next we notice that we can branch
execution flow using an 'if statement' within a function definition. We
can also loop, in fact we can do pretty much anything we want within a
function definition. Finally let's focus on the 'return statement'.
Each return statement exits the function immediately, and replaces the
value of the function call with the value of the expression following
the reserved word 'return'. So following <code>minimum(9,3)</code> we
see that program execution 'dives into' the function 'minimum', sets
'a' and 'b' to 9 and 3 respectively via the implicit tuple unpacking,
prints 'a', prints 'b', and never executes <code>return a</code> but
instead executes <code>return b</code>, at which point execution leaves
the function definition, and returns (hence the name return) to the
point of the function call, and making the value of the function call
<em>3</em>.</p>
<h2>Composition of Functions in the Definition</h2>
<p>Of course, since we can do 'pretty much anything' in a function
definition, we can also call other functions, both python built in
functions, and our own defined ones, as in an example to get two
coordinates from the user.</p>
<pre class='listing'>
def getcoords():
x = raw_input("Enter an X coordinate: ")
y = raw_input("Enter a Y coordinate: ")
print "The smaller coordinate is %i" % ( minimum(int(x), int(y)) )
return x, y
</pre>
<p>So here we have called both a built in function (raw_input) and our
own previously defined function (minimum) within the function
definition. Also note that we form a tuple in our return statement. We
wish to return two values, but the 'return statement' can only return
the value of a singe expression, so to return multiple values, that
expression must be a tuple (or list) of values.</p>
<h2>Composition of Functions in Parameter Lists</h2>
<p>Just as expressions can be composed to form more complex expression,
so can functions be composed in the strict mathematical sense, i.e.
given two functions 'f(a)' and 'g(b)', we can obtain a value for f of g
of x. Similarly in python we could say,</p>
<pre class='listing'>
print minimum(5, minimum(int(raw_input("> ")), 8))
</pre>
<p>Remember that expressions are evaluated inside to outside, so the
value of raw_input is determined first, then it is converted to an
integer, then compared against 8 in the inner minimum function, and
finally the value of the inner minimum function is compared against 5
in the outer minimum function. Thus we have composed minimum with
itself, and further with raw_input.</p>
<p>In the same way that the range of 'g(b)' must fall within the domain
of 'f(a)', so too must we ensure in python when doing our function
compositions that the results of inner functions are of appropriate
type and value for use as parameters to outer functions.</p>
<!--<h2>Providing Default Values for Parameters</h2>
<p>Considering programming is all about being lazy and getting
computers to do the work for us, we find that entering every single
parameter every time we call a function gets tedious. Especially if 90%
of the time we are entering the same values. We want to be able to
specify a default value to assume when we feel lazy and want to leave
those parameters out. We do this by 'assigning' a default value when
specifying the parameter list in the function definition.</p>
<pre class='listing'>
#a simple function to change the radix (base) of a number, and return a string
#representing the number in the chosen radix
#this is most commonly used for hexadecimal notation, hence the default of 16
def radix(number, r = 16, case = "upper"):
upper = "0123456789ABCDEF"
lower = "0123456789abcdef"
if case == "upper":
digits = upper
else:
digits = lower
ret = ""
while number > 0:
ret = digits[number % r] + ret
number /= r
return ret
print radix(17)
print radix(255)
print radix(17,8)
print radix(17,2)
</pre>
<p>The example above produces the following output</p>
<pre class='listing'>
11
FF
21
10001
</pre>
<p>Deconstruction time! Note first how we define the parameter list of
the 'radix' function. We assign defaults. When we call 'radix' the
first time, we only provide one parameter, so during the implicit tuple
unpacking, we get the equivalent of <code>number, r, case = 17,</code>
which would be problematic because the right hand tuple is not big
enough. In this case python fills up the tuple as necessary with the
default values, yielding in fact <code>number, r, case = 17, 16,
"upper"</code>.</p>
<p>Looking at our third call of the 'radix' function, we have provided
two parameters, so python unpacks the tuple as <code>number, r, case =
17, 8,</code>, and fills up to the size required with default values,
so we get<br /> <code>number, r, case = 17, 8, "upper"</code>. Note how
the default values <strong>fill up their respective positions in the
tuple</strong>, and not from left to right, i.e. the first missing
parameter ('case') is filled up not with the first default parameter
(16), but rather the default for the parameter at the missing position
('upper'). Because passed in values are not associated by name to the
parameter names in the function definition, but rather by position, it
is imperative that we specify default values (thus allowing optional
parameters) <strong>after all mandatory parameters</strong>. Finally,
and obviously, if all the parameters are provided, no defaults are
used.</p>
<h2>Handling Keyword Arguments for Parameters</h2>
<p>There is one more way in which parameters can be passed. That being
by keyword. Python uses a very specific format for specifying the
passing of parameters by keyword,</p>
<pre class='definition'>
def <funcname>([parameter 1][, parameter 2][...][[,] **kwargs]):
statement
[statement]
[...]
</pre>
<p>Ending a parameter list in a function definition with the special
'expression' <code>**kwargs</code> (meaning key word arguments), means
that python will provide a dictionary inside function definition called
'kwargs', containing all the parameters passed in in keyword form. The
'**kwargs' can also be alone in the parameter list. Re-examining the
radix example we have</p>
<pre class='listing'>
#a simple function to change the radix (base) of a number, and return a string
#representing the number in the chosen radix
#this is most commonly used for hexadecimal notation, hence the default of 16
def radix(number, **kwargs):
upper = "0123456789ABCDEF"
lower = "0123456789abcdef"
if "radix" in kwargs:
r = kwargs["radix"]
else:
r = 16
digits = lower
if "case" in kwargs:
if kwargs["case"] == "upper":
digits = upper
ret = ""
while number > 0:
ret = digits[number % r] + ret
number /= r
return ret
print radix(17)
print radix(255, case = "upper")
print radix(17, radix = 8)
print radix(17, radix = 2)
print radix(17, case = "upper", radix = 12)
</pre>
<p>Which gives us the following output</p>
<pre class='listing'>
11
ff
21
10001
</pre>
<p>Using <code>**kwargs</code> allows us to call the function and name
the parameters we will assign values to explicitly, as opposed to
implicitly by position. But for the same reasons default parameters
must be specified after mandatory parameters, '**kwargs' must appear
after default parameters (if any), otherwise after mandatory
parameters.</p>
<h2>Functions as Variable Values</h2>
<p>As we have seen, we can refer to the function itself, as a value,
without calling it by using the name of the function without round
brackets and a parameter list. If we can refer to the function as a
value, then we can assign that value to variable. Then we can use the
variable to call the function. First a toy example for explanatory
purposes.</p>
<pre class='listing'>
#!/usr/bin/python
def plus(a, b):
return a + b
def prod(a, b):
return a * b
f = plus
f(4,5)
f = prod
f(4,5)
</pre>
<p>As we can see, we are able to assign a function to a variable;
<code>f = plus</code>. Next we see that we can call the function
<strong>currently</strong> assigned to 'f' by using the same call
syntax we would use with a function proper, namely using round braces
and a parameter list; <code>f(4,5)</code>. Note that assigning a
different function to 'f', and 'calling' 'f' again, we are in fact
calling the newly assigned function.</p>
<p>At first we might think this merely serves to confuse things, but
there is a use for the concept of <strong>function pointers</strong> as
they are called. Suppose we have a list, and we wish to apply a
function to every to every element in that list, such that we obtain a
new list containing the result of the function applied to the
respective element in the original list. We could create an empty list,
loop over the original list, and call the chosen function with each
element of the original list as a parameter, appending the results to
the new list. Now suppose we find that we perform this activity on a
regular basis, so regular a basis that we would want to make a function
to do this. The only problem is that the function we would want applied
to the list changes. Which means we can't hard code it into our
'application' function definition, but we must somehow accept the
function to apply as a parameter to our 'application' function. Using
function pointers we can do exactly this...</p>
<pre class='listing'>
#!/usr/bin/python
#a short program to demonstrate the use of function pointer
#we define a functions that 'applies' a function to each element in a list, and
#returns a list of the results of that function. Both the list and the function
#are specified as parameters
def apply(f, l):
ret = []
for e in l:
ret.append(f(e))
return ret
#imagine we had received four 'numbers' from raw_input calls, which means they
#are in fact strings
inputs = ["1", "2", "3", "4"]
#but we need them as integers
int_list = apply(int, inputs)
print int_list
#or perhaps even as floats
float_list = apply(float, inputs)
#or even converted to names of numbers
def nameofnum(n):
return ["one", "two", "three", "four", "five"][int(n)-1]
name_list = apply(nameofnum, inputs)
</pre>
<p>Try running this program and see what the output is.</p>-->
<h2>Exercises</h2>
<ol>
<li>Loops and conditionals both alter the flow of a program. Functions also alter the flow of a program, but in a different way. What is the difference?</li>
<!--<p>Given the code:</p>
<pre class='listing'>def suffix(m, s, chop = None):
if chop == None:
chop = -len(m)
return m[:-(chop)]+s
def prefix(m, p):
return p+m
s = "hand"
print suffix(s, "y")
print suffix("conceivable", "y", 1)
print prefix("conceivable", "in")
</pre>
<ol start='2'>
<li>How many parameters does each function take?</li>
<li>What is the value of the variable <em>s</em> outside of
<em>suffix</em>?</li>
<li>What is the value of the variable <em>s</em> inside of
<em>suffix</em>? How is this value assigned?</li>
<li>What is the value of the variable <em>s</em> inside of
<em>prefix</em>?</li>
<li>Compose the <em>suffix</em> and <em>prefix</em> functions using
parameter composition (i.e. traditional mathematical composition)
to create the word "inconceivably".</li>
<li>Rewrite either the <em>suffix</em> or the <em>prefix</em>
function as a defined composition of the other so that it returns a
word with both the prefix and the suffix concatenated.</li>
<li>Make the suffix parameter of your new function default to the
empty string, so that only prefixes need be specified if no suffix
is desired.</li>
<li>Make the prefix, suffix, and chop parameters keyword arguments
so that they can be specified in any order and all are
optional.</li>-->
<li>Write a function that computes the sum of squares of two
numbers.</li>
<li>Write a function that computes the sum of squares of two or
three numbers.</li>
<!--<li>Write a function that accepts a single integer parameter, and
returns True if the number is prime, otherwise False.</li>-->
<!--<li>Write a function that accepts a single integer parameter, and
returns a list of the prime numbers from 2 to the number.</li>-->
<!--<li>Write a function that accepts a single integer parameter, and
returns a list of the prime factors of that number.</li>-->
<!--<li>Write a function that accepts a list of numbers, and returns
their mean.</li>-->
<li>Write a function that accepts a list of numbers, and returns
the sum of their squares.</li>
<li>Write a program that asks the user for a space separated list
of data points (i.e. floating point numbers), then uses your
function from the previous question to output the sum of squares of
those numbers.</li>
<!--<li>Write a program that asks the user for a space separated list
of data points (i.e. floating point numbers), then uses appropriate
functions from previous questions to calculate and output the
standard deviation of those numbers.</li>-->
<!--<li>Write a function that accepts a list of numbers, a gradient and
an intercept, ala the linear function. Assume each number in the
list is a y value for the corresponding x value equal to the
numbers index position in the list, i.e. 0, 1, 2 etc... The
function should return the sum of squares of the residuals (the
difference between the data point or y value and the value of the
linear function at the corresponding x value).</li>-->
<!--<li>Write a program that asks the user for a space separated list
of data points, (i.e. floating point numbers), then output the
gradient and y intercept of the linear equation that best fits the
data, and the quantitative fit value for the proposed linear model.
Hint: Check the <a
href="http://en.wikipedia.org/wiki/Linear_least_squares">WikiPedia
article</a> on Least Squares Regression for formulae.</li>-->
</ol>
<div class="centered">
[<a href="strings.html">Prev: Strings in Depth</a>] [<a href="index.html">Course Outline</a>] [<a href="problems.html">Next: Problem Solving Session</a>]
</div>
</div>
<div class="pagefooter">
Copyright © James Dominy 2007-2008; Released under the <a href="http://www.gnu.org/copyleft/fdl.html">GNU Free Documentation License</a><br />
<a href="intropython.tar.gz">Download the tarball</a>
</div>
</body>
</html>