Homework for Week 13
After this week you can
- Define a class
- Create instances of a class
- Use instance variables and methods
- Add objects to a list
Object-oriented programming
Up to now, when writing programs, we have stored information in variables. Variables can hold values of various types: integers, strings, lists, dictionaries, etc. But so far, we have not been able to store data types that we define ourselves. In this chapter, we'll learn about classes and objects and see how to create and use them. In addition, we will explore how to add methods to classes and take advantage of properties given to objects.
This week we'll cover the basics of object-oriented programming. Next week will be devoted to inheritance.
Watch the lecture videos:
Slides in English
Textbook in English
Object and class
Object-oriented programming is based on the concept of objects. An object is a data type that consists of variables and methods. Variables define the object's state, methods define the object's behavior. Using objects helps to make programs clearer and more structured.
An example of an object can be a person. We can describe a person's variables, or state, with words such as name, age, height, hair color, gender, etc. Activities such as eating, studying, sleeping, exercising, etc., are methods, i.e., behavior.
To use objects, we need to create a class. There we specify what variables and methods the object has. A class is a template that describes the data and the methods used to manipulate the data.
Creating a class starts with the keyword class
, followed by the class name (conventionally with a capital letter) and a colon. One file can contain several different class definitions: each class must start with the keyword class
and have a unique name.
Constructor
Object variables are defined in the class constructor. The constructor is run whenever the program creates a new instance of the class. The name of the constructor is always __init__. All variables that exist in an instance of the class must be defined in the constructor. These variables are also called instance variables. When creating an instance (object) of a class, its __init__ method is called, which determines the initial state of the object (values of instance variables). Each new object of the class is initialized using the __init__ method.
For example, we can create a class Student whose instances have properties such as name, age, university specialty, and average grade.
class Student: # Constructor def __init__(self, name, age, specialty, average_grade): # Objects of type Student have four instance variables self.name = name self.age = age self.specialty = specialty self.average_grade = average_grade
Using the constructor, we give four properties to the instances of the student class: name, age, specialty, and average grade. Now, in the same program, we create two instances of the Student class with different properties. Student instances must be defined outside of the Student class.
# end of class Student student1 = Student("Karl Tamm", 21, "Biology", 3.9) student2 = Student("Maria Hein", 24, "Computer Science", 4.6) print(student1.age) print(student2.specialty)
Output
21
Computer Science
As you can see, the two students have different characteristics. Properties, or instance variables, can be accessed with the following syntax: object_name.instance_variable_name. In the above example, the age of the first student and the specialty of the second student are printed this way.
Parameter self
Any number of parameters can be given to the class constructor (the __init__ method), but the first parameter must always be self. When a new class instance is created, that instance is automatically passed to the self parameter of the __init__ method. The value of this variable refers to the newly created object. Therefore, all instance variables are bound to that instance. The first parameter of class constructor and instance methods must always be self.
Methods
Methods are functions defined inside the class and can only be called using an instance (object) of the class. The first parameter of all methods is always self, similar to the class constructor, i.e., the __init__ method.
For example, we can extend the Student class with two methods.
class Student: # Constructor def __init__(self, name, age, specialty, average_grade): # Objects of type Student have four instance variables self.name = name self.age = age self.specialty = specialty self.average_grade = average_grade # Method no. 1 def institute(self): if self.specialty.lower() == "biology": return "Student " + self.name + " studies at the Institute of Bio and Transplantation Medicine." elif self.specialty.lower() == "informatics": return "Student " + self.name + " studies at the Institute of Computer Science." else: return "Don't know other institutes." # Method no. 2 def scholarship(self, scholarship_limit): if self.average_grade < scholarship_limit: return "Student " + self.name + " does not receive a scholarship." else: return "Student " + self.name + " receives a scholarship."
- The method institute has no parameters (of course, apart from the parameter self, which must be present in every method included in the class). The method returns the institute where the student studies, depending on the specialty specified in the student instance.
- The parameter of the scholarship method is the lower limit of the average grade as a floating point number for receiving the scholarship. The method returns a string with information on whether the student receives a scholarship or not.
In both methods, we notice that the instance variables are accessed with the keyword self (self.specialty, self.average_grade) in the method body. In this way, it is possible to use the object's instance variables when calling a method. As mentioned above, methods can only be called using an object. Therefore, we can refer to the instance variables of the object itself in the method's body.
More about creating the constructor
When creating the constructor, we can also add a default value to the instance variables. For example, if we want all students to be students of the University of Tartu, we can create the variable university in the constructor as follows:
self.university = "University of Tartu"
If we want to use a list as an instance variable, we can create an empty list in the constructor and change it in the instance method. For example, we can add a list to the constructor of the Student class about the courses taken:
self.courses = []
The entire constructor would then look like this:
# Constructor def __init__(self, name, age, specialty, average_grade): # Objects of type Student would then have six instance variables self.name = name self.age = age self.specialty = specialty self.average_grade = average_grade self.university = "University of Tartu" self.courses = []
To add courses to the student instance, we can create an instance method that adds elements to the list:
# Method no. 3 def add_course(self, course): self.courses.append(course)
And we can use the instance method like this:
student1.add_course("Programming") print(student1.courses)
Adding objects to a list
Objects can also be added to lists. Let's add two instances of the class Student to a list and test the methods:
student1 = Student("Karl Tamm", 21, "Biology", 3.9) student2 = Student("Maria Hein", 24, "Informatics", 4.6) students = [] students.append(student1) students.append(student2) print(students[0].institute()) print(students[1].scholarship(4.6))
Output
Student Karl Tamm studies at the Institute of Bio and Transplantation Medicine.
Student Maria Hein receives a scholarship.
Quiz
Solve the quiz on object-oriented programming in Moodle.
Exercises
1. Library
Create a class called Book
whose constructor's parameters are title, author, number of pages, and type of a book (novel, fairy tale, detective, etc.). The class also has a method print_info, which prints the book's information on the screen in a readable form.
>>> truth_and_justice = Book("Truth and Justice", "A. H. Tammsaare", 453, "novel")
>>> truth_and_justice.print_info()
Truth and justice, A. H. Tammsaare, 453, novel
Create a class called Library
, whose constructor creates an empty list of books. The class must have the following methods:
- Method add_book, which takes an instance of the class
Book
as an argument and adds it to the list of books. - Method print_books, which prints the information of all the books in the library using the method print_info.
- Method borrow_book, whose argument is the book title as a string. The capitalization of letters in the argument may not be correct. The method searches for a book with that title in the list of books. If the book exists in the list, then removes it from the list and returns the book instance found. If the book doesn't exist, then leaves the list unchanged and returns the value
None
.
>>> lib = Library()
>>> lib.add_book(truth_and_justice)
>>> lib.print_books()
Books in the library:
Truth and Justice, A. H. Tammsaare, 453, novel
>>> book = lib.borrow_book("TRUTH and JUSTICE")
>>> book.title
'Truth and Justice'
Here is a file books.txt where each line contains the data of one book, separated by commas:
Truth and Justice, A. H. Tammsaare, 453, novel The Adventures of Sherlock Holmes, A. C. Doyle, 233, detective All Quiet on the Western Front, E. M. Remarque, 310, novel Little Red Riding Hood, Charles Perrault, 17, fairy tale Curtain, Agatha Christie, 98, detective The Great Gatsby, F. Scott Fitzgerald, 188, novel
Write the main program that creates an instance of the Library
class, adds all the books in the file books.txt to it, and prints all the books in the library to the screen. It then asks the user for the title of the book they want to borrow. If a book with this name is in the library, the program borrows it and again prints all books in the library. If the book is not in the library, the program asks the user for the name of the book again until the user enters the title of an existing book. After that the program terminates.
Books in the library:
Truth and Justice, A. H. Tammsaare, 453, novel
The Adventures of Sherlock Holmes, A. C. Doyle, 233, detective
All Quiet on the Western Front, E. M. Remarque, 310, novel
Little Red Riding Hood, Charles Perrault, 17, fairy tale
Curtain, Agatha Christie, 98, detective
The Great Gatsby, F. Scott Fitzgerald, 188, novel
Enter the title of the book you want to borrow: curt
Cannot find such book, try again!
Enter the title of the book you want to borrow: curTAIN
The book Curtain successfully borrowed!
Books in the library:
Truth and Justice, A. H. Tammsaare, 453, novel
The Adventures of Sherlock Holmes, A. C. Doyle, 233, detective
All Quiet on the Western Front, E. M. Remarque, 310, novel
Little Red Riding Hood, Charles Perrault, 17, fairy tale
The Great Gatsby, F. Scott Fitzgerald, 188, novel
2. Scooter rental
Create a class called Scooter
, whose constructor's parameters are the name of the rental company, the starting fee for a ride, the price per 100 meters of riding, and the available riding distance of the scooter in kilometers.
The class must have the following methods.
- Method price, which takes the length of the ride in kilometers as an argument. If the ride length requested does not exceed the available riding distance of the scooter, the method returns the price of a ride of that length, taking into account the starting fee and the price per 100 meters. However, if the ride length exceeds the scooter's available riding distance, the method returns the integer 1000.
- Method ride, which takes the length of the ride as an argument and subtracts it from the available riding distance. If the available riding distance becomes exhausted, it assigns the value 0 to the distance field.
- Method charge, whose argument is the number of kilometers, and which increases the available riding distance of the scooter by the given number of kilometers.
>>> bolt = Scooter("Bolt", 1.5, 0.1, 20)
>>> bolt.price(3)
4.5
>>> bolt.ride(15)
>>> bolt.charge(5)
>>> bolt.price(15)
1000
Create a class called Rental
whose constructor's parameter is a list of instances of the class Scooter
.
The Rental
class must have the following methods.
- Method display_choices, which takes the length of the ride in kilometers as an argument and prints the name of each scooter and the price of the ride, ordering the scooters from top to bottom, starting with the cheapest. To find the price of the ride, use the price method.
- Method rent, whose arguments are the name of the scooter the user wants to ride and the length of the ride. If the requested length does not exceed the available riding distance of the scooter, then it prints the price of the ride and rides the scooter so many kilometers (method ride). Otherwise, it prints an appropriate message and does nothing.
- Method charge_scooter, which takes the name of the scooter to be charged and the number of kilometers as arguments. The method increases the available riding distance of the scooter by the requested number of kilometers (method charge).
Finally, write a program that prompts the user for the details of three scooters:
- Bolt, 1.5, 0.1, 20
- Tuul, 1, 0.15, 18
- Bird, 0, 0.3, 34
The data for each scooter is entered as one line. All three scooters are added to the list of scooters of an instance of the Rental
class, and then the following methods are called on that instance:
- display_choices(2)
- rent("Bolt", 3)
- rent("Tuul", 18)
- rent("Tuul", 5)
- charge_scooter("Tuul", 5)
- rent("Tuul", 2)
Enter company, starting fee, price per hundred meters, and available distance: Bolt, 1.5, 0.1, 20
Enter company, starting fee, price per hundred meters, and available distance: Tuul, 1, 0.15, 18
Enter company, starting fee, price per hundred meters, and available distance: Bird, 0, 0.3, 34
1. Bolt - 3.5 euros
2. Tuul - 4.0 euros
3. Bird - 6.0 euros
The price of the ride was 4.5 euros
The price of the ride was 28.0 euros
The battery of the scooter is too low for this ride.
The price of the ride was 4.0 euros
Submit your solutions
Submit the solutions to the tasks via Moodle as files home1.py and home2.py.
Advice
Programming is breaking of one big impossible task into several very small possible tasks.