*Scope of variables* means the parts of code where a particular variable
is accessible. When you were writing a single program this was simple,
but as you start to use functions and `main()` you need to start to think.
## All Local Variables
> ### Key Point
If you define **all** your variables inside functions then the rule is
simple
- Variables are local to the function in which they are defined.
So if we take the example below which forms a list of numbers and then
uses function `add_values()` to sum them up.
```python
defadd_values(values):
x=0.0# Local variable
foryinvalues:#Sum up values in list
x+=y
returnx# return local value
defmain():
v=[]# make list of numbers
foriinrange(0,10):
x=5.0*i
v.append(x)
x=add_values(v)# Sum up with function
print("Sum of values is : "+str(x))# Print
main()
```
- The `x` used in `add_values()` is local to that function, it is used to hold the sum of the elements of the list and its **value** is returned in line 5
- The `x` used (twice) in `main()` is a *completely separate* to the same named variable in `add_values()`, and in particular it is located in a different location in computer memory, so the value of one does *not* affect the other.
> ### Key Point
Use of local variables is the recommended programming style, it
- Makes each function separate and removes inter-dependancies
- Allows each function to operate independently of others, so easier
to reuse in other applications.
- Easier to test and debug each function seperately.
> **Note: functions have *no memory* from any previous call, so all local variables get re-created every time the function is called.**
## Global Variables
When variables are declared outside functions, including outside `main()` they become *global*, so
```python
wave=6.5# Declare outside main or fucntion
defbright(x):
val=x*wave# Can access global variable wave
returnval
defmain():
v=bright(15.0)
print("value of bright is : "+str(v)+" and can also access wave "+str(wave))
```
- In Line 1, `wave` is a global float variable declared outside any function.
- In Line 4 and 9 the value of `wave` is accessible. It is also accesible from *any* other function declared within this file.
>> Here is a longer example of using a global variable
In this case `wavelength` is visible within both `main()` and the function `planck()`.
> ### Key Point: Rules
>The rules for global variables are:
>- The global variable must be decared before any function it is used
in, so typically at the top of the file.
>- It is visible from all functions declared within the file.
>- The value of a global **cannot** be changed from within any function
or `main()`, so it is “*Read Only*”.
> Global variables look *like a good thing*, but they should be used with *extreme care* and only when you want to set a *global default* across a set of functions.
## Changing Globals
The default operation of globals is that they are *read only* within
each function, but you can override this by the use of the `global` keyword as shown below.
```python
wave=6.5# Declare outside main or funtion
defbright(x):
val=x*wave# Can access global variable wave
returnval
defmain():
globalwave# make wave writable fron within main
v=bright(15.0)
print("value of bright is : "+str(v)+" and can also access wave "+str(wave))
wave=25.0# Update global variable
v=bright(15.0)
print("value of bright is : "+str(v)+" and can also access wave with new value "+str(wave))
```
So here in line 8 we have declared that `wave` is a writable global in `main()`, so when we update it in line 12 the value seen by function `bright()` also changes.
> ### Wrong
Using `global` to make global variables writable within functions is *very dangerous*; it leads to totally unmaintanable code and should only be used when you really understand what you are doing.
> WARNING: Having lists in global is a recipe for disaster, there are all sorts of horrible and none obvious consequences; how it works is logical, but typically not what you want; just “don’t do it”.
"In computing languages there are *three* styles to\n",
"designate the start and end of code blocks, these being\n",
"1. *brackets*, in C and Java style languages,\n",
"2. *keywords* in Fortran and Shell scripts.\n",
"3. *indentation* in Python.\n",
">In computing languages there are *three* styles to designate the start and end of code blocks, these being:\n",
">1. *brackets*, in C and Java style languages,\n",
">2. *keywords* in Fortran and Shell scripts.\n",
">3. *indentation* in Python.\n",
"\n",
"> So in most languages *indentation* of code blocks is *good style* but\n",
"not essential. However (uniquely?) in the start and end of blocks are\n",
...
...
@@ -162,17 +161,17 @@
"- Add careful comments explaining what you are doing.\n",
"\n",
">**Example Code:**\n",
"- One way example:\n",
"- Two way example:\n",
"- Three way example:\n",
"- Which quadrant is a complex number in :\n",
"- Is point inside sphere using a function :\n",
">- [One way example](../CodeExamples/OneWayConditional.ipynb)\n",
">- [Two way example](../CodeExamples/TwoWayConditional.ipynb)\n",
">- [Three way example](../CodeExamples/ThreeWayConditional.ipynb)\n",
">- [Which quadrant is a complex number in](../CodeExamples/ComplexQuadrant.ipynb)\n",
">- [Is point inside circle using a function](../CodeExamples/PointsInCircle.ipynb)\n",
"> Download these and \"play\" with them; in particular change in indentation\n",
"and see what type of \"crashes\" you get.\n",
"\n",
">> Once you have practiced and understood the `if : elif: else:` syntax you have completed\n",
"enough to attempt [Checkpoint 2](../Checkpoints/Checkpoint2.ipynb)\n",
"Note, Checkpoint is much more tricky than it looks, read in instuctions\n",
"Note, Checkpoint 2 is much more tricky than it looks, read in instructions\n",
"and the **Hint** and plan out all the conditions that your program has\n",
"to deal with."
]
...
...
%% Cell type:markdown id: tags:
# Conditional Statements
In order to start making a computer program do more than simple
pre-determined calculations we have to introduce the idea of conditional
statements. These make the execution path though the code depend on the
values of the variables. This is called *Flow Control* and is the first
real step in *programming*.
> **This section introduces multiple new concepts and syntax, take
your time and study it carefully.**
## The `if-else` structure
The simplest conditional structure is the `if - else`, to see this consider the
section of code below, where `a` is a float variable that has already been
set:
```python
<codetoseta>
ifa>0:
b=4.0+math.sqrt(a)
a=2.0*(b+1.0)
else:
b=4.0-3.0*math.sqrt(-a)
a=7.0*(b-3.0)
print("The value of a is : "+str(a)+" and b is : "+str(b))
```
There is a considerable amount of new syntax here; read through this
very carefully.
- Line 1: Sets the value of `a`, which may be positive or negative.
- Line 2: Start of the `if` with logical statement `a > 0` which will be `True` or `False`.
**Note** the `:` which is an essential part of the syntax.
- Lines 3 & 4: These two lines are executed only if `a > 0`.
**Note** these lines *must* be indented by exactly 4 spaces.
- Line 5: Start of the `else` code.
**Note** the `:` and also the `else`*must* be aligned with the `if`.
- Lines 6 & 7: These two lines are executed only if `a > 0` is `False`.
**Note** again they *must* be indented by exactly 4 spaces.
- Line 8: Execution continues here *after* the `if: else:` structure.
**Note** this line *must* be aligned with the `if` and the `else`.
### Key Point
As you can see, correct indentation in `Python` is *essential* - it
is part of the syntax of the language.
The editor will allow you to use `<tab>` key to do the indentation but you
absolutely *must* get the right every time. There is no margin for
error!
> #### More on indentation
In computing languages there are *three* styles to
designate the start and end of code blocks, these being
1.*brackets*, in C and Java style languages,
2.*keywords* in Fortran and Shell scripts.
3.*indentation* in Python.
>In computing languages there are *three* styles to designate the start and end of code blocks, these being:
>1. *brackets*, in C and Java style languages,
>2. *keywords* in Fortran and Shell scripts.
>3. *indentation* in Python.
> So in most languages *indentation* of code blocks is *good style* but
not essential. However (uniquely?) in the start and end of blocks are
designated by *indentation* only; it is part of the syntax of . This
makes code short and concise, but it does mean you *must* get the
indentation absolutely right!
> Failing to do this is the biggest source of (some very interesting)
bugs!
The conditional statement, the `a > 0` above, can be any logical statement that you can build up using `and`, `or` and `not`; you will learn more about this later.
## The `if-elif-else` structure
There is a more complete and useful `if-elif-else` construction that you will often use in programming, look at the following example,
```python
<codetoseta>
ifa>4.0:
b=4.0-math.sqrt(a)
a=2.0*(b-3.0)
elifa>0:
b=1.0+math.sqrt(a)
a=(b-1.0)
else:
b=4.0-3.0*math.sqrt(-a)
a=7.0*(b-3.0)
print("The value of a is : "+str(a)+" and b is : "+str(b))
```
Looking at this is detail we have:
- Line 2: Changes the conditional on line 2 so that lines 3 & 4 will
only be executed if $a > 4$.
- Line 5: Introduces a new statement `elif` (short for *else if*) with an
additional condition that $a > 0$ and if `True` lines 6 & 7 will be executed.
- Line 8: The `else` catches *all other cases*, so here Lines 8 & 9 will be
executed when $a \leq 0$.
### Key Point
Here it is essential to note that:
- only **one** of the indented blocks of code will be executed, and
- this will be determined at the execution of the initial `if` statement.
This looks a more complex piece of code but it will become one of the
most common constructs you will use in programs.
## Nested if : else
You can nest `if: elif: else:` blocks to any depth you like, so for example you can have:
```python
<codetoseta>
<codetosetb>
ifa>0:
ifb>0:
val=math.sqrt(b/a)
else:val=math.sqrt(-b/a)
else:
ifb>-10:
val=math.sqrt(-a/(b+11.0))
else:val=float("nan")
print("Val is : "+str(val))
```
Here:
- Line 3: Tests on variable `a`. The execution thread will jump *either*
to Line 4 *or* to Line 9.
- Lines 4 to 7: Will be executed only if the test on Line 3 is `True`.
Either Line 5 or Line 7 will be executed depending on the test on
Line 4.
- Lines 9 to 12: Will be executed only if the test on Line 3 is `False`.
Either Line 10 or Line 12 will be executed depending on the test on
Line 9.
- Line 13: Will print out the final value of `val` .
Note here the indentation; Lines 4, 6, 9 and 11 *must* be indented by 4
spaces while lines 5, 7, 10 and 12 *must* be indented by 8 spaces.
### Key Point
You can nest `if: elif: else:` to any *depth*, **but** such complex structure are
difficult to write and even more difficult to debug.
The general rule is:
- Do not nest deeper than two levels - if you find you have to,
consider using *functions* to break up the code (see later in
course).
- Add careful comments explaining what you are doing.
>**Example Code:**
- One way example:
- Two way example:
- Three way example:
- Which quadrant is a complex number in :
- Is point inside sphere using a function :
>- [One way example](../CodeExamples/OneWayConditional.ipynb)
>- [Two way example](../CodeExamples/TwoWayConditional.ipynb)
>- [Three way example](../CodeExamples/ThreeWayConditional.ipynb)
>- [Which quadrant is a complex number in](../CodeExamples/ComplexQuadrant.ipynb)
>- [Is point inside circle using a function](../CodeExamples/PointsInCircle.ipynb)
> Download these and "play" with them; in particular change in indentation
and see what type of "crashes" you get.
>> Once you have practiced and understood the `if : elif: else:` syntax you have completed
enough to attempt [Checkpoint 2](../Checkpoints/Checkpoint2.ipynb)
Note, Checkpoint is much more tricky than it looks, read in instuctions
Note, Checkpoint 2 is much more tricky than it looks, read in instructions
and the **Hint** and plan out all the conditions that your program has