Lecture 5
More Functions and Objects
CS1302 Introduction to Computer Programming
Global variables
How can different functions work on the same variable?
- Why use global in the first 2 functions but not the last?
- A local variable must be defined within a function, and so...
- An assignment defines a local variable unless global is used, and so...
What happens with global declarations removed?
count = count + 1count += 1Hint:
Issues with global variables
Functions with global variables are dependent.
Functional independence
With global variables,
- codes are less predictable, more difficult to reuse/extend, and
- tests cannot be isolated, making debugging difficult.
To ensure functional independence, define pure functions which
- return the same value for the same arguments, and
- have no observable side effects including input/output.
Default parameters
Can we call a function without specifying all its arguments?
- step is a default parameter.
- start and stop are non-default parameters.
Can we set start=1 as a default parameter instead of stop=5?
- Default parameters must follow non-default parameters. Why?
- How can range sets the default for start but not stop? Hint.
- Default parameters are filled from back to front.
- We can specify argument when calling a function.
Can we set multiple default parameter?
Recursion
Can we define a function using the function itself?
What does the function compute?
- \(f(n)=n\cdot f(n-1)=n\cdot (n-1) \cdots 1\)=
- More efficient? No because more resources need to keep track of the execution.
- Easier to write? Yes because wishful thinking leads to code reuse.
Why recursion instead of iteration?
Reusing Functions
Say you would like to do check if a number is divisible by the numbers 2, 3, 5 and 7. Normally, you would write something like
Remember that the modulo operator \(\%\) takes the reminder of the division of number \(n\) by the numbers 2, 3, 5, and 7.
How do we avoid copy-pasting the same logic (code duplication) to decrease redundancy?
- Copy-pasting -> BAD PRACTICE
- Not easy to "transport" a function into other programs
- If a bug (unexpected behavior) is discovered in our isDivisibleBy function, we would have to repeat the copy-paste function multiple times.
Further simplification:
Functions as Data
Functions in Python are objects, just like the previous types you have studied (strings, integers). Thus, we can treat it like data.
Lambda Expressions
Lambda expressions are simple, anonymous functions to simplify function calls.
Local Function Definitions
Sometimes also referred to as nested functions
Break down functions into smaller components in a function
Partial Application
Application of passing functions as arguments to other functions
Break down functions into smaller components in a function
Let us get back to our previous example:
Objects
Python supports object oriented programming (OOP). As previously mentioned, each Python object has a type, or class.
An object is an instance of a class.
With OOP, we combine data and methods.
Before we go deeper into objects, let us look back at some of the general ideas and ways to express and use objects.
Object Methods
In general, a method call will have the following syntax:
object
method name
parameter list
(
)
.
object
period (dot)
method name
parameter list
: expression that represents object
: associates object expression with method
to be called
: name of method to execute
: comma-separated list of method's parameters
always required even if there are no parameters
similar to parameter list for a function call
Object Methods
Example: String Objects
Python strings are objects. They provide the perfect example of combining data and methods.
course_name = "cs1302"
print("Welcome to the {} course, hope you like it so far!"
.format(course_name.upper()))
# Output: Welcome to the CS1302 course, hope you like it so far!String contains the data "cs1302" and has the upper() method
Optional:
For more string methods, check out https://docs.python.org/3/library/string.html
File Objects
Sometimes, we might want to read data from a file or save the results of our program execution into a file. We can achieve this with Python's standard library.
# Reading a file named file.txt
f = open("file.txt") # Equivalent of open("file.txt", "r")
for line in f:
print(line.strip())
f.close()There are several different modes for opening a file, specified in the second argument of the open function
- 'r', opens file for reading, default (no argument)
- 'w', opens file for writing, create new file if nonexistent
- 'a', opens file and adds text to the end of file (append)
Context Manager
Works with classes which provide initialization (open) and finalization (close) protocols. These protocols are defined for objects using the built-in __enter__and __exit__methods.
object-creation
object
:
with
as
block
Context Manager
with
object-creation
as
object
block
: reserved word, begins the statement
: attempts to create an object, only executes
function in block if creation successful
: reserved word, binds object created by object-
creation expression to a variable
: binding for object created by object-creation
: contains code which can use the previously
bounded object
object-creation
object
:
with
as
block
Example: File Objects
Formal name of file objects is \(TextIOWrapper\), found in the built-in \(io\) module. No import statement is required since the functions from \(io\) module are exposed by default.
open
filename
open mode
,
)
(
Returns a file (\(TextWrapperIO\)) object. Supported open modes are:
- 'r' for reading, default when no open
mode is specified
- 'w' for writing
- 'a' for appending data to file
*appending = adding data to end of file
Example: File Objects
When a file has been opened with 'w' or 'a', we can write to it with a file object's \(write\) method.
Usually, we have to call the \(close\) method to close the file.
Example: File Objects
with open("my_diary.txt", "w") as f:
# Note that \n represents a newline operator
f.write("I am currently attending\n")
f.write("The CS1302 course\n")
print(f.read())
for line in f:
print(line.strip())
With context managers, we can automatically close the file after all function inside the block executes:
Fraction Objects
Provided by the \(Fraction\) class from the \(fractions\) module
Modelling rational numbers (numbers as ratio of two integers) with a numerator and denominator.
Reserved Object Methods in Fractions
Python reserves some special names for some methods.
For instance, the \(Fraction\) class provides an __add__ method. This function is invoked when we add two fractions. The + operator is an example of syntactic sugar for the __add__ method.
Reserved Object Methods in Fractions
Other special methods which Python provides:
- __mul__, multiplication: f.__mul__(g) is equivalent to f * g
- __eq__, relational quality: f.__eq__(g) is equivalent to f == g
- __gt__, greater than: f.__gt__(g) is equivalent to f > g
- __sub__, subtraction: f.__sub__(g) is equivalent to f - g
- __neg__, unary minus: f.__neg__() is equivalent to -f
Let's apply these concepts to what you have learned from previous lectures in the next slide!
Object Mutability and Aliasing
A variable is a name that labels an object. We have treated a variable as if it represents the object. For example, given the following statement:
We often refer to the object \(frac1\). In fact, this \(frac1\) "object" is the \(Fraction\) object representing the rational number \(\frac{1}{2}\).
To better understand objects, let us have a deeper look.
Object Mutability and Aliasing
A variable is a name that labels an object. We have treated a variable as if it represents the object. For example, given the following statement:
We often refer to the object \(frac1\). In fact, this \(frac1\) "object" is the \(Fraction\) object representing the rational number \(\frac{1}{2}\).
To better understand objects, let us have a deeper look.
Object Mutability and Aliasing
Object Mutability and Aliasing
This aliasing behavior might be a problem. Let's say we created two class variables c1 and c2.
Why is this so?
Garbage Collection
The following statement:
f = Fraction(2, 3)
Creates a Fraction object representing the rational number \(\frac{2}{3}\) and assigns the variable f to the object. By doing so, the Python interpreter reserves some computer memory to hold the object and initializes the objects as such:
f.numerator = 2
f.denominator = 3
Garbage Collection
If we reassign the statement in the previous slide to be:
f = None
Where None is a special type which represents no object, the Fraction object previously created is now effectively abandoned and is unused for the remainder of the program's execution. In other words, it is now garbage.
Garbage is memory allocated by a program which is no longer accessible by the program. Python's interpreter is able to automatically do garbage collection using a reference counting garbage collector.
Reference Counting
Let us look at the visualization below:
CS1302 Lecture 5
By Chung Chan
CS1302 Lecture 5
- 187