# Week 4, Wednesday: Functions, indefinite loops

Quiz 2 back, write answers in `cs21/examples/quiz2.py`

### using `import`

Libraries and modules are already-written python code you can use in your programs. Some, like `math` and `random`, come with python, but still need to be imported if you want to use them. Others, like `graphics`, which we will use next week, need to be downloaded from the web, then imported. We will also learn later how to write our own modules. This is another example of code reuse: why write code again if there is already a well-tested library or module you can use?

To use any common math functions, like `sqrt()`, `sin()`, `cos()`, or even constants like `pi`, you must first import the python math library:

``````>>> sqrt(16)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'sqrt' is not defined
>>> from math import *
>>> sqrt(16)
4.0
``````

Side Note: another way to import modules is just `import math`. If you do that, then you need to call any function in the `math` module with `math.` in front of the function:

``````>>> import math
>>> sqrt(16)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'sqrt' is not defined
>>> math.sqrt(16)
4.0
``````

You can import modules either way. In this class, we will probably always use the `from math import *` syntax. If you go out in the real world and write real programs, using `import math` is probably better...

### pseudo random numbers

Random numbers and picking things randomly (like from a list) can make our programs more interesting. Python has a library of functions dealing with random numbers and random choices. Two functions we often use are `randrange()` and `choice()`. Here are examples of each:

``````>>> from random import *
>>> randrange(1,11)
2
>>> randrange(1,11)
2
>>> randrange(1,11)
1
>>> randrange(1,11)
10
>>> randrange(1,11)
3

>>> names = ["jeff","carlo","zach","charlotte","lauri","andy"]
>>> choice(names)
'lauri'
>>> choice(names)
'zach'
>>> choice(names)
'carlo'
``````

`randrange()` is similar to `range()`, except it just chooses one number from the range of values. `choice()` picks randomly from a list or a string.

Here is a simple example that simulates flipping a 'coin':

``````>>> coin = ["heads","tails"]
>>> choice(coin)
>>> choice(coin)
'tails'
>>> choice(coin)
'tails'
``````

### indefinite (`while`) loops

Suppose we wanted to keep flipping a coin, until we got 3-in-a-row.

``````\$ python flip5heads.py
1. tails
2. tails
4. tails
6. tails
...
...
45. tails
``````

That time it took 50 flips. If I ran it again, it might take 7, or 96, or who knows how many... The point is, there is a loop in that program, but it is not a `for` loop, because we don't know ahead of time how many iterations are needed.

The syntax for the above loop is something like this:

``````inarow = 0
while inarow < 5:
flip coin
print results of flip
keep track of how many in a row (update inarow)
``````

This says, as long as `inarow` is less than 5, keep flipping the coin.

The official syntax for a while loop is:

``````while some_condition_is_true:
do this
and this
and this
``````

So the indented code block, which can be 1 or any number of lines, is executed if the condition is `True`. Then we go back to the top of the loop and see if the condition is still `True`. If it is, execute the code block again. If not, the loop is done.

``````\$ python whileloopgame.py
.......... (10)
char (u/d): u
........... (11) level UP
char (u/d): u
............ (12) level UP
char (u/d): d
........... (11) level down
char (u/d): d
.......... (10) level down
char (u/d): d
......... ( 9) level down
char (u/d): d
........ ( 8) level down
char (u/d): d
....... ( 7) level down
char (u/d): pony
The game starts at level 10. If the user enters `u`, go up a level. If they enter `d`, go down a level. Keep going until they get to level zero (not a very exciting game...I know!). And only accept `u` and `d` from the user. If you have time, add random insults. :)