class Circle:
def __init__(self, radius=1):
self.radius = radius
def area(self):
return self.radius**2*3.14
7 Classes/Packages for Python
7.1 Classes
A class is an abstract structure that can be used to hold both variables and functions. Variables in a class are called attributes, and functions in a class are called methods.
A class is defined in the following way.
In this example, we define a class Circle
, which represents a circle. There is one attribute radius
, and one method area
. When define a cirlce, we need to specify its radius, and we could use the method area
to compute the area of the circle.
= Circle()
cir1 = Circle(radius=5)
cir2
cir1.area()
3.14
cir2.area()
78.5
Here we define two circles. The first circle cir1
is of radius 1
. This 1
comes from the default value. Check the definition of Circle.__init__()
.
The second circle cir2
is of radius 5
, and this number is specified when we initialize the Circle
instance.
Then we compute the areas of these two circles by calling the area()
method. You can also use cir1.radius
to get access the radius of the circle. The syntax difference between attributes and methods is the ()
at the end.
7.1.1 self
You may notice the self
variable in the definition of the classes. The self
is used to refered to the class its. When you want to get access to the class attributes or the class methods, you may use self
.
Take the code as an example.
class Circle:
def __init__(self, radius=1):
self.radius = radius
In the __init__
function, there are two radius
.
radius
is the local variable that is used by the function. It is also the input argument.self.radius
is the class attribute, that is shared by all class methods. For example, we may add another class method to the classCircle
.
class Circle:
def __init__(self, radius=1):
self.radius = radius
def area(self):
return self.radius**2*3.14
def perimeter(self):
return self.radius*3.14*2
Both area()
and perimeter()
use the same self.radius
.
Class attributes are defined in the __init__()
function.
7.1.2 A design example
Assume that we live in a world without Pandas, and we would like to design a table object. Then what do we need?
A table should have multiple rows and multiple columns. We should be able to get access entries by columns and row index. We should also be able to display the table by using the print
funciton.
The .__str__()
method will be called when you try to print
the object. If you don’t explicitly override it, the type of the object will be shown.
Therefore we may write the following class.
class myTableClass():
def __init__(self, listoflist=None):
if listoflist is None:
= [[]]
listoflist self.nrows = len(listoflist)
self.ncols = len(listoflist[0])
self.data = listoflist
self.shape = (self.nrows, self.ncols)
def get(self, i, j):
return self.data[i][j]
def __str__(self):
= [' '.join([str(x) for x in row]) for row in self.data]
tmp return '\n'.join(tmp)
This is a very brief table object. We may add more things to it. For example, we could talk about column names.
class myTableClass():
def __init__(self, listoflist=None, columns=None):
if listoflist is None:
= [[]]
listoflist if columns is None:
= list()
columns self.nrows = len(listoflist)
self.ncols = len(listoflist[0])
self.data = listoflist
self.shape = (self.nrows, self.ncols)
self.columns = columns
def get(self, i, j):
return self.data[i][j]
def rename(self, columns=None):
if columns is not None:
self.columns = columns
def __str__(self):
= [' '.join([str(x) for x in row]) for row in self.data]
tmp if len(self.columns) != 0:
0, self.columns)
tmp.insert(return '\n'.join(tmp)
In Jupyter notebook or similar environment, we might directly call df
to show a DataFrame and the shown DataFrame is rendered very pretty. This is due to the IPython.display.display()
method, and is part of IPython console components.
7.2 Inheritance
One of the most important feature of classes is inheritance. Attributes and methods can be passed from parents to children, and child classes can override those attributes and methods if needed.
For example, we would like to first write a people
class.
class people():
def __init__(self, name='default', age=20):
self.name = name
self.age = age
def eat(self):
print('eat something.')
This people
class defines a people who can eat. Then using this people
class, we could build a children class: student
.
class student(people):
pass
= student('name1', 10)
stu1
stu1.eat() stu1.name
eat something.
'name1'
type(stu1)
__main__.student
Now you can see that this stu1
is a student
, but it has all attributes and methods as a people
. However at current stage student
and people
are exactly the same since we don’t have any new codes for student
. Let us improve it a little bit.
class student(people):
def __init__(self, name='default', age=20, grade=1):
super().__init__(name, age)
self.grade = grade
def eat(self):
print('eat in the cafe.')
= student('name1', 10)
stu1 stu1.eat()
eat in the cafe.
Now student
class override the eat()
method from people
. If someone is a student
, he or she will eat in the cafe instead of just eat something.
In addition, you may also notice that the __init__()
constructor function is also overriden. The first part is super().__init__(name, age)
which is just call the people
’s constructor function. The second part is new in student
, that we add a new attribute grade
to it. Now stu1
have attributes from people
and the new attribute defined in student
.
stu1.name, stu1.age
('name1', 10)
stu1.grade
1
7.3 packages / modules
Main reference is RealPython and [1].
7.3.1 import
In most cases we won’t only write one single Python file. If we want to use codes from other files, we need to import
.
- If both files are in the same folder, e.g.
file1.py
andfile2.py
, you may just putimport file2
infile1.py
, and usefile2.myfunction()
to call functions or variables defined infile2.py
. - If both files are in the same folder, and you just want to use one function from
file1.py
infile2.py
, you mayfrom file1 import myfunction()
, and then directly writemyfunction()
infile2.py
.
Example 7.1 This is from file1.py
.
= "This is from file1.py."
s = [100, 200, 300]
a print(s)
def foo(arg):
print(f'arg = {arg}')
class Foo:
pass
This is from file1.py.
In file2.py
, we could get access to these variables and functions and classes as follows.
import file1
file1.s
'This is from file1.py.'
file1.a
[100, 200, 300]
file1.foo(file1.a)
arg = [100, 200, 300]
file1.Foo()
<assests.codes.file1.Foo at 0x1804b99b100>
An alternative way is to use from <module> import <names>
to directly use the names without the file1.
prefix.
Please see the following Example to get a feel about how namespace works.
Example 7.2
= 'foo'
s = ['foo', 'bar', 'baz']
a
from file1 import s as string, a as alist
s
'foo'
string
'This is from file1.py.'
a
['foo', 'bar', 'baz']
alist
[100, 200, 300]
We may use dir()
to look at all objects in the current namespace.
7.3.2 __name__
__name__
is a variable to tell you want is the current active namespace. See the following example.
Example 7.3
import file1
__name__ file1.
'assests.codes.file1'
The result file1
means that the codes in file1.py
are now treated as a package and are imported into other files.
__name__
'__main__'
The result __main__
means that the codes we are writing now are treated as in the “active” enviroment.
You may see the following codes in a lot of places.
if __name__ == '__main__':
pass
It means that the following codes will only be run in the “active” mode. If you import the codes as a package, these part of codes won’t be run.
7.3.3 Packages
Pacages is a way to group and organize mutliple modules. It allow for a hierachical structuring of the module namespace using dot notation.
Creating a package is straightforward, since it makes use of the operating system’s inherent hierarchical file structure.
Python defines two types of packages, regular packages and namespace packages. The above package is the regular one. Namespace packages allow codes are spread among different folders. We won’t talk about it in this course.
To create a regular package, what you need to do is to organize the files in suitable folders, and then add an __init__.py
in each folder. The file can be empty, or you could add any initialization codes for the package which is represented by the folder.
In the past __init__.py
is required for a package. After Python 3.3 the namespace package is introduced, the __init__.py
is not required (but recommended) for regular packages, and cannot be used for namespace packages.
Let us put the previous file1.py
and file2.py
into subfolder assests/codes/
. To make it into a package assests
and a subpackage codes
, we need to put __init__.py
in each folder.
import assests.codes.file1 as f1
f1.s
'This is from file1.py.'
7.4 Exercieses
Problems are based on [2].
Exercise 7.1 (Heron’s formula) Consider a triangle whose sides are \(a\), \(b\) and \(c\). Heron’s formula states that the area of this triangle is \[\sqrt{s(s−a)(s−b)(s−c)}\quad\text{ where } s=\frac12(a+b+c).\]
Please write a function that given three points computes the area of the triangle with vertices being the given points. The input is required to be a list
of three tuple
s, where each tuple
contains two numbers representing the 2d-coordinate of a point.
Exercise 7.2 (array) Write a function to reverse an 1D NumPy array (first element becomes last).
Exercise 7.3 (Compare two numpy
arraies) Consider two numpy
arraies x
and y
. Compare them entry by entry. We would like to know how many are the same.
Write a function that the inputs are x
and y
, and the output is the number of the same numbers.
Exercise 7.4 (Comma Code) Say you have a list value like this: spam = ['apples', 'bananas', 'tofu', 'cats']
.
Write a function that takes a list value as an argument and returns a string with all the items separated by a comma and a space, with and
inserted before the last item. For example, passing the previous spam
list to the function would return ‘apples, bananas, tofu, and cats’. But your function should be able to work with any list value passed to it. Be sure to test the case where an empty list []
is passed to your function.
Exercise 7.5 Create a Car class with two instance attributes:
.color
, which stores the name of the car’s color as a string..mileage
, which stores the number of miles on the car as an integer.
Then instantiate two Car objects — a blue car with 20,000 miles and a red car with 30,000 miles — and print out their colors and mileage. Your expected output are below:
= mycar(color='blue', mileage=20000)
car1 = mycar(color='red', mileage=30000)
car2
print(car1)
print(car2)
A blue car with 20000 mileage.
A red car with 30000 mileage.
Exercise 7.6 Create a GoldenRetriever
class that inherits from the Dog
class. Give the sound
argument of GoldenRetriever.speak()
a default value of Bark
. Use the following code for your parent Dog
class:
class Dog:
= "Canis familiaris"
species
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} is {self.age} years old"
def speak(self, sound):
return f"{self.name} says {sound}"