0% found this document useful (0 votes)
2 views

le3_functions_and_exceptions

Uploaded by

valer93979
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

le3_functions_and_exceptions

Uploaded by

valer93979
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

The continue and break statements

When working with for and while loops, there may be cases where the programmer would like to stop the loop before the loop's condition evaluates to false (in the case of while loops) or before the elements in
the iterable are exhausted (in the case of for loops). To do this, we use the break statement

In [ ]: # Program to print 1-10


i = 1
while i <= 10:
print(i)
i += 1

1
2
3
4
5
6
7
8
9
10

In [ ]: # We can make the program stop immediately after printing 5


i = 1
while i <= 10:
print(i)
if i == 5:
break
i += 1

1
2
3
4
5

Problem

Write a program that generates a random number between 0-100 and asks the user guess the number. Each time telling the user whether their guess was greater than or less than the generated number or whether it's
correct. If the user makes 8 wrong guesses, he loses and the game ends.

In some cases we might want to skip the execution of our loop's body for certain values, for such cases we use the continue statement. Anytime a continue statement is encountered in a loop, Python moves to
the next iteration of the loop without executing any code left in the body of the loop:

In [ ]: # Print every number between 1-10 except 7


for num in range(1,11):
if num == 7:
# When number is equal to 7 skip the remaining lines of code and start
# the next iteration (i=8)
continue
print(num)
1
2
3
4
5
6
8
9
10

Functions
Functions are a convenient way to divide our code into useful blocks, allowing us to order our code, make it more readable, and reuse it.

We have seen several builtin function in this course already: print() , len() , range() , etc. Packaging code as a function allows us to execute it from various locations in our program just by calling the function,
rather than duplicating the block of code in multiple places in our code.

Defining a function
We can also define our own functions in Python. Here is an example of a function:

In [ ]: def square(number):
"""Calculate the square of number.

Args:
number: The value to be squared.

Returns:
result: The square of argument `number`.
"""
result = number ** 2
return result

In [ ]: # We can then use our function


print(square(5))
print(square(9))

25
81
A function definition

• begins with the def keyword,


• followed by the function name,
• a set of parentheses
• a colon (:)
• body of the function (which must be indented)

The function name is an identifier, and so all the naming conventions discussed previously about identifiers applies.

The set of parentheses contain the function's parameter list - a comma-separated sequence of parameters representing the data that the function needs to perform its task. Function square above only has
one parameter named number - the value to be squared.

When a function finishes executing, it returns control to its caller - that is, the line of code that called the function. If a return statement is defined in the function, the value the statement returns is passed on to the
caller. If no return statement is defined in the function, a value of None is returned. In the case of the square function, the square of the argument number is returned by the function.

A function without a return statement will implicitly return None .

In Python, None is used to represent the absence of a value. It evaluates to False in conditional statements.

It is possible to create functions with default argument values:

A function can also have multiple arguments:

In [ ]: def volume_cylinder(length, width, height):


"""Calculate the volume of the cylinder with dimensions `length`, `width`, and `height`."""
return length * width * height

In [ ]: from math import pi


def volume_cylinder(radius, height):
"""Calculate the volume of the cylinder with radius `radius` and height `height`"""
volume = pi * radius**2 * height
return volume

To call a function properly, it is important to pass in the arguments in the order they appear in the function definition. For example, to calculate the volume of a cylinder with radius=2.4cm and height=10cm. The
dimensions of the cylinder must be passed in the specific order the function expects: volume_cylinder(2.4, 10) . Passing the arguments in a different order will produce a different result.
volume_cylinder(10, 2.4) will produce the volume of a cylinder with radius=10 and height=2.4.

To avoid this pitfall, it is also possible to use the argument names in calling statement of the function: volume_cylinder(radius=2.4, height=10) will yield the same result as
volume_cylinder(height=10, radius=2.4) because we are specifying which value is the height and which is the radius in our function calls.

In [ ]: # The volume of a cylinder with radius=2.4 & height=10


volume = volume_cylinder(2.4, 10) # Correct
print(f"The volume of the cylinder is {volume:.2f}")

volume = volume_cylinder(10, 2.4) # Incorrect


print(f"The volume of the cylinder is {volume:.2f}")

volume = volume_cylinder(radius=2.4, height=10) # Correct


print(f"The volume of the cylinder is {volume:.2f}")

volume = volume_cylinder(height=10, radius=2.4) # Correct


print(f"The volume of the cylinder is {volume:.2f}")
The volume of the cylinder is 180.96
The volume of the cylinder is 753.98
The volume of the cylinder is 180.96
The volume of the cylinder is 180.96

A function can also take an arbitrary number of arguments. For example, we can modify function find_maximum to take as many arguments as the user wants. This is typically useful when the order of the arguments
does not matter:

In [ ]: def find_maximum(*numbers):
"""Return the highest number between number_1, number_2, number_3."""
result = None
for num in numbers:
if (result is None) or (num > result):
result = num
return result

Keyword argument and positional arguments


For functions like find_maximum above, the arguments of the function can be passed in any other of the caller's choice. This means that find_maximum(1, 3, 5) will yield the same result as
find_maximum(5, 1, 3) .

In [ ]: import random
help(random.randint)

Help on method randint in module random:

randint(a, b) method of random.Random instance


Return random integer in range [a, b], including both end points.

Variable scopes
It is important to discuss the reachability of python variables. A variable is only available from within the region it is created. Variables created inside functions belong to the local scope of that function, and can only be
used inside that function. Such functions are sometimes referred to as local variables.

In [ ]: def our_function():
var_inside_our_func = 50
print(var_inside_our_func) # This will print out 50

print(var_inside_out_func) # This will raise a NameError exception

---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_6222/2394188547.py in <module>
3 print(var_inside_our_func) # This will print out 50
4
----> 5 print(var_inside_out_func) # This will raise a NameError exception

NameError: name 'var_inside_out_func' is not defined

In the example above, variable var_inside_out_func is only available from within the function our_func . Trying to reference the variable outside the function will cause a NameError exception.

Global Variable
A variable created in the main body of the Python code is referred to as a global variable. Global variables are available from within any scope, global and local.
In [ ]: # A variable created outside of a function or class is global and
# can be used by anyone:
var_global = 300

def new_function():
print(f"From inside function `new_function`: {var_global}")

new_function() # Prints out the value of var_global

# Also prints out the value of var_global


print(f"From the outer scope of the code: {var_global}")

From inside function `new_function`: 300


From the outer scope of the code: 300

Important notice
If you attempt to modify the var_global variable from within a function or a class, Python will treat it as a different variable from the var_global defined at the top of the piece of code:

In [ ]: var_global = 300 # global variable

def newest_function():
var_global = 150 # Just a local variable that belongs to this function

print(f"From inside function `newest_function`: {var_global}")

newest_function()

# The value of the global variable remains unchanged


print(f"From the outer scope of the code: {var_global}")

From inside function `newest_function`: 150


From the outer scope of the code: 300

If you need to modify the global variable from within the scope of a function, you must use the global keyword to make this possible

In [ ]: var_global = 300 # global variable

def newest_function():
global var_global
var_global = 150 # Modifies the value of the global variable from inside a function

print(f"From inside function `newest_function`: {var_global}")

newest_function()

# The value of the global variable remains unchanged


print(f"From the outer scope of the code: {var_global}")

From inside function `newest_function`: 150


From the outer scope of the code: 150
Errors and Exceptions
There are two categories of errors in Python: syntax errors and exceptions.

Syntax Errors
Syntax errors occur when an invalid line code is present in code being executed by the interpreter.

In [ ]: score = 70
if score >= 70 print("A")

File "/tmp/ipykernel_11536/3086719611.py", line 2


if score >= 70 print("A")
^
SyntaxError: invalid syntax

Exceptions
Even if the statement or expression is syntactically correct, it may cause an error when an attempt is made to execute it. Errors detected during execution are called exceptions. There are many issues that could lead to
exceptions in a program's execution. Most common is if the program is used in an unexpected way. Let's say we have a function that accepts two numbers a and b and returns the result of dividing a by b :

In [ ]: def divide(*, a, b):


"Divide a by b."
return a / b

The function will raise an exception when we set b to be zero:

In [ ]: divide(a=90, b=0)

---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
/tmp/ipykernel_11536/2015877406.py in <module>
----> 1 divide(a=90, b=0)

/tmp/ipykernel_11536/3979253694.py in divide(a, b)
1 def divide(*, a, b):
2 "Divide a by b."
----> 3 return a / b

ZeroDivisionError: division by zero

If we attempt to pass an invalid value to the argument of the function, say a string, we will also get an exception:

In [ ]: divide(a='ab', b=2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/tmp/ipykernel_11536/1540736037.py in <module>
----> 1 divide(a='ab', b=2)

/tmp/ipykernel_11536/3979253694.py in divide(a, b)
1 def divide(*, a, b):
2 "Divide a by b."
----> 3 return a / b

TypeError: unsupported operand type(s) for /: 'str' and 'int'

The last line of the error message will always give an explanation of what went wrong. Exceptions come in different types, and the type is printed as part of the error message: the types in the examples above are
ZeroDivisionError and TypeError .

Handling Exceptions
We can anticipate common exceptions that may occur when users are trying to use our program when we are designing the program. We could use try-catch blocks to catch the common exceptions our divide
function may encounter while in use:

In [ ]: def divide(*, a, b):


try:
result = a / b
except ZeroDivisionError:
print("Division by zero is not allowed")
return result

The try statement works as follows:

• First, the try clause (the statement(s) between the try and except keywords) is exected.
• If no exception occurs, the except clause is skipped and exection of hte try statement is finished.
• If an exception occurs during execution of the try clause, the rest of the clause is skipped. Then, if its type matches the exception named after the except keyword, the except clause is executed, and then
execution continues after the try/except block.
• If an exception occurs which does not match the exception named in the except clause, it is passed on to outer try statements; if no handler is an unhandled exception and execution stops with a message as shown
above.

Another example

Assuming we have an input statement that requires a user to enter a number, we could add an exception block to keep requesting an input from the user until a number is entered:

In [ ]: while True:
try:
x = int(input("Please enter a number: "))
break
except ValueError:
print("You are required to enter a number. Please try again...")
print(f"Finally, you entered {x}")

You are required to enter a number. Please try again...


You are required to enter a number. Please try again...
You are required to enter a number. Please try again...
You are required to enter a number. Please try again...
Finally, you entered 45
Useful commands for Python development
Note: A module is a file containing a set of functions and/or classes we can include in our applications.

We can re-use a module in another module by using the import statement. For example, we have used functions in the math module that come with every python installation by calling import math .

After import the math module, we might want to find out the functions that are available within the module. To find out, we can use the dir() function:

In [ ]: import math # Importing the math module

display(dir(math)) # List out all the functions/classes available within the module
['__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'acos',
'acosh',
'asin',
'asinh',
'atan',
'atan2',
'atanh',
'ceil',
'comb',
'copysign',
'cos',
'cosh',
'degrees',
'dist',
'e',
'erf',
'erfc',
'exp',
'expm1',
'fabs',
'factorial',
'floor',
'fmod',
'frexp',
'fsum',
'gamma',
'gcd',
'hypot',
'inf',
'isclose',
'isfinite',
'isinf',
'isnan',
'isqrt',
'lcm',
'ldexp',
'lgamma',
'log',
'log10',
'log1p',
'log2',
'modf',
'nan',
'nextafter',
'perm',
'pi',
'pow',
'prod',
'radians',
'remainder',
'sin',
'sinh',
'sqrt',
'tan',
'tanh',
'tau',
'trunc',
'ulp']

You can ignore the function/classes that begin with and end with underscores as they have a special meaning in Python.

We can get instructions on how to use the functions and classes within an imported module by calling the builtin help() function:

In [ ]: import math

display(help(math.cos))
print()
display(help(math.radians))

Help on built-in function cos in module math:

cos(x, /)
Return the cosine of x (measured in radians).

None
Help on built-in function radians in module math:

radians(x, /)
Convert angle x from degrees to radians.

None

From using the help function, we can see that we can find the cosine of an angle x which is in radians by calling the math.cos function.

In [ ]: math.cos(math.radians(60))

Out[ ]: 0.5000000000000001

You might also like