In this example we define a class called Rectangle. Each element in this class has attributes of width, height.

https://www.youtube.com/watch?v=ZLE84BNDUeA

Ex 3.1.1 Declaring a Class, Defining Methods of that Class, and Instantiating Objects

Lines 4 defines the class named Rectangle. In Python classes are usually given a name beginning with an upper case letter.

Line 5 "init is a reseved method in python classes. It is called as a constructor in object oriented terminology. This method is called when an object is created from a class and it allows the class to initialize the attributes of the class. The word init is bracketed by double underscores. These are sometimes called magic methods. Some verbalize these by using the word dunder (for double underscore). e.g. dunder init. The first argument in this initialization method MUST BE self. When we create an object from this class that object is passed to init as self. The remaining arguments (in this case width and height). These are the properties that make a rectangle unique.

Lines 6-7 tells init to assign the variable width to the created object. The value of width will be passed to init at the time the object is instantiated.

" Lines 8-10 define functions find_area(self) and find_perimeter(self) as methods for this class of functions. When applied to a particular rectangle object, self refers to that instance. The value of the area is defined in line 9 as self.width*self.height. Again referring to the particular rectangle object to which it is applied.

Line 14 is called the class constructor. Calling the Rectangle(21,41) creates, initializes (using init, and returns a new instance of the class. This instance is then assigned to the variable rec1.

Lines 15-16 The methods find_area() and find_perimeter() are applied to the instance rec1 using the dot notation.

Lines 17- 19 are print statements using f string formats. Note: we could have eliminated lines 14 and 15 by simply putting the rhs of these expressions in the appropriate {}.

In [2]:
# Ex 3.1.1

# defining the class Rectangle
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def find_area(self):
        return self.width*self.height
    def find_perimeter(self):
        return 2*(self.width+self.height)

# constructing a rectangle object from the class    
rec1 = Rectangle(21, 42)
a=rec1.find_area()
per=rec1.find_perimeter()
print(f'For the rectangle of height={rec1.height} and width= {rec1.width}')
print(f'The area is {a}')
print(f'The perimeter is {per}')
For the rectangle of height=42 and width= 21
The area is 882
The perimeter is 126

Ex 3.1.2 Multiple Classes

In the following example we will define two classes: a class of squares characterized by the length of its side, and a class of triangles characterized by the base and height.



Lines 2-5 define the class Square. An object from the Square class has only one parameter. Remember the first argument of init is always self. The second argumet is side. Within the class definition any calculations (e.g. the area defined by the function area() must use self.side.

Lines 6-11 define the parameters of the object and the method area(). Note: this is a different method from the one defined in square. This method is only valid when applied to an object of class Triangle. Lines 12-13 Here we instantiate a Square object--sh1, and a triangle object--sh2.

Lines 14-15 Even though the method .area() is used with the same name, these are again DIFFERENT methods. When .area() is applied to an object of the Square class, the program knows to apply the appropriate fuction.

Line 16 prints out the two areas. NOTICE each area is a tuple. Look at the return statements for the area of the square and the area of the rectangle. We actually return TWO values for the area: the first is the string 'square' or 'triange' depending on the object class, and the second is the value of the computed area.

Lines 17-18 are f-string prints. Here a1[0] addresses the first element of the tuple contained in a1, while a1[1] is the second element of the tuple--the actual area.

In [ ]:
# Ex 3.1.2 
class Square:
    def __init__(self,side):
        self.side=side
    def area(self):
        return('square',self.side**2)
class Triangle:
    def __init__(self,base,height):
        self.base=base
        self.height=height
    def area(self):
        return('triangle',.5*float(self.base)*self.height)
sh1=Square(2)
sh2=Triangle(3,4)
a1=sh1.area()
a2=sh2.area()
print(a1,a2)
print(f'I am a {a1[0]} with an area={a1[1]}')
print(f'I am a {a2[0]} with an area={a2[1]}')

Ex 3.1.3 Subclasses

This example is a modification of 3.1.2. In this example, we are going to define a subclass of triangle objects which are colored either red, green or blue. In order to do this we will use the random.choice() function from the library random.

Line 2 imports the library random.

Lines 4-13 are identical to Ex 3.1.2

Lines 14-19 define a subclass of the Triangle class. The fact that it is a subclass of Triangle is specified in the definition class ColorTriangle(Triangle). The arguement here is not self as in the earlier classes, but Triangle.

Line 15 The first init indicates that this new class has base and height as arguments. Line 16 establishes the fact that these arguments are INHERITED from the super class (Triangle).

Line 17 defines the color of the triangle as a random selection from the set ['RED','GREEN','BLUE']

Lines 18-19 returns a tuple with THREE elements: the string 'triangle', the area, and the self.color)

The remainder of the program is similar to Ex 3.1.2 except for the last print statement which now uses THREE elements of the returned tuple for the instance of the ColorTriangle.

In [1]:
#Ex 3.1.3
import random 
class Square:
    def __init__(self,side):
        self.side=side
    def area(self):
        return('square',self.side**2)
class Triangle:
    def __init__(self,base,height):
        self.base=base
        self.height=height
    def area(self):
        return('triangle',.5*float(self.base)*self.height)
class ColorTriangle(Triangle):
    def __init__(self,base,height):
        super().__init__(base,height)
        self.color=random.choice(['RED','GREEN','BLUE'])   
    def area(self):
        return'triangle',.5*float(self.base)*self.height,(self.color)
sh1=Square(2)
sh2=Triangle(3,4)
sh3=ColorTriangle(3,4)
a1=sh1.area()
a2=sh2.area()
a3=sh3.area()
print(f'I am a {a1[0]} with an area={a1[1]}')
print(f'I am a {a2[0]} with an area={a2[1]}')
print(f'I am a {a2[0]} with an area={a2[1]} and I am colored {a3[2]}')
I am a square with an area=4
I am a triangle with an area=6.0
I am a triangle with an area=6.0 and I am colored GREEN
In [ ]: