{python}

Introduction to Python - Lecture 4

Zohair ul Hasan

Recap

 

  • Boolean datatype
  • Comparison (==, >, <, etc) and Boolean (and, or, not) operators
  • Conditions
  • Code blocks
  • Control statements (if statement, while loop statement, for loop statement)
  • The range() function
  • Importing modules

Recap

Recap

Last week's tasks

My Rock Paper Scissors Solution

Today's Lecture

  • Functions
  • Exception Handling

Functions

  • We've seen Python built-in functions e.g. print(), input(), and len() 
  • Today we will explore how we can create our own "user defined" functions

Functions

A function is like a mini-program within a program

Functions

def hello():
    print('Howdy!')
    print('Howdy!!!')
    print('Hello there.')

hello()
hello()
hello()
Output:
  
Howdy!
Howdy!!!
Hello there.
Howdy!
Howdy!!!
Hello there.
Howdy!
Howdy!!!
Hello there.

Avoid this duplication

print('Howdy!')
print('Howdy!!!')
print('Hello there.')
print('Howdy!')
print('Howdy!!!')
print('Hello there.')
print('Howdy!')
print('Howdy!!!')
print('Hello there.')

Arguments

print("Hello World")

len("hi!")

Arguments

print("Hello World")

len("hi!")

Arguments

Creating a function that accepts arguments

def hello(name):
    print('Hello, ' + name)

hello('Alice')
hello('Bob')
Output:
  
Hello, Alice
Hello, Bob

Creating a function that accepts arguments

def hello(name):
    print('Hello, ' + name)

hello('Alice')
hello('Bob')
Output:
  
Hello, Alice
Hello, Bob

Arguments

Creating a function that accepts arguments

def hello(your_name):
    print('Hello, ' + your_name)

hello('Alice')
hello('Bob')
Output:
  
Hello, Alice
Hello, Bob

Parameter

Arguments

Parameters

Parameters are variables that store arguments.

Parameters

Variables defined in the function parameters are "forgotten" when the function returns. 

def hello(your_name):
    print('Hello, ' + your_name)

hello('Alice')
hello('Bob')
print(your_name)
Output:

Hello, Alice
Hello, Bob
Traceback (most recent call last):
  File "/Users/zohair/Projects/test/testing-debugger/test.py", line 6, in <module>
    print(name)
          ^^^^
NameError: name 'your_name' is not defined

Terminology: def, call, argument, parameter

def hello(your_name):
    print('Hello, ' + your_name)

hello('Alice')
hello('Bob')

Define statement (or function definition). Defines the hello function.

Terminology: def, call, argument, parameter

def hello(your_name):
    print('Hello, ' + your_name)

hello('Alice')
hello('Bob')

Define statement (or function definition). Defines the hello function.

Calls the created function

Terminology: def, call, argument, parameter

def hello(your_name):
    print('Hello, ' + your_name)

hello('Alice')
hello('Bob')

Define statement (or function definition). Defines the hello function.

Calls the created function

Value being passed to function is called an argument

Terminology: def, call, argument, parameter

def hello(your_name):
    print('Hello, ' + your_name)

hello('Alice')
hello('Bob')

Define statement (or function definition). Defines the hello function.

Calls the created function

Value being passed to function is called an argument

Variables that have an argument assigned to them are called parameters

Creating a function that accepts multiple arguments

def hello(name, day):
    print('Hello, ' + name + '. Today is ' + day + ".")

hello('Alice', 'Thursday')
hello('Bob', 'Friday')
Output:
  
Hello, Alice. Today is Thursday.
Hello, Bob. Today is Friday.

Return values

>>> len('hello!')
6

Value that a function call evaluates to is called the return value of the function

Return values

We can specify the return values of a function using the return statement

A return statement consists of the following:

  • The return keyword
  • The value or expression the function should return

Return values

If an expression is used with the return statement, the return value will be whatever the expression evaluates to

Return values

import random

def get_answer(answer_number):
    if answer_number == 1:
        return 'It is certain'
    elif answer_number == 2:
        return 'It is decidedly so'
    elif answer_number == 3:
        return 'Yes'
    elif answer_number == 4:
        return 'Reply hazy try again'
    elif answer_number == 5:
        return 'Ask again later'
    elif answer_number == 6:
        return 'Concentrate and ask again'
    elif answer_number == 7:
        return 'My reply is no'
    elif answer_number == 8:
        return 'Outlook not so good'
    elif answer_number == 9:
        return 'Very doubtful'

r = random.randint(1, 9)
fortune = get_answer(r)
print(fortune)

Return values can be directly passed as arguments to other functions

r = random.randint(1, 9)
fortune = getAnswer(r)
print(fortune)
print(getAnswer(random.randint(1, 9)))

Remember, expressions are composed of values and operators. A function call can be used in an expression because the call evaluates to its return value.

New Datatype - NoneType

There is a value called None, which represents the absence of a value

This value is the only value that exists for the NoneType datatype

New Datatype - NoneType

>>> type(None)
<class 'NoneType'>

New Datatype - NoneType

Just like the Boolean True and False values, None must be typed with a capital N

New Datatype - NoneType

None is helpful when you need to store something that won't be confused for a real value in a variable

New Datatype - NoneType

For example, None is the return value for print()

The print() function simply displays text on the screen, but does not need to return anything like len() or input() do

Since all function calls are required to resolve to a value, it returns None

New Datatype - NoneType

>>> spam = print("Hello!")
Hello!
>>> print(spam)
None

New Datatype - NoneType

By default, if a function doesn't have a return statement, Python adds a return None statement at the end of the function behind the scenes.

New Datatype - NoneType

Writing a return statement without a value or expression after it also returns None

Keyword Arguments

Usually arguments are identified by their position in the function call

random.randint(1, 20)

Keyword Arguments

Usually arguments are identified by their position in the function call

random.randint(1, 20)

Lower end of range

Higher end of range

Keyword Arguments

Keyword arguments are identified by the keyword put before them when calling the function instead of through their position

print("Hello", end='')

E.g.

Keyword Arguments

Keyword arguments are often used for optional parameters.

For example, the print() function has the optional parameters end and sep to specify what should be printed at the end of its arguments and between its arguments (separating them) respectively

Keyword Arguments

print('Hello')
print('World')
Output:
  
Hello
World

The print() function automatically adds a newline character to the end of the string it is passed

Keyword Arguments

However, you can set the end keyword argument to change the newline character to a different string

print('Hello', end='')
print('World')
Output:

HelloWorld

Keyword Arguments

Passing multiple arguments to the print() function will automatically separate them with a single space

>>> print('cats', 'dogs', 'mice')
cats dogs mice

Keyword Arguments

You can replace the default separating string by passing the sep keyword argument a different string

>>> print('cats', 'dogs', 'mice', sep=',')
cats,dogs,mice

Keyword Arguments

We can add keyword arguments to the functions we create as well, but we need to learn about lists and dictionaries before we can do so

The Call Stack

The Call Stack

Python will remember which line of code called the function so that the execution can return there when it encounters a return statement

If that original function called other functions, the execution would return to those function calls first, before returning from the original function call.

The Call Stack

def a():
    print('a() starts')
    b()
    d()
    print('a() returns')

def b():
    print('b() starts')
    c()
    print('b() returns')

def c():
    print('c() starts')
    print('c() returns')

def d():
    print('d() starts')
    print('d() returns')

a()
Output:

a() starts
b() starts
c() starts
c() returns
b() returns
d() starts
d() returns
a() returns

The Call Stack

The call stack is how Python remembers where to return the execution after each function call. The call stack isn’t stored in a variable in your program; rather, Python handles it behind the scenes. When your program calls a function, Python creates a frame object on the top of the call stack. Frame objects store the line number of the original function call so that Python can remember where to return. If another function call is made, Python puts another frame object on the call stack above the other one.

The Call Stack

When a function call returns, Python removes a frame object from the top of the stack and moves the execution to the line number stored in it. Note that frame objects are always added and removed from the top of the stack and not from any other place.

The top of the call stack is which function the execution is currently in. When the call stack is empty, the execution is on a line outside of all functions.

The Local and Global scope

Follow the activity at https://itp.zohair.dev/activities/local-and-global-scope to learn more about local and global scope

Exception Handling

Follow the activity at https://itp.zohair.dev/activities/exception-handling to learn more about exception handling

Zigzag

Follow the activity at https://itp.zohair.dev/activities/zigzag to practice the concepts we learned today.

Summary

  • Functions are the primary way to divide your code into logical groups
  • Code in one function cannot directly affect the values of variables in other functions
  • Functions can be thought of as "black boxes"
  • Exception handling (try-catch)

Homework

Please complete the homework at: https://itp.zohair.dev/homeworks/collatz-sequence