Skip to content
Carlos Iriarte

Learning Python | Modules

python, learning3 min read

When we build programs sometimes they get big. The same way we split little pieces of logic with Methods, Functions and Classes we might want to start segregating our code in multiple files, for many reasons, the most common one is to reuse a piece of code that we already wrote. Let's see how all that works.

When we writing the first few programs in earlier posts, we created a file named like cat.py and then keep appending more code at the end of the file.

Let's try to use our file in another program!

Create a new file by opening a terminal and type:

1$ touch main.py

Note: Whenever you see $ at the beginning of commands it means it should be typed in your terminal.

Now let's add the following content to our file:

1import cat

Now let's run our new script:

1$ python main.py
2ฅ^•ﻌ•^ฅ Meoooooooow
3ฅ^•ﻌ•^ฅ Meow
4ฅ^•ﻌ•^ฅ Meoooow
5
6ฅ^•ﻌ•^ฅ Meooooow
7ฅ^•ﻌ•^ฅ Meoow
8ฅ^•ﻌ•^ฅ Meoooooooooow
9
10a == b Not the same Cat!
11
12a == a Same Cat
13
14b == b Same Cat
15
16a == b It's not the same cat!
17
18a == a It's the same cat!

What we're seeing is the output of cat.py. Why is that? When we use other imports we usually don't get this kind of output!

When Python reads our file it starts "interpreting" our statements from top to bottom, line by line. Therefore adding the following line:

1import module_name

Acts as a copying and pasting cat.py in our main.py at the top of the file.

Rad. Except when it's not. Most of the time, what we want to do when reusing code this way is to import the definitions. In our example above we want to get just the Cat definition, but we don't want to execute all those meows.

To do that, we need to go back to the original cat.py and make a few adjustments:

1class Cat:
2 def __init__(self,
3 oos_when_hungry,
4 oos_when_playful,
5 oos_when_open_door):
6 self.oos_when_hungry = oos_when_hungry
7 self.oos_when_playful = oos_when_playful
8 self.oos_when_open_door = oos_when_open_door
9
10 @staticmethod
11 def meow(number_of_os):
12 print("ฅ^•ﻌ•^ฅ Me" + "o" * number_of_os + "w")
13
14 def open_the_door(self):
15 Cat.meow(self.oos_when_open_door)
16
17 def hungry(self):
18 Cat.meow(self.oos_when_hungry)
19
20 def i_wanna_play(self):
21 Cat.meow(self.oos_when_playful)
22
23 def equals(self, other_cat):
24 if self.oos_when_hungry == other_cat.oos_when_hungry and \
25 self.oos_when_playful == other_cat.oos_when_playful and \
26 self.oos_when_open_door == other_cat.oos_when_open_door:
27 return True
28 else:
29 return False
30
31 def __equals__(self, other_cat):
32 return self.equals(other_cat)
33
34
35# Let me tell you about my girly kitty's morning
36a = Cat(1, 4, 8)
37a.open_the_door()
38a.hungry()
39a.i_wanna_play()
40
41print() # Let's add some space for readability. This line has nothing to do with the cats.
42
43# Let me tell you about my big macho kitty
44b = Cat(2, 10, 5)
45b.open_the_door()
46b.hungry()
47b.i_wanna_play()
48
49print() # Let's add some space for readability. This line has nothing to do with the cats.
50
51if a.equals(b):
52 print("a == b Same Cat")
53else:
54 print("a == b Not the same Cat!")
55
56print() # Let's add some space for readability. This line has nothing to do with the cats.
57
58if a.equals(a):
59 print("a == a Same Cat")
60else:
61 print("a == a Not the same Cat!")
62
63print() # Let's add some space for readability. This line has nothing to do with the cats.
64
65if b.equals(b):
66 print("b == b Same Cat")
67else:
68 print("b == b Not the same Cat!")
69
70print() # Let's add some space for readability. This line has nothing to do with the cats.
71
72if a == b:
73 print("a == b It's the same cat!")
74else:
75 print("a == b It's not the same cat!")
76
77print() # Let's add some space for readability. This line has nothing to do with the cats.
78
79if a == a:
80 print("a == a It's the same cat!")
81else:
82 print("a == a It's not the same cat!")

First, let's review what we mean by "definitions":

1

A definition is every time we describe the behavior of a class, a method or a function.

1

Later on, we use these definitions when we instantiate/create objects of the class or when we invoke those methods and functions.

1import cat
2
3# Let me tell you about my girly kitty's morning
4a = Cat(1, 4, 8)
5a.open_the_door()
6a.hungry()
7a.i_wanna_play()
8
9print() # Let's add some space for readability. This line has nothing to do with the cats.
10
11# Let me tell you about my big macho kitty
12b = Cat(2, 10, 5)
13b.open_the_door()
14b.hungry()
15b.i_wanna_play()
16
17print() # Let's add some space for readability. This line has nothing to do with the cats.
18
19if a.equals(b):
20 print("a == b Same Cat")
21else:
22 print("a == b Not the same Cat!")
23
24print() # Let's add some space for readability. This line has nothing to do with the cats.
25
26if a.equals(a):
27 print("a == a Same Cat")
28else:
29 print("a == a Not the same Cat!")
30
31print() # Let's add some space for readability. This line has nothing to do with the cats.
32
33if b.equals(b):
34 print("b == b Same Cat")
35else:
36 print("b == b Not the same Cat!")
37
38print() # Let's add some space for readability. This line has nothing to do with the cats.
39
40if a == b:
41 print("a == b It's the same cat!")
42else:
43 print("a == b It's not the same cat!")
44
45print() # Let's add some space for readability. This line has nothing to do with the cats.
46
47if a == a:
48 print("a == a It's the same cat!")
49else:
50 print("a == a It's not the same cat!")

We can reuse those definitions by "importing" them in our main.py from our cat.py module.

1import cat
2
3# Let me tell you about my girly kitty's morning
4a = Cat(1, 4, 8)
5a.open_the_door()
6a.hungry()
7a.i_wanna_play()
8
9print() # Let's add some space for readability. This line has nothing to do with the cats.
10
11# Let me tell you about my big macho kitty
12b = Cat(2, 10, 5)
13b.open_the_door()
14b.hungry()
15b.i_wanna_play()
16
17print() # Let's add some space for readability. This line has nothing to do with the cats.
18
19if a.equals(b):
20 print("a == b Same Cat")
21else:
22 print("a == b Not the same Cat!")
23
24print() # Let's add some space for readability. This line has nothing to do with the cats.
25
26if a.equals(a):
27 print("a == a Same Cat")
28else:
29 print("a == a Not the same Cat!")
30
31print() # Let's add some space for readability. This line has nothing to do with the cats.
32
33if b.equals(b):
34 print("b == b Same Cat")
35else:
36 print("b == b Not the same Cat!")
37
38print() # Let's add some space for readability. This line has nothing to do with the cats.
39
40if a == b:
41 print("a == b It's the same cat!")
42else:
43 print("a == b It's not the same cat!")
44
45print() # Let's add some space for readability. This line has nothing to do with the cats.
46
47if a == a:
48 print("a == a It's the same cat!")
49else:
50 print("a == a It's not the same cat!")

But what about those extra meows we got when we imported the cat module the first time? Let's go back to cat.py for a moment.

1class Cat:
2 def __init__(self,
3 oos_when_hungry,
4 oos_when_playful,
5 oos_when_open_door):
6 self.oos_when_hungry = oos_when_hungry
7 self.oos_when_playful = oos_when_playful
8 self.oos_when_open_door = oos_when_open_door
9
10 @staticmethod
11 def meow(number_of_os):
12 print("ฅ^•ﻌ•^ฅ Me" + "o" * number_of_os + "w")
13
14 def open_the_door(self):
15 Cat.meow(self.oos_when_open_door)
16
17 def hungry(self):
18 Cat.meow(self.oos_when_hungry)
19
20 def i_wanna_play(self):
21 Cat.meow(self.oos_when_playful)
22
23 def equals(self, other_cat):
24 if self.oos_when_hungry == other_cat.oos_when_hungry and \
25 self.oos_when_playful == other_cat.oos_when_playful and \
26 self.oos_when_open_door == other_cat.oos_when_open_door:
27 return True
28 else:
29 return False
30
31 def __equals__(self, other_cat):
32 return self.equals(other_cat)
33
34
35# Let me tell you about my girly kitty's morning
36a = Cat(1, 4, 8)
37a.open_the_door()
38a.hungry()
39a.i_wanna_play()
40
41print() # Let's add some space for readability. This line has nothing to do with the cats.
42
43# Let me tell you about my big macho kitty
44b = Cat(2, 10, 5)
45b.open_the_door()
46b.hungry()
47b.i_wanna_play()
48
49print() # Let's add some space for readability. This line has nothing to do with the cats.
50
51if a.equals(b):
52 print("a == b Same Cat")
53else:
54 print("a == b Not the same Cat!")
55
56print() # Let's add some space for readability. This line has nothing to do with the cats.
57
58if a.equals(a):
59 print("a == a Same Cat")
60else:
61 print("a == a Not the same Cat!")
62
63print() # Let's add some space for readability. This line has nothing to do with the cats.
64
65if b.equals(b):
66 print("b == b Same Cat")
67else:
68 print("b == b Not the same Cat!")
69
70print() # Let's add some space for readability. This line has nothing to do with the cats.
71
72if a == b:
73 print("a == b It's the same cat!")
74else:
75 print("a == b It's not the same cat!")
76
77print() # Let's add some space for readability. This line has nothing to do with the cats.
78
79if a == a:
80 print("a == a It's the same cat!")
81else:
82 print("a == a It's not the same cat!")

You can prevent executing those statements by checking if the file cat.py was invoked as a module or as a script by checking its name.

1class Cat:
2 def __init__(self,
3 oos_when_hungry,
4 oos_when_playful,
5 oos_when_open_door):
6 self.oos_when_hungry = oos_when_hungry
7 self.oos_when_playful = oos_when_playful
8 self.oos_when_open_door = oos_when_open_door
9
10 @staticmethod
11 def meow(number_of_os):
12 print("ฅ^•ﻌ•^ฅ Me" + "o" * number_of_os + "w")
13
14 def open_the_door(self):
15 Cat.meow(self.oos_when_open_door)
16
17 def hungry(self):
18 Cat.meow(self.oos_when_hungry)
19
20 def i_wanna_play(self):
21 Cat.meow(self.oos_when_playful)
22
23 def equals(self, other_cat):
24 if self.oos_when_hungry == other_cat.oos_when_hungry and \
25 self.oos_when_playful == other_cat.oos_when_playful and \
26 self.oos_when_open_door == other_cat.oos_when_open_door:
27 return True
28 else:
29 return False
30
31 def __equals__(self, other_cat):
32 return self.equals(other_cat)
33
34
35if __name__ == "__main__":
36 # Let me tell you about my girly kitty's morning
37 a = Cat(1, 4, 8)
38 a.open_the_door()
39 a.hungry()
40 a.i_wanna_play()
41
42 print() # Let's add some space for readability. This line has nothing to do with the cats.
43
44 # Let me tell you about my big macho kitty
45 b = Cat(2, 10, 5)
46 b.open_the_door()
47 b.hungry()
48 b.i_wanna_play()
49
50 print() # Let's add some space for readability. This line has nothing to do with the cats.
51
52 if a.equals(b):
53 print("a == b Same Cat")
54 else:
55 print("a == b Not the same Cat!")
56
57 print() # Let's add some space for readability. This line has nothing to do with the cats.
58
59 if a.equals(a):
60 print("a == a Same Cat")
61 else:
62 print("a == a Not the same Cat!")
63
64 print() # Let's add some space for readability. This line has nothing to do with the cats.
65
66 if b.equals(b):
67 print("b == b Same Cat")
68 else:
69 print("b == b Not the same Cat!")
70
71 print() # Let's add some space for readability. This line has nothing to do with the cats.
72
73 if a == b:
74 print("a == b It's the same cat!")
75 else:
76 print("a == b It's not the same cat!")
77
78 print() # Let's add some space for readability. This line has nothing to do with the cats.
79
80 if a == a:
81 print("a == a It's the same cat!")
82 else:
83 print("a == a It's not the same cat!")

You achieve that by checking the special variable __name__ and compare it to the string "__main__". Don't forget to indent the code that instantiates and tests the code to match the if statement in your condition.

Let's take a look at a module we didn't write: jira. Let's install that module first:

Note: make sure you run the steps in setting up your development environment

1$ pipenv run pip install jira
1from jira import JIRA
2
3options = {"server": "https://jira.atlassian.com"}
4jira = JIRA(options)
5
6# Get all projects viewable by anonymous users.
7projects = jira.projects()
8
9print(projects)

Let's analyze the following code line by line:

1

From the jira module, get the JIRA class definition.

1

Construct a dictionary (a dict object) with key server and value https://jira.atlassian.com, and assign the value to the options variable.

1

With those options, instantiate a jira object from the JIRA class.

1

Invoke the projects function from my new jira object and assign the results to the projects variable.

1

Print the object projects.

1

But... how does python know where to find the jira module. What does it mean "to install it"?

If you compare the jira example from above to our cat module example. One important difference is that cat.py was located in the same directory as our main.py file.

Like most programming languages, Python cares where you place your files, and it follows a series of rules to find modules. You can read more about those rules here.

I'll try to simplify what that page says here:

Note: you can modify this behavior but that's a bit out of scope for this tutorial.

  1. It looks for built-in functions.
  2. It looks for modules in your current working directory (this is how it found cat.py!)
  3. It looks at the python installation folder (your site-packages).

i.e. installing the jira module means to get the files from some location on the internet and placing them in the right location in your computer.

Now that we know that, the really cool fact is that the JIRA class we're using in our code is not that special. Someone else wrote it, published it in pypi.org and made it available for everyone.

When we ran:

1$ pipenv run pip install jira

the command pipenv just helped us to place all those bits we downloaded in the right place.

You can even learn how jira was implemented (which is just a fancy word to say "coded" or "written")

You can read how the JIRA class has an __init__ method. Or the projects function.