9.2 — Keyword arguments, More on OOP

Defining functions/methods with keyword arguments

A keywords argument has a default value in function or method definition.

def func(pos1, pos2, ..., name1=value1, name2=value2, ...):

Here, pos1, pos2, etc are positional arguments and
name1, name2, etc are keyword arguments with default values value1, value2, respectively.

Keyword arguments cannot appear before positional arguments.

If the function is called without passing a keyword argument, that argument gets its default value.

1def greet(name, greeting="Hello", num_of_times=1):
2 for i in range(num_of_times):
3 print(greeting, name)
4
5# try the following one at a time:
6# greet("Dev")
7# greet("Dev", greeting="Hi")
8# greet("Dev", num_of_times=3)
9# greet("Dev", greeting="Hi", num_of_times=3)
10# greet("Dev", num_of_times=3, greeting="Hi")

OOP continued

1class Student:
2 """ Represents a student. """
3
4 def __init__(self, student_name, id_num):
5 self.name = student_name
6 self.id_num = id_num
7
8 def display_info(self):
9 print("Name of student:", self.name)
10 print("Student ID:", self.id_num)
11
12
13new_student = Student("Bob", 260000000)
14new_student.display_info()
15# Name of student: Bob
16# Student ID: 260000000

Let’s add a new attribute to store courses and a new method which allows adding a course.

1s1 = Student("Robin", 26005)
2s1.add_course("COMP 208")
3s1.add_course("POLI 220", pass_fail=True)
4s1.add_course("MATH 250")
5s1.display_info()
Output
Name of student: Robin
Student ID: 26005
Courses: COMP 208, POLI 220 (pass/fail), MATH 250

  • Add an attribute courses, initializing it to empty dictionary. This dictionary will store a course name as a key and a boolean value to indicate whether the course is registered as pass/fail.
  • Update display_info method to also display a comma-separate list of course names. If there are no courses in the courses dictionary, do not display any line for it.
  • Add a method add_course that takes as a course name (str) and a keyword argument pass_fail (default value: False) and adds them to the attribute courses.

Code available in the file student_methods.py.

Displaying objects: __str__ method

When we display student1 we see what class the object belongs to, and the identity of the object.

1s1 = Student("Dev", 26001)
2print(s1)
Output
<__main__.Student object at 0x7f8cd66aa890>

Wouldn’t it be nice to display name, id_num and other attributes when we do print(student1)?

__str__ method

  • We can change the string representation of our class objects by implementing a method called __str__ in our class.

    1def __str__(self):
    2 # must return a string
  • If we do that, then when we call print(obj) or str(obj) with an instance obj of our class, __str__ method is called automatically and the returned string is used.

Try it!

In the Student class, add a __str__ method that returns a string in the following format:

Name: <name attribute>
Student ID: <id_num attribute>
Courses: <comma-separated courses>

Then, try to use print with an object of Student class.

Code available in the file student_str.py.

Example — List of Student objects

1students = [Student("Dev", 260001),
2 Student("Reza", 260005)]
3
4# Create a student object and append it to the list
5students.append(Student("Alice", 260011))
6
7print(students[2]) # uses __str__ of Student class
8# Name: Alice
9# Student ID: 260011
10# Courses: None registered.

1# Continued from previous slide:
2
3print(students) # Does not use __str__ of Student class
4# [<__main__.Student object at 0x10ad16100>,
5# <__main__.Student object at 0x10ad169d0>,
6# <__main__.Student object at 0x10ad16a00>]
7
8
9for s in students:
10 print(s) # uses __str__ of Student class

Try questions on Ed Lessons.

More on special methods

https://docs.python.org/3/reference/datamodel.html#special-method-names

“A class can implement certain operations that are invoked by special syntax (such as arithmetic operations or subscripting and slicing) by defining methods with special names.”

See the files point.py and point_tester.py.

zip function

zip(x, y) function creates an iterable of tuples (xi,yi)(x_i, y_i) where xix_i is element from x and yiy_i is element from y.

1x_values = [0.5, -2, 5, 10]
2y_values = [-1.5, 3, -3.5, 20]
3
4points = list(zip(x_values, y_values))
5print(points)
6# [(0.5, -1.5), (-2, 3), (5, -3.5), (10, 20)]

1x = [1, 2.5, 5]
2y = [2, 4, 10.5]
3
4total = 0
5for i in range(len(x)):
6 total += x[i] * y[i]
7
8print(total)
1x = [1, 2.5, 5]
2y = [2, 4, 10.5]
3
4total = 0
5for x, y in zip(x, y):
6 total += x * y
7
8print(total)

What happens when one of the argument lists of zip is shorter than the other?

Truth Value Testing

Any object can be tested for truth value, e.g. when used in an if or while condition.

1x = [1, 2, 3]
2
3if x:
4 print("do something")
5else:
6 print("do other thing")

By default, an object is considered true

  • unless its class defines either a special __bool__() method that returns False or a __len__() method that returns zero, when called with the object.

Here are most of the built-in objects considered false:

  • Constants defined to be false: None and False
  • Zeros: 0, 0.0
  • empty sequences and collections: "", tuple(), [], {}, set(), range(0)

Incorrect:

1ans = input('Are you sure? ')
2
3if ans == 'y' or 'yes':
4 print('Installing...')

Correct:

1ans = input('Are you sure? ')
2
3if ans == 'y' or ans == 'yes':
4 print('Installing...')