Skip to content

Commit 482fb4b

Browse files
author
Andrew McCluskey
authored
Merge pull request #72 from WG150/packages-intro
Introduction to packages
2 parents 0064bac + cc21c0c commit 482fb4b

3 files changed

Lines changed: 389 additions & 15 deletions

File tree

content/good_practice/custom_modules.ipynb

Lines changed: 264 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,265 @@
44
"cell_type": "markdown",
55
"metadata": {},
66
"source": [
7-
"# Custom modules"
7+
"# Custom Modules"
8+
]
9+
},
10+
{
11+
"cell_type": "markdown",
12+
"metadata": {},
13+
"source": [
14+
"### Pre-requisites\n",
15+
"\n",
16+
"* functions\n",
17+
"* types\n",
18+
"* collections\n",
19+
"* packages"
20+
]
21+
},
22+
{
23+
"cell_type": "markdown",
24+
"metadata": {},
25+
"source": [
26+
"# Modules\n",
27+
"\n",
28+
"Instead of creating one large piece of code that can often be unwieldy we can break it up into smaller chunks, or modules. Modules can be accessed through installed packages or they can written by the user. "
29+
]
30+
},
31+
{
32+
"cell_type": "markdown",
33+
"metadata": {},
34+
"source": [
35+
"## Custom Modules"
36+
]
37+
},
38+
{
39+
"cell_type": "markdown",
40+
"metadata": {},
41+
"source": [
42+
"Below is an example of a custom module (i.e. one we have written ourselves) called `print_things.py`:"
43+
]
44+
},
45+
{
46+
"cell_type": "markdown",
47+
"metadata": {},
48+
"source": [
49+
"```python\n",
50+
"def print_names(list_of_names):\n",
51+
" for name in list_of_names:\n",
52+
" print(name)\n",
53+
"\n",
54+
"def print_dictionary(input_dictionary):\n",
55+
" for key, value in input_dictionary.items():\n",
56+
" print(\"Key: \" + key + \", Value: \" + str(value))\n",
57+
"```"
58+
]
59+
},
60+
{
61+
"cell_type": "markdown",
62+
"metadata": {},
63+
"source": [
64+
"Here, `print_things.py` contains the objects:\n",
65+
"\n",
66+
"* `print_names()` \n",
67+
"* `print_dictionary()`\n",
68+
"\n",
69+
"which are both functions."
70+
]
71+
},
72+
{
73+
"cell_type": "markdown",
74+
"metadata": {},
75+
"source": [
76+
"Great! We have made our module, but how can we go about using it? \n",
77+
"\n",
78+
"Python makes this really simple with the `import` statement. "
79+
]
80+
},
81+
{
82+
"cell_type": "markdown",
83+
"metadata": {},
84+
"source": [
85+
"## Importing Modules\n",
86+
"\n"
87+
]
88+
},
89+
{
90+
"cell_type": "markdown",
91+
"metadata": {},
92+
"source": [
93+
"In order to use our newly created module we need to `import` it into our main script:\n",
94+
"\n",
95+
"```python\n",
96+
"import print_things\n",
97+
"```\n",
98+
"\n",
99+
"Now, we can access the objects in the `print_things` module:\n",
100+
"\n",
101+
"\n",
102+
"\n",
103+
"\n"
104+
]
105+
},
106+
{
107+
"cell_type": "code",
108+
"execution_count": null,
109+
"metadata": {},
110+
"outputs": [],
111+
"source": [
112+
"import print_things\n",
113+
"\n",
114+
"\n",
115+
"element_names = [\"Hydrogen\", \"Helium\", \"Lithium\"]\n",
116+
"element_protons = {\"Hydrogen\": 1, \"Helium\": 2, \"Lithium\": 3}\n",
117+
"\n",
118+
"print_things.print_names(element_names)\n",
119+
"\n",
120+
"print_things.print_dictionary(element_protons)"
121+
]
122+
},
123+
{
124+
"cell_type": "markdown",
125+
"metadata": {},
126+
"source": [
127+
"An alternative to using `import` is to use the `from` statement. This allows us to select certain objects from our module rather than importing all of them in one go:"
128+
]
129+
},
130+
{
131+
"cell_type": "code",
132+
"execution_count": null,
133+
"metadata": {},
134+
"outputs": [],
135+
"source": [
136+
"from print_things import print_names\n",
137+
"\n",
138+
"\n",
139+
"element_names = [\"Hydrogen\", \"Helium\", \"Lithium\"]\n",
140+
"\n",
141+
"print_things.print_names(element_names)"
142+
]
143+
},
144+
{
145+
"cell_type": "markdown",
146+
"metadata": {},
147+
"source": [
148+
"However, if we do want to `import` all objects in our `print_things` module with the `from` statement we can do so like this:\n",
149+
"\n",
150+
"```python\n",
151+
"from print_things import *\n",
152+
"```\n",
153+
"\n",
154+
"Using this style of import, if there are any modules that we don't want to be imported (i.e. that we only want to be used within the module itself), we can prefix them with an underscore (`_`).\n",
155+
"\n",
156+
"```python\n",
157+
"def print_names(list_of_names):\n",
158+
" for name in list_of_names:\n",
159+
" print(name)\n",
160+
"\n",
161+
"def print_dictionary(input_dictionary):\n",
162+
" for key, value in input_dictionary.items():\n",
163+
" print(\"Key: \" + key + \", Value: \" + str(value))\n",
164+
"\n",
165+
"def _private_function():\n",
166+
" print(\"I'm a private function!\")\n",
167+
"```\n",
168+
"\n",
169+
"Here, `_private_function()` can only be used within the `print_things.py` module. We can test this by importing the `print_things.py` module and trying to use it:"
170+
]
171+
},
172+
{
173+
"cell_type": "code",
174+
"execution_count": null,
175+
"metadata": {},
176+
"outputs": [],
177+
"source": [
178+
"# Import all of the functions from the print_things.py module\n",
179+
"from print_things import *\n",
180+
"\n",
181+
"element_names = [\"Hydrogen\", \"Helium\", \"Lithium\"]\n",
182+
"\n",
183+
"# Use the print_names() function \n",
184+
"print_names(element_names)\n",
185+
"\n",
186+
"# Use the _private_function()\n",
187+
"_private_function()"
188+
]
189+
},
190+
{
191+
"cell_type": "markdown",
192+
"metadata": {},
193+
"source": [
194+
"This can be avoided by importing the module in the normal way:"
195+
]
196+
},
197+
{
198+
"cell_type": "code",
199+
"execution_count": null,
200+
"metadata": {},
201+
"outputs": [],
202+
"source": [
203+
"# Import all of the functions from the print_things.py module\n",
204+
"import print_things\n",
205+
"\n",
206+
"element_names = [\"Hydrogen\", \"Helium\", \"Lithium\"]\n",
207+
"\n",
208+
"# Use the print_names() function \n",
209+
"print_things.print_names(element_names)\n",
210+
"\n",
211+
"# Use the _private_function()\n",
212+
"print_things._private_function()"
213+
]
214+
},
215+
{
216+
"cell_type": "markdown",
217+
"metadata": {},
218+
"source": [
219+
"Another useful way to use both the `import` / `from` statements is to `import` modules and use an alternative name:\n",
220+
"\n",
221+
"```python\n",
222+
"from print_things import print_names as pn # Import print_names from the print_things module \n",
223+
"import print_things as pt # Import the whole print_things module\n",
224+
"``` "
225+
]
226+
},
227+
{
228+
"cell_type": "markdown",
229+
"metadata": {},
230+
"source": [
231+
"## Organising Modules: Packages"
232+
]
233+
},
234+
{
235+
"cell_type": "markdown",
236+
"metadata": {},
237+
"source": [
238+
"As a project grows, the number of individual modules may increase and can often be hard to manage. This is where Python packages come in. \n",
239+
"\n",
240+
"Packages are collections of modules contained within a directory. However, in order to make sure this directory is recognised as a package it needs to contain a file named `__init__.py`, this allows it to be imported (just like the `print_things.py` module we created earlier)."
241+
]
242+
},
243+
{
244+
"cell_type": "markdown",
245+
"metadata": {},
246+
"source": [
247+
"For example if we had a package called `pkg` that contained two modules we will name `module2.py` and `module1.py` we could `import` them as:\n",
248+
"\n",
249+
"```python\n",
250+
"import pkg.module1, pkg.module2\n",
251+
"```"
252+
]
253+
},
254+
{
255+
"cell_type": "markdown",
256+
"metadata": {},
257+
"source": [
258+
"### Location"
259+
]
260+
},
261+
{
262+
"cell_type": "markdown",
263+
"metadata": {},
264+
"source": [
265+
"An important point that applies to packages (and by extension modules) is their location. Most of the time a package manager will sort out the location of installed packages so they are useable. Additionally, Python will also look in your current working directory for any [custom packages](https://pythoninchemistry.org/intro_python_chemists/advanced/custom_packages.html). \n"
8266
]
9267
},
10268
{
@@ -17,9 +275,9 @@
17275
],
18276
"metadata": {
19277
"kernelspec": {
20-
"display_name": "Python 3",
278+
"display_name": "Python 3.7.3 64-bit",
21279
"language": "python",
22-
"name": "python3"
280+
"name": "python37364bitd38a54fb656a4d2291427feb2f9b7184"
23281
},
24282
"language_info": {
25283
"codemirror_mode": {
@@ -31,9 +289,9 @@
31289
"name": "python",
32290
"nbconvert_exporter": "python",
33291
"pygments_lexer": "ipython3",
34-
"version": "3.7.3"
292+
"version": "3.7.3-final"
35293
}
36294
},
37295
"nbformat": 4,
38-
"nbformat_minor": 4
39-
}
296+
"nbformat_minor": 2
297+
}

0 commit comments

Comments
 (0)