5.2 — Scope of variables, List operations

Scope of variables

  • A variable name only exists inside the body of the function in which it is created.
    • It does not exist outside the function or in any other functions.
1def f():
2 x = 3
3 print("In f(), x =", x)
4
5f()
6print(x)
Output
In f(), x = 3
NameError: name 'x' is not defined

  • The scope of a variable consists of parts of the program where the variable name exists and can be used.
  • Each function has its own local scope, which other functions cannot access.
  • global scope consists of names accessible by the entire module (Python file).

A variable created inside a function is called a local variable.

A variable created outside any function is called a global variable.

1def f():
2 x = 3 # local variable
3 # local x is used below!
4 print("In f(), x =", x)
5
6
7x = 100 # global variable
8f()
9print(x) # global x is used
Output
In f(), x = 3
100
  • As we saw above, it is possible to create a local variable with the same name as a global variable.
  • These are considered two different variables, and inside the function only the local one will be used.

1def f():
2 # global x is used below!
3 print("Inside f(), x =", x)
4
5
6x = 100 # global variable
7f()
8print(x)
Output
Inside f(), x = 100
100

What will happen if the global variable x is created after the function call f()?

How variable name is looked up?

  • Inside a function, when a name is used:
    • First, name is searched within the function (local scope) to see if it exists.
    • If name is not found in the function, it is searched globally
  • Outside a function, name is simply searched globally
  • If a name cannot be found anywhere (local or global scope), we get NameError complaining that the name is not defined.

What will be printed in each case?

1def f():
2 y = 5
3 print(x)
4
5x = 10
6f()
1def f():
2 x = 5
3 print(x)
4
5x = 10
6f()
7print(x)

Output
10
Output
5
10

Function parameters are also local to the function.

Best Practice

  • Try to avoid using global variables within functions when possible.
    • It is okay to use variables that don’t change (e.g. constants such as π\pi)
    • It is also okay to use modules inside functions

Lists — Concatenation + and Replication *

1# lists a and b are joined to produce a third list c:
2a = [1, 2]
3b = [10, 11, 12]
4c = a + b
5print(c)
6# [1, 2, 10, 11, 12]
7
8a = [1, 2]
9# resulting list consists of repeated items of list a:
10c = a * 3
11print(c)
12# [1, 2, 1, 2, 1, 2]

membership operators: in and not in

We can use them to test if an object is present in a list.

1a = [1, 2]
2b = [10, 11, 12]
3
4print(1 in a) # True
5print(11 in a) # False
6print(5 not in b) # True
7
8x = 3.14
9print(x in a or x in b) # False

in/not in operators are very useful in simplifying code:

1# Instead of long conditions like this:
2if x == 5 or x == 7 or x == 10:
3 # do something
1# Now we can do:
2if x in [5, 7, 10]:
3 # do something

Slicing a list

Similar to strings, we can also get a sub-list — parts of a list — using slice notation. Slicing creates a new list.

1days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
2
3print(days[2:5])
4# ['Wed', 'Thu', 'Fri']
5
6print(days[:6:2])
7# ['Mon', 'Wed', 'Fri']

1days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
2
3# Make a copy of the whole list
4print(days[:])
5# ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
6
7# Makes a reversed copy of the list
8print(days[::-1])
9# ['Sun', 'Sat', 'Fri', 'Thu', 'Wed', 'Tue', 'Mon']

Iterating through a list

We can either use an index or loop directly over items in a list:

1def average(nums):
2 total = 0
3
4 for i in range(len(nums)):
5 total += nums[i]
6
7 return total / len(nums)
8
9grades = [85, 100, 98, 75]
10print(average(grades))
1def average(nums):
2 total = 0
3
4 for x in nums:
5 total += x
6
7 return total / len(nums)
8
9grades = [85, 100, 98, 75]
10print(average(grades))

But when we need to modify a list inside a loop we have to use an index:

1def add_bonus(grades, bonus):
2 """ Add bonus to each grade in grades list
3 (grade should not exceed 100)
4 Returns: None
5 """
6 for i in range(len(grades)):
7 grades[i] = min(grades[i] + bonus, 100)
8
9
10assignment_grades = [55, 60, 67, 97]
11add_bonus(assignment_grades, 5)
12print(assignment_grades) # [60, 65, 72, 100]

Built-in functions that work with lists

1grades = [90, 70, 60.5, 70, 80]
2
3# len(x):
4# Returns the number of items in the list x.
5print(len(grades)) # 5
6
7# sum(x):
8# Returns the sum of all the numbers in list x.
9# A TypeError occurs when some item is not a number.
10print(sum(grades)) # 370.5

1grades = [90, 70, 60.5, 70, 80]
2
3# min(x) / max(x) :
4# Returns the smallest/largest item in the list x.
5# A TypeError occurs if the items cannot be compared.
6
7print(min(grades)) # 60.5
8
9print(max(grades)) # 90
10
11print(min(["90", 70, 60.5, 70, 80]))
12# TypeError: '<' not supported between instances of 'int' and 'str'

List methods

Python has several methods that we can call on a list object:

1# list.append(x): Adds the item x to the end of the list
2
3grades = [90, 70, 60.5, 70, 80]
4grades.append(100)
5print(grades) # [90, 70, 60.5, 70, 80, 100]
6
7grades.append("30")
8print(grades) # [90, 70, 60.5, 70, 80, 100, '30']
9
10grades.append(False)
11print(grades) # [90, 70, 60.5, 70, 80, 100, '30', False]

Example:

1def filter_values(nums, threshold):
2 ''' Return a new list to include numbers from
3 the list nums that are above threshold
4 '''
5 new_list = []
6
7 for n in nums:
8 if n > threshold:
9 new_list.append(n)
10
11 return new_list
12
13print(filter_values([3, 1, 2, 5, 4], 3)) # [5, 4]
14print(filter_values([3, 1, 2, 5, 4], 5)) # []

1# list.insert(i, x): Adds the item x to the list at index i
2
3grades = [90, 70, 60.5, 70, 80]
4grades.insert(0, 100)
5print(grades) # [100, 90, 70, 60.5, 70, 80]
6
7# insert() works even when index is greater than length of list
8grades = [90, 70, 60.5, 70, 80]
9grades.insert(10, "B+")
10print(grades) # [90, 70, 60.5, 70, 80, 'B+']

1# list.remove(x):
2# Removes the first occurrence of the item x in the list.
3# A ValueError occurs if there is no such item.
4
5grades = [90, 70, 60.5, 70, 80, 'B+']
6grades.remove(70)
7print(grades) # [90, 60.5, 70, 80, 'B+']
8
9grades.remove("B+")
10print(grades) # [90, 60.5, 70, 80]
11
12grades.remove(60)
13# ValueError: list.remove(x): x not in list

1# list.pop(i):
2# Removes and returns item at index i
3# list.pop():
4# Removes and returns the last item from the list
5
6grades = [90, 70, 60.5, 70, 80, 'B+']
7last_item = grades.pop()
8print(last_item) # B+
9print(grades) # [90, 70, 60.5, 70, 80]
10
11second_item = grades.pop(1)
12print(second_item) # 70
13print(grades) # [90, 60.5, 70, 80]

1# list.count(x) :
2# Returns the number of occurrences of the item x.
3
4grades = [90, 70, 60.5, 70, 80, 'B+']
5print(grades.count(70)) # 2
6print(grades.count("B+")) # 1
7print(grades.count(60)) # 0

1# list.index(x) :
2# Returns the index of the first occurrence of item x in list.
3# A ValueError occurs if item x is not found in list.
4
5grades = [90, 70, 60.5, 70, 80, 'B+']
6
7print(grades.index(70)) # 1
8print(grades.index(60)) # ValueError: 60 is not in list

1# list.extend(sequence) :
2# Extend list by appending items from the sequence.
3
4grades = [90, 70, 60.5, 70, 80]
5
6grades.extend([100, 95])
7print(grades) # [90, 70, 60.5, 70, 80, 100, 95]
8
9grades.extend("cat")
10print(grades)
11# [90, 70, 60.5, 70, 80, 100, 95, 'c', 'a', 't']

Lists and Strings

There are built-in functions and string methods that allows us to transform strings to/from lists.

1# list(seq): built-in function which converts a sequence (such as
2# a string or a list) into a list
3
4fruit = "apple"
5letters = list(fruit)
6print(letters) # ['a', 'p', 'p', 'l', 'e']

1# s.split(): Breaks the string s using whitespace
2# (spaces, tab character and newline) as the separator and
3# returns a list of strings containing the separated parts
4
5data = "Red Green Blue"
6names = data.split()
7print(names) # ['Red', 'Green', 'Blue']
8
9# Multiple spaces are also removed
10data = " Red Green Blue "
11names = data.split()
12print(names) # ['Red', 'Green', 'Blue']

1data = "Red\tGreen\tBlue" # separated by tab
2names = data.split()
3print(names) # ['Red', 'Green', 'Blue']
4
5data = """Red
6Green
7Navy Blue"""
8names = data.split()
9print(names) # ['Red', 'Green', 'Navy', 'Blue']

1# s.splitlines(): Breaks a multi-lines strings into separate lines
2# and returns a list containing those lines.
3
4data = """Red
5 Green
6Navy Blue
7"""
8names = data.splitlines()
9print(names) # ['Red', ' Green', 'Navy Blue']

1# s.strip(): Return a copy of the string with
2# leading and trailing whitespace removed.
3# s.lstrip(): removes leading whitespace only
4# s.rstrip(): removes trailing whitespace only
5
6name = " Green "
7print("|" + name + "|")
8print("|" + name.strip() + "|")
9print("|" + name.lstrip() + "|")
10print("|" + name.rstrip() + "|")
Output
|    Green    |
|Green|
|Green    |
|    Green|

1# s.strip(chars): Return a copy of the string
2# with leading and trailing chars removed.
3# s.lstrip(chars): removes leading chars only
4# s.rstrip(chars): removes trailing chars only
5
6text = "...#some . text #..."
7
8print(text.strip("."))
9print(text.lstrip("."))
10print(text.rstrip("."))
11
12# multiple chars to remove
13print(text.strip(". #"))
Output
#some . text   #
#some . text   #...
...#some . text   #
some . text

1# s.split(sep): Breaks the string s using the separator string sep
2# and returns a list of strings containing the separated parts
3
4data = "Red,Green,Blue"
5names = data.split(",")
6print(names) # ['Red', 'Green', 'Blue']
7
8data = "Red, Green, Blue"
9names = data.split(",")
10print(names) # ['Red', ' Green', ' Blue']
11# notice space in strings above

1# sep.join(L): joins all the strings in the list L using
2# the string sep and returns the joined string.
3
4names = ['Red', 'Green', 'Blue']
5joined = " ".join(names)
6print(joined) # Red Green Blue
7
8# a comma
9joined = ",".join(names)
10print(joined) # Red,Green,Blue

1# a comma and a space
2names = ['Red', 'Green', 'Blue']
3joined = ", ".join(names)
4print(joined) # Red, Green, Blue
5
6# empty string, no separator
7letters = ["a", "p", "p", "l", "e"]
8joined = "".join(letters)
9print(joined) # apple

Try the problem “Parsing a string” on Ed Lessons.

Try the problem “Puzzle: Switching 100 light bulbs” on Ed Lessons.