├── .gitignore
├── Wk06
├── 02-template
│ ├── templates
│ │ └── index.html
│ └── site.py
├── 06-storing-input
│ ├── test.db
│ ├── templates
│ │ └── index.html
│ └── site.py
├── 01-framework
│ └── site.py
├── 03-html
│ ├── templates
│ │ └── index.html
│ └── site.py
├── 04-uri-attributes
│ ├── templates
│ │ ├── index.html
│ │ └── custom.html
│ └── site.py
└── 05-user-input
│ ├── templates
│ ├── custom.html
│ └── index.html
│ └── site.py
├── Wk07
├── clustering.png
├── regression.png
├── classification.png
├── feature-selection.png
├── classification-data.png
├── density-estimation.png
├── workspace.py
└── model_and_algorithms.py
├── Wk10
├── clustering.png
└── plot_cluster_comparison_001.png
├── Wk05
├── Wk05-wsgi.py
├── workspace.py
├── ingredient_recipe_interface.py
└── Wk05-OOP-Public-interface-Solution.ipynb
├── Wk02
├── tsp_solver.py
├── tsp_solver_pep8.py
├── tsp_solver_doc.py
├── workspace.py
├── simulated_annealing_optimizer.py
└── genetic_algorithm_optimizer.py
├── LICENSE
├── Wk04
├── Wk04_matplotlib_gui.py
├── Wk04-GUI.ipynb
└── Wk04-OOP-Inheritance-abstraction.ipynb
├── Wk03
├── lpthw_ex43.py
├── cookbook.py
└── Wk03-Paradigms.ipynb
├── README.md
└── Wk01
├── Wk01-Overview.ipynb
└── .ipynb_checkpoints
└── Wk01-Overview-checkpoint.ipynb
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 |
--------------------------------------------------------------------------------
/Wk06/02-template/templates/index.html:
--------------------------------------------------------------------------------
1 | Hello, World
--------------------------------------------------------------------------------
/Wk07/clustering.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brienna/BIOF509/HEAD/Wk07/clustering.png
--------------------------------------------------------------------------------
/Wk07/regression.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brienna/BIOF509/HEAD/Wk07/regression.png
--------------------------------------------------------------------------------
/Wk10/clustering.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brienna/BIOF509/HEAD/Wk10/clustering.png
--------------------------------------------------------------------------------
/Wk07/classification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brienna/BIOF509/HEAD/Wk07/classification.png
--------------------------------------------------------------------------------
/Wk07/feature-selection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brienna/BIOF509/HEAD/Wk07/feature-selection.png
--------------------------------------------------------------------------------
/Wk07/classification-data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brienna/BIOF509/HEAD/Wk07/classification-data.png
--------------------------------------------------------------------------------
/Wk07/density-estimation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brienna/BIOF509/HEAD/Wk07/density-estimation.png
--------------------------------------------------------------------------------
/Wk06/06-storing-input/test.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brienna/BIOF509/HEAD/Wk06/06-storing-input/test.db
--------------------------------------------------------------------------------
/Wk10/plot_cluster_comparison_001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brienna/BIOF509/HEAD/Wk10/plot_cluster_comparison_001.png
--------------------------------------------------------------------------------
/Wk06/01-framework/site.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 |
3 | app = Flask(__name__)
4 |
5 | @app.route('/')
6 | def index():
7 | return 'Hello, World'
8 |
9 | if __name__ == '__main__':
10 | app.run()
11 |
--------------------------------------------------------------------------------
/Wk06/03-html/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello
4 |
7 |
8 |
9 |
10 | Hello, World
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Wk06/04-uri-attributes/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello
4 |
7 |
8 |
9 |
10 | Hello, World
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Wk06/05-user-input/templates/custom.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello
4 |
7 |
8 |
9 |
10 | Hello, World
11 | {{ custom }}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Wk06/02-template/site.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask(__name__)
4 |
5 | @app.route('/')
6 | def index():
7 | return render_template('index.html')
8 |
9 | if __name__ == '__main__':
10 | app.run(debug=True)
11 |
--------------------------------------------------------------------------------
/Wk06/04-uri-attributes/templates/custom.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello
4 |
7 |
8 |
9 |
10 | Hello, World
11 | {{ custom }}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Wk06/03-html/site.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask(__name__)
4 |
5 | @app.route('/')
6 | def index():
7 | return render_template('index.html')
8 |
9 | if __name__ == '__main__':
10 | app.run(debug=True)
11 |
--------------------------------------------------------------------------------
/Wk06/04-uri-attributes/site.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask(__name__)
4 |
5 | @app.route('/')
6 | def index():
7 | return render_template('index.html')
8 |
9 | @app.route('/custom//')
10 | def custom(custom):
11 | return render_template('custom.html', custom=custom)
12 |
13 | if __name__ == '__main__':
14 | app.run(debug=True)
15 |
--------------------------------------------------------------------------------
/Wk06/05-user-input/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello
4 |
7 |
8 |
9 |
10 | Hello, {{ name }}
11 |
12 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Wk05/Wk05-wsgi.py:
--------------------------------------------------------------------------------
1 | from wsgiref.simple_server import make_server
2 |
3 |
4 | def simple_app(environ, start_response):
5 | """A simple WSGI application"""
6 | status = '200 OK'
7 | headers = [('Content-type', 'text/plain; charset=utf-8')]
8 |
9 | start_response(status, headers)
10 |
11 | return ["Hello World\n".encode('utf-8')]
12 |
13 | if __name__ == '__main__':
14 | httpd = make_server('', 8000, simple_app)
15 | print("Serving on port 8000...")
16 | httpd.serve_forever()
17 |
--------------------------------------------------------------------------------
/Wk02/tsp_solver.py:
--------------------------------------------------------------------------------
1 | import itertools
2 |
3 | def distance(coords):
4 | distance = 0
5 | for p1, p2 in zip(coords[:-1], coords[1:]):
6 | distance += ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
7 | return distance
8 |
9 | def find_best_route(coords):
10 | best_distance = distance(coords)
11 | best = coords
12 | for option in itertools.permutations(coords, len(coords)):
13 | option_distance = distance(option)
14 | if option_distance < best_distance:
15 | best = option
16 | best_distance = option_distance
17 | return (best_distance, best)
18 |
--------------------------------------------------------------------------------
/Wk02/tsp_solver_pep8.py:
--------------------------------------------------------------------------------
1 | import itertools
2 |
3 |
4 | def distance(coords):
5 | distance = 0
6 | for p1, p2 in zip(coords[:-1], coords[1:]):
7 | distance += ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
8 | return distance
9 |
10 |
11 | def find_best_route(coords):
12 | best_distance = distance(coords)
13 | best = coords
14 | for option in itertools.permutations(coords, len(coords)):
15 | option_distance = distance(option)
16 | if option_distance < best_distance:
17 | best = option
18 | best_distance = option_distance
19 | return (best_distance, best)
20 |
--------------------------------------------------------------------------------
/Wk06/06-storing-input/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello
4 |
7 |
8 |
9 |
10 | Hello, {{ first_name }}
11 |
12 |
18 |
19 | Previous Visitors
20 |
21 | {% for visitor in previous_visitors %}
22 | - {{ visitor.first_name + " " + visitor.last_name }}
23 | {% endfor %}
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Wk06/05-user-input/site.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask(__name__)
4 |
5 | app.config['SECRET_KEY'] = 'important to keep unknown in production'
6 |
7 | from flask_wtf import Form
8 | from wtforms import StringField
9 | from wtforms.validators import DataRequired
10 |
11 |
12 |
13 |
14 | class MyForm(Form):
15 | name = StringField('name', validators=[DataRequired()])
16 |
17 |
18 | @app.route('/', methods=('GET', 'POST'))
19 | def index():
20 | form = MyForm()
21 | if form.validate_on_submit():
22 | name = form.name.data
23 | else:
24 | name = 'stranger'
25 | return render_template('index.html', form=form, name=name)
26 |
27 | @app.route('/custom//')
28 | def custom(custom):
29 | return render_template('custom.html', custom=custom)
30 |
31 | if __name__ == '__main__':
32 | app.run(debug=True)
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Jonathan Street
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Wk02/tsp_solver_doc.py:
--------------------------------------------------------------------------------
1 | """Module to find the shortest path connecting a set of points
2 |
3 | find_best_route accepts a set of coordinates and will return the shortest
4 | route."""
5 | import itertools
6 |
7 |
8 | def distance(coords):
9 | """Calculates the distance of a path between multiple points
10 |
11 | Arguments:
12 | coords -- List of coordinates, e.g. [(0,0), (1,1)]
13 |
14 | Returns: Total distance as a float
15 | """
16 | distance = 0
17 | for p1, p2 in zip(coords[:-1], coords[1:]):
18 | distance += ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
19 | return distance
20 |
21 |
22 | def find_best_route(coords):
23 | """Find the shortest path between a set of points
24 |
25 | Arguments:
26 | coords -- List of coordinates, e.g. [(0,0), (1,1)]
27 |
28 | Returns: Tuple of shortest distance and the route
29 | """
30 | best_distance = distance(coords)
31 | best = coords
32 | for option in itertools.permutations(coords, len(coords)):
33 | option_distance = distance(option)
34 | if option_distance < best_distance:
35 | best = option
36 | best_distance = option_distance
37 | return (best_distance, best)
38 |
--------------------------------------------------------------------------------
/Wk04/Wk04_matplotlib_gui.py:
--------------------------------------------------------------------------------
1 | """
2 | Do a mouseclick somewhere, move the mouse to some destination, release
3 | the button. This class gives click- and release-events and also draws
4 | a line or a box from the click-point to the actual mouseposition
5 | (within the same axes) until the button is released. Within the
6 | method 'self.ignore()' it is checked wether the button from eventpress
7 | and eventrelease are the same.
8 |
9 | """
10 | from matplotlib.widgets import RectangleSelector
11 | import matplotlib.pyplot as plt
12 | import matplotlib.cbook as cbook
13 |
14 |
15 | def line_select_callback(eclick, erelease):
16 | 'eclick and erelease are the press and release events'
17 | x1, y1 = eclick.xdata, eclick.ydata
18 | x2, y2 = erelease.xdata, erelease.ydata
19 | print ("(%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1, x2, y2))
20 | print (" The button you used were: %s %s" % (eclick.button, erelease.button))
21 |
22 |
23 | def toggle_selector(event):
24 | print (' Key pressed.')
25 | if event.key in ['Q', 'q'] and toggle_selector.RS.active:
26 | print (' RectangleSelector deactivated.')
27 | toggle_selector.RS.set_active(False)
28 | if event.key in ['A', 'a'] and not toggle_selector.RS.active:
29 | print (' RectangleSelector activated.')
30 | toggle_selector.RS.set_active(True)
31 |
32 |
33 |
34 | image_file = cbook.get_sample_data('grace_hopper.png')
35 | image = plt.imread(image_file)
36 | fig, current_ax = plt.subplots()
37 | plt.imshow(image)
38 | toggle_selector.RS = RectangleSelector(current_ax,
39 | line_select_callback,
40 | drawtype='box', useblit=True,
41 | button=[1,3], # don't use middle button
42 | minspanx=5, minspany=5,
43 | spancoords='pixels')
44 | plt.connect('key_press_event', toggle_selector)
45 | plt.show()
46 |
--------------------------------------------------------------------------------
/Wk05/workspace.py:
--------------------------------------------------------------------------------
1 | from ingredient_recipe_interface import Ingredient, Recipe
2 |
3 |
4 | bread = Recipe('Bread', [(820, Ingredient('Flour', 0.77, 0.10, 0.01)),
5 | (30, Ingredient('Oil', 0, 0, 1)),
6 | (36, Ingredient('Sugar', 1, 0, 0)),
7 | (7, Ingredient('Yeast', 0.3125, 0.5, 0.0625)),
8 | (560, Ingredient('Water', 0, 0, 0))])
9 | print(bread.ingredients)
10 | # Should be roughly [(820, Ingredient(Flour, 0.77, 0.1, 0.01)), (30, Ingredient(Oil, 0, 0, 1)),
11 | # (36, Ingredient(Sugar, 1, 0, 0)), (7, Ingredient(Yeast, 0.3125, 0.5, 0.0625)), (560, Ingredient(Water, 0, 0, 0))]
12 |
13 | print(bread.nutrition)
14 | #Should be roughly {'carbs': 669.5875, 'protein': 85.5, 'fat': 38.6375} the order is not important
15 |
16 | #Points to note:
17 | # - The different call to Ingredient, you can use isinstance or type to change the
18 | # behaviour depending on the arguments supplied
19 | # - Cholesterol as an extra nutrient, your implementation should accept any nutrient
20 | # - Use of Recipe (bread) as an ingredient
21 | basic_french_toast = Recipe('Basic French Toast', [(300, Ingredient('Egg', {'carbs': 0.0077, 'protein': 0.1258,
22 | 'fat': 0.0994, 'cholesterol': 0.00423})),
23 | (0.25, bread)])
24 | print(basic_french_toast.ingredients)
25 | # Should be roughly:
26 | # [(300, Ingredient(Egg, 0.0077, 0.1258, 0.0994)), (0.25, Recipe(Bread, [(820, Ingredient(Flour, 0.77, 0.1, 0.01)),
27 | # (30, Ingredient(Oil, 0, 0, 1)), (36, Ingredient(Sugar, 1, 0, 0)), (7, Ingredient(Yeast, 0.3125, 0.5, 0.0625)),
28 | # (560, Ingredient(Water, 0, 0, 0))]))]
29 | # Note the formatting for the Recipe object, a __repr__ method will be needed
30 |
31 | print(basic_french_toast.nutrition)
32 | # Should be roughly {'protein': 59.115, 'carbs': 169.706875, 'cholesterol': 1.2690000000000001, 'fat': 39.479375000000005}
33 | # The order is not important
--------------------------------------------------------------------------------
/Wk07/workspace.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 | from model_and_algorithms import Model, RCT, EpsilonGreedy, EpsilonDecrease
3 |
4 |
5 | # plot RCT algorithm
6 | model = Model(RCT, {'n_arms': 2, 'epsilon':0.05}, weights=[0.1, 0.2])
7 | model.repeat_simulation()
8 |
9 | fig, axes = plt.subplots(1,3, figsize=(18,6))
10 | plt.suptitle("Performance of RCT and EpsilonGreedy algorithms", fontsize=20)
11 |
12 | model.plot_arm_frequency(ax=axes[0])
13 | model.plot_reward(ax=axes[1])
14 | model.plot_cumulative_reward(ax=axes[2])
15 |
16 |
17 | # plot EpsilonGreedy algorithm on same plots as RCT algorithm
18 | model = Model(EpsilonGreedy, {'n_arms': 2, 'epsilon':0.05}, weights=[0.1, 0.2])
19 | model.repeat_simulation()
20 |
21 | model.plot_arm_frequency(ax=axes[0], colour='red')
22 | model.plot_reward(ax=axes[1], colour='red')
23 | model.plot_cumulative_reward(ax=axes[2], colour='red')
24 |
25 |
26 |
27 |
28 | # plot different Epsilon values
29 | fig, axes = plt.subplots(1, 3, figsize=(18,6))
30 | plt.suptitle("Performance of EpsilonGreedy algorithm with different epsilon values", fontsize=20)
31 |
32 | colors = ['red', 'orange', 'yellow', 'blue', 'purple', 'black']
33 | epsilon_values = [1, 0.9, 0.6, 0.4, 0.2, 0.01]
34 | for color, value in zip(colors, epsilon_values):
35 | model = Model(EpsilonGreedy, {'n_arms': 2, 'epsilon':value}, weights=[0.1, 0.2])
36 | model.repeat_simulation()
37 | model.plot_arm_frequency(ax=axes[0], colour=color)
38 | model.plot_reward(ax=axes[1], colour=color)
39 | model.plot_cumulative_reward(ax=axes[2], colour=color)
40 |
41 |
42 |
43 |
44 | # plot EpsilonDecrease algorithm
45 | fig, axes = plt.subplots(1, 3, figsize=(18,6))
46 | plt.suptitle("Performance of EpsilonGreedy algorithm, reducing epsilon value over time", fontsize=20)
47 |
48 | model = Model(EpsilonDecrease, {'n_arms': 2, 'epsilon':1}, weights=[0.1, 0.2])
49 | model.repeat_simulation()
50 |
51 | model.plot_arm_frequency(ax=axes[0])
52 | model.plot_reward(ax=axes[1])
53 | model.plot_cumulative_reward(ax=axes[2])
54 |
55 | plt.show()
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/Wk02/workspace.py:
--------------------------------------------------------------------------------
1 |
2 | import timeit
3 | import matplotlib.pyplot as plt
4 | from simulated_annealing_optimizer import distance, new_path, new_path_modified, simulated_annealing_optimizer
5 | from genetic_algorithm_optimizer import new_path, distance, genetic_algorithm_optimizer, recombine, select_best
6 |
7 |
8 | coords = [(0,0), (10,5), (10,10), (5,10), (3,3), (3,7), (12,3), (10,11)]
9 |
10 | ###################################
11 | # simulated annealing algorithm #
12 | ###################################
13 | best_path, best_cost, history = simulated_annealing_optimizer(coords, distance, new_path_modified, 1000, 0.01, 1000)
14 | print('simulated annealing algorithm best cost: ', best_cost)
15 |
16 | ## plot cost for each path tested with simulated annealing algorithm
17 | plt.plot([i['current_cost'] for i in history])
18 | plt.show()
19 |
20 | # plot coordinates of best path calculated with simulated annealing algorithm
21 | plt.plot([i[0] for i in best_path], [i[1] for i in best_path])
22 | plt.show()
23 |
24 |
25 | # test to determine if new_path_modified improves performance of simulated annealing algorithm
26 | # there is not a significant difference, new_path_modified may even be worse
27 | def wrapper(func, *args, **kwargs):
28 | def wrapped():
29 | return func(*args, **kwargs)
30 | return wrapped
31 |
32 | new_path_modified_test = wrapper(simulated_annealing_optimizer, coords, distance, new_path_modified, 1000, 0.01, 1000)
33 | new_path_test = wrapper(simulated_annealing_optimizer, coords, distance, new_path, 1000, 0.01, 1000)
34 |
35 | time_npm = timeit.timeit(new_path_modified_test, number = 100)
36 | time_np = timeit.timeit(new_path_test, number = 100)
37 | print('new_path_modified time: ', time_npm)
38 | print('new_path time: ', time_np)
39 |
40 |
41 | #######################
42 | # genetic algorithm #
43 | #######################
44 | best_path, best_cost, history = genetic_algorithm_optimizer(coords, distance, new_path, 500, 100)
45 | print('genetic algorithm best cost: ', best_cost)
46 |
47 | # plot cost for each path tested with genetic algorithm
48 | plt.plot([i['current_cost'] for i in history])
49 | plt.show()
50 |
51 | # plot coordinates of best path calculated with genetic algorithm
52 | plt.plot([i[0] for i in best_path], [i[1] for i in best_path])
53 | plt.show()
54 |
55 |
--------------------------------------------------------------------------------
/Wk03/lpthw_ex43.py:
--------------------------------------------------------------------------------
1 | # Learn Python The Hard Way
2 | # Exercise 43: Basic Object-Oriented Analysis and Design
3 | # http://learnpythonthehardway.org/book/ex43.html
4 |
5 | # Aliens have invaded a space ship and our hero has to go through a maze
6 | # of rooms defeating them so he can escape into an escape pod to the planet
7 | # below. The game will be more like a Zork or Adventure type game with text
8 | # outputs and funny ways to die. The game will involve an engine that runs
9 | # a map full of rooms or scenes. Each room will print its own description
10 | # when the player enters it and then tell the engine what room to run next
11 | # out of the map.
12 |
13 | # Scenes:
14 | # Death: This is when the player dies and should be something funny.
15 |
16 | # Central Corridor: This is the starting point and has a Gothon already
17 | # standing there they have to defeat with a joke before continuing.
18 |
19 | # Laser Weapon Armory: This is where the hero gets a neutron bomb to blow
20 | # up the ship before getting to the escape pod. It has a keypad the hero
21 | # has to guess the number for.
22 |
23 | # The Bridge: Another battle scene with a Gothon where the hero places
24 | # the bomb.
25 |
26 | # Escape Pod: Where the hero escapes but only after guessing the right
27 | # escape pod.
28 |
29 |
30 | class Map(object): # inherits from the class 'object'
31 |
32 | def __init__(self, start_scene): # necessary for instantiation below
33 | pass
34 |
35 | def next_scene(self, scene_name):
36 | pass
37 |
38 | def opening_scene(self):
39 | pass
40 |
41 |
42 | class Engine(object): # inherits from the class 'object'
43 |
44 | def __init__(self, scene_map): # necessary for instantiation below
45 |
46 | def play(self):
47 | pass
48 |
49 |
50 | class Scene(object): # inherits from the class 'object'
51 |
52 | def enter(self):
53 | pass
54 |
55 |
56 | class Death(Scene): # inherits from the class 'Scene'
57 |
58 | def enter(self): # override parent method
59 | pass
60 |
61 |
62 | class CentralCorridor(Scene): # inherits from the class 'Scene'
63 |
64 | def enter(self): # override parent method
65 | pass
66 |
67 |
68 | class LaserWeaponArmory(Scene): # inherits from the class 'Scene'
69 |
70 | def enter(self): # override parent method
71 | pass
72 |
73 |
74 | class TheBridge(Scene): # inherits from the class 'Scene'
75 |
76 | def enter(self): # override parent method
77 | pass
78 |
79 |
80 | class EscapePod(Scene): # inherits from the class 'Scene'
81 |
82 | def enter(self): # override parent method
83 | pass
84 |
85 |
86 | a_map = Map('central_corridor') # instantiate Map object
87 | a_game = Engine(a_map) # instantiate Engine object, passing Map instance
88 | a_game.play()
89 |
90 |
--------------------------------------------------------------------------------
/Wk06/06-storing-input/site.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template
2 |
3 | app = Flask(__name__)
4 |
5 | app.config['SECRET_KEY'] = 'important to keep unknown in production'
6 |
7 | from flask_wtf import Form
8 | from wtforms import StringField
9 | from wtforms.validators import DataRequired
10 |
11 |
12 |
13 |
14 | class MyForm(Form):
15 | """A class definition for a form object.
16 |
17 | Attributes:
18 | first_name (object)
19 | last_name (object)
20 | """
21 | first_name = StringField('First name:', validators=[DataRequired()])
22 | last_name = StringField('Last name:', validators=[DataRequired()])
23 | # Fields are responsible for rendering and data conversion
24 | # They delegate to optional validators for data validation
25 | # StringField is the base for most of the more complicated fields,
26 | # and it represents
27 | # DataRequired checks that the data attribute on the field is a ‘true’ value
28 |
29 |
30 | from flask_sqlalchemy import SQLAlchemy
31 |
32 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
33 | db = SQLAlchemy(app) # create database
34 | db.create_all() # create all tables (will not recreate tables already present in database)
35 |
36 |
37 | class Visitor(db.Model):
38 | """A class definition for a visitor MetaData object.
39 |
40 | Attributes (initalized in __init__):
41 | first_name (string)
42 | last_name (string)
43 |
44 | """
45 | # create columns for database table (not yet set)
46 | id = db.Column(db.Integer, primary_key=True)
47 | first_name = db.Column(db.String(80))
48 | last_name = db.Column(db.String(80))
49 |
50 |
51 | def __init__(self, first_name, last_name):
52 | self.first_name = first_name
53 | self.last_name = last_name
54 |
55 |
56 | def __repr__(self):
57 | return ''.format(self.first_name, self.last_name)
58 |
59 |
60 | @app.route('/', methods=('GET', 'POST'))
61 | def index():
62 | """Process form for each visitor and return rendered HTML."""
63 |
64 | form = MyForm()
65 | previous_visitors = Visitor.query.order_by('id DESC').all()
66 |
67 | # check if form submission is a valid POST request
68 | if form.validate_on_submit():
69 | first_name = form.first_name.data # retrieve first name from form
70 | last_name = form.last_name.data # retrieve last name from form
71 | db.session.add(Visitor(first_name, last_name)) # set columns in database table
72 | db.session.commit() # write changes to the database
73 | else:
74 | first_name = 'stranger'
75 | last_name = None
76 |
77 | return render_template('index.html', form=form, first_name=first_name, last_name=last_name, previous_visitors=previous_visitors)
78 |
79 |
80 | if __name__ == '__main__':
81 | app.run(debug=True)
82 |
--------------------------------------------------------------------------------
/Wk05/ingredient_recipe_interface.py:
--------------------------------------------------------------------------------
1 | class Ingredient(object):
2 | """The ingredient object that contains nutritional information"""
3 |
4 | def __init__(self, name, *args):
5 | self.name = name
6 |
7 | values = []
8 | nutrients = ['carbs', 'protein', 'fat', 'cholesterol']
9 |
10 | for arg in args:
11 | # if argument is a dict, assign it as instance attribute
12 | if isinstance(arg, dict):
13 | self.nutrition = arg
14 | # if argument isn't a dict, add argument to list
15 | else:
16 | values.append(arg)
17 |
18 | # if non-dict arguments were added to list, set them as instance attributes
19 | if len(values) > 0:
20 | self.nutrition = {}
21 | for nutrient, value in zip(nutrients, values):
22 | self.nutrition[nutrient] = value
23 |
24 |
25 | def __repr__(self):
26 | # if instance contains 'cholesterol' attribute, include it in str representation
27 | return 'Ingredient({0}, {1})'.format(self.name, self.nutrition)
28 |
29 |
30 | def get_nutrition(self):
31 | """Returns the nutritional information for the ingredient"""
32 | return (self.nutrition)
33 |
34 |
35 | class Recipe(object):
36 | """The Recipe object containing the ingredients"""
37 |
38 | def __init__(self, name, ingredients,):
39 | self.name = name
40 | self.ingredients = ingredients
41 |
42 |
43 | def __repr__(self):
44 | return 'Recipe({0}, {1})'.format(self.name, self.ingredients)
45 |
46 |
47 | def get_nutrition(self):
48 | """Returns the nutritional information for the recipe"""
49 | nutrition = [0, 0, 0]
50 | carbs = 0
51 | protein = 0
52 | fat = 0
53 | cholesterol = 0
54 | nutrition_cholesterol = 0
55 | for amount, ingredient in self.ingredients:
56 | # if ingredient is a Recipe instance
57 | if isinstance(ingredient, Recipe):
58 | ingredient = ingredient.ingredients # update ingredient to recipe's ingredients
59 | for amt, ing in ingredient:
60 | # print('ingredient within recipe: ', ing)
61 | carbs += amt * ing.carbs
62 | protein += amt * ing.protein
63 | fat += amt * ing.fat
64 | if hasattr(ing, 'cholesterol'):
65 | cholesterol += amt * ing.cholesterol
66 | nutrition[0] += amount * carbs
67 | nutrition[1] += amount * protein
68 | nutrition[2] += amount * fat
69 | nutrition_cholesterol += amount * cholesterol
70 | # if ingredient is an Ingredient instance
71 | else:
72 | # print('ingredient: ', ingredient)
73 | nutrition[0] += amount * ingredient.carbs
74 | nutrition[1] += amount * ingredient.protein
75 | nutrition[2] += amount * ingredient.fat
76 | if hasattr(ingredient, 'cholesterol'):
77 | nutrition_cholesterol += amount * ingredient.cholesterol
78 |
79 | # if cholesterol nutrition info has been supplied, append to list
80 | if nutrition_cholesterol > 0:
81 | nutrition.append(nutrition_cholesterol)
82 | return nutrition
83 |
84 |
85 | @property
86 | def nutrition(self):
87 | info = self.get_nutrition()
88 | nutrients = {}
89 | nutrients['carbs'] = info[0]
90 | nutrients['protein'] = info[1]
91 | nutrients['fat'] = info[2]
92 | # if info consists of more than carbs, protein, fat, add to nutrients dict
93 | if len(info) > 3:
94 | nutrients['cholesterol'] = info[3]
95 | return nutrients
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/Wk03/cookbook.py:
--------------------------------------------------------------------------------
1 |
2 | class Cookbook(object):
3 | """A class definition for a cookbook. The following attributes are supported:
4 |
5 | Attributes:
6 | name: A string representing the Cookbook's name
7 | recipes: A list of recipe objects"""
8 |
9 | def __init__(self, name):
10 | """Initalize a Cookbook object with name set to the value supplied, and initialize recipes array"""
11 | self.name = name
12 | self.recipes = []
13 |
14 | def open(self, recipe_name):
15 | """Return a recipe.
16 |
17 | Arguments received:
18 | recipe_name -- string representing the recipe name
19 | """
20 | for i in range(len(self.recipes)):
21 | if self.recipes[i].name == recipe_name:
22 | return self.recipes[i]
23 |
24 | def add(self, recipe):
25 | '''Append recipe object to Cookbook instance's recipes array
26 |
27 | Arguments received:
28 | recipe -- the recipe object to append
29 | '''
30 | self.recipes.append(recipe)
31 |
32 |
33 | class Recipe():
34 | """A class definition for a recipe. The following attributes are supported:
35 |
36 | Attributes:
37 | name: a string representing the recipe's name
38 | ingredients: a dictionary of ingredients the recipe needs
39 | equipment: a list of equipment the recipe needs
40 | instructions: a string representing the instructions
41 | servings: an integer representing the number of people the recipe can serve
42 | nutrition_info: a dictionary of nutrition info for each ingredient
43 | cooking_time: a float representing cooking time in minutes
44 | """
45 |
46 | def __init__(self, name, ingredients, equipment, instructions, servings, cooking_time):
47 | """Initialize a Recipe object with name, ingredients, equipment, instructions,
48 | servings, nutrition_info, prep_time, cooking_time set to the values supplied"""
49 | self.name = name
50 | self.ingredients = ingredients
51 | self.equipment = equipment
52 | self.instructions = instructions
53 | self.servings = servings
54 | # self.nutrition_info, loops thru ingredients dict to retrieve nutrition info from each ingredient
55 | self.cooking_time = cooking_time
56 |
57 | def __str__(self):
58 | """Return a basic string representation of the Recipe instance"""
59 | return "Recipe: {0}.\nServes {1}.\nIngredients: {2}.\nInstructions: {3}.\nCooking time: {4} min.".format(self.name, self.servings, self.ingredients, self.instructions, self.cooking_time)
60 |
61 |
62 | class Ingredient(object):
63 | '''A class definition for an ingredient. The following attributes are supported:
64 |
65 | Attributes:
66 | name: a string representing the ingredient's name
67 | quantity: a string representing the quantity of ingredient needed
68 | nutrition_info: a string representing nutrition info of ingredient
69 | '''
70 |
71 | def __init__(self, name, quantity, nutrition_info):
72 | '''Initialize a Ingredient object with name, quantity, nutrition_info set to values supplied'''
73 | self.name = name
74 | self.quantity = quantity
75 | self.nutrition_info = nutrition_info
76 |
77 | def __str__(self):
78 | '''Return a basic string representation of the Ingredient instance'''
79 | pass
80 |
81 | def scale(self, old_servings, new_servings):
82 | '''Scales quantity of ingredient according to new/old serving sizes
83 |
84 | Arguments accepted:
85 | old_servings -- an integer representing the number of people the recipe can currently serve
86 | new_servings -- 'an integer representing the number of people the recipe needs to serve'''
87 | pass
88 |
89 | def convert(self):
90 | '''Converts quantity of ingredient from metric to imperial, or vice versa'''
91 | pass
92 |
93 |
94 | # create banana bread recipe
95 | flour = Ingredient('flour', '2 cups', 'flour nutrition info')
96 | baking_soda = Ingredient('baking soda', '1 tsp', 'baking soda nutrition info')
97 | salt = Ingredient('salt', '1/4 tsp', 'salt nutrition info')
98 | butter = Ingredient('butter', '1/2 cup', 'butter nutrition info')
99 | brown_sugar = Ingredient('brown sugar', '3/4 cup', 'brown sugar nutrition info')
100 | bananas = Ingredient('bananas', '2 1/3 cups', 'banana nutrition info')
101 | ingredients = [flour, baking_soda, salt, butter, brown_sugar, bananas]
102 | equipment = ['9x5 inch loaf pan', 'oven', 'bowl', 'wooden spoon', 'measuring cups/spoons']
103 | bananaBread = Recipe('banana bread', ingredients, equipment, 'instructions', 12, 80.0)
104 |
105 | a_cookbook = Cookbook('My Delicious Noms') # instantiate Cookbook
106 | a_cookbook.add(bananaBread) # add banana bread recipe to the Cookbook instance
107 | recipe = a_cookbook.open('banana bread') # open the banana bread recipe
108 | print(recipe)
109 |
110 |
--------------------------------------------------------------------------------
/Wk07/model_and_algorithms.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | class Model(object):
4 | def __init__(self, algo, algo_kwargs, weights=[0.1, 0.1], size=100, repeats=200):
5 | self.algo = algo
6 | self.algo_kwargs = algo_kwargs
7 | self.weights = weights
8 | self.size = size
9 | self.repeats = repeats
10 |
11 | def run_simulation(self):
12 | """Run a single simulation, recording the performance"""
13 | algo = self.algo(**self.algo_kwargs) # instantiate algorithm object
14 | arm_choice_record = []
15 | reward_record = []
16 | for i in range(self.size):
17 | arm = algo.choose_arm()
18 | arm_choice_record.append(arm)
19 | reward = np.random.random() < self.weights[arm]
20 | reward_record.append(reward)
21 | algo.update(arm, reward)
22 | return arm_choice_record, reward_record
23 |
24 | def repeat_simulation(self):
25 | """Run multiple simulations, recording the performance of each"""
26 | arm_choice = []
27 | reward = []
28 | for i in range(self.repeats):
29 | arm_choice_record, reward_record = self.run_simulation()
30 | arm_choice.append(arm_choice_record)
31 | reward.append(reward_record)
32 | self.arm_choice = np.array(arm_choice)
33 | self.reward = np.array(reward)
34 |
35 | def plot_arm_frequency(self, ax, colour='black'):
36 | """Plot the frequency with which the second arm is chosen
37 | NOTE: Currently only works for two arms"""
38 | ax.plot(self.arm_choice.mean(axis=0), 'k.', color=colour)
39 | ax.set_title('Frequency of arm choice')
40 | ax.set_xlabel('Trial')
41 | ax.set_ylabel('Frequency')
42 | return ax
43 |
44 | def plot_reward(self, ax, colour='black'):
45 | """Plot the average reward for each trial across all simulations"""
46 | ax.plot(self.reward.mean(axis=0), 'k.', color=colour)
47 | ax.set_title('Reward')
48 | ax.set_xlabel('Trial')
49 | ax.set_ylabel('Reward')
50 | return ax
51 |
52 | def plot_cumulative_reward(self, ax, colour='black'):
53 | """Plot the cumulative reward across all simulations"""
54 | ax.plot(np.cumsum(self.reward, axis=1).mean(axis=0), 'k.', color=colour)
55 | ax.set_title('Cumulative Reward')
56 | ax.set_xlabel('Trial')
57 | ax.set_ylabel('Cumulative Reward')
58 | return ax
59 |
60 |
61 | class RCT(object):
62 | def __init__(self, n_arms, epsilon):
63 | self._epsilon = epsilon # self.epsilon is assigned via @property
64 | self.counts = [0] * n_arms
65 | self.values = [0] * n_arms
66 | self.n_arms = n_arms
67 |
68 | def choose_arm(self):
69 | """Choose an arm"""
70 | if np.random.random() > self.epsilon:
71 | # exploit (use best arm)
72 | weights = np.array(self.values)
73 | weights = weights == weights.max()
74 | weights = weights / weights.sum()
75 | return np.random.choice(np.arange(self.n_arms), p=weights)
76 | else:
77 | # explore (test all arms)
78 | return np.random.randint(self.n_arms)
79 |
80 |
81 | def update(self, arm, reward):
82 | """Update an arm with the reward"""
83 | self.counts[arm] = self.counts[arm] + 1
84 | n = self.counts[arm]
85 | value = self.values[arm]
86 | # Running product
87 | self.values[arm] = ((n - 1) / n) * self.values[arm] + (1/n) * reward
88 |
89 | @property
90 | def epsilon(self):
91 | if sum(self.counts) < 100:
92 | return 1
93 | else:
94 | return 0
95 |
96 |
97 | class EpsilonGreedy(RCT):
98 |
99 | @property
100 | def epsilon(self):
101 | return self._epsilon
102 |
103 |
104 | # When we have very little information on the relative performance of the two
105 | # arms a high exploration rate quickly provides us with additional information.
106 | # However, after several hundred trials we are relatively confident in the
107 | # performance of each arm and a high exploration rate is detrimental as we will
108 | # be choosing an arm we know to be inferior at a high rate. A better approach
109 | # would be to reduce the exploration rate as we acquire more information.
110 | class EpsilonDecrease(EpsilonGreedy):
111 |
112 | @property
113 | def epsilon(self):
114 | """Gradually reduce the value of epsilon over time"""
115 | total = sum(self.counts)
116 | return float(self._epsilon) / (total + float(self._epsilon))
117 |
118 |
--------------------------------------------------------------------------------
/Wk02/simulated_annealing_optimizer.py:
--------------------------------------------------------------------------------
1 | """Module to calculate best path between multiple points, using simulated annealing algorithm
2 |
3 | Functions:
4 | distance -- cost function that calculates distance as the cost of a path
5 | new_path -- path altering function that creates a new path
6 | new_path_modified -- same as new_path but slightly modified
7 | simulated_annealing_optimizer -- objective function that implements the simulated annealing algorithm
8 | """
9 |
10 | import random
11 | import numpy as np
12 |
13 |
14 | def distance(coords):
15 | """Calculate the distance of a path between multiple points
16 |
17 | Arguments received:
18 | coords — list of coordinates, e.g. [(0,0), (10, 5), (10, 10)], representing a path
19 |
20 | Arguments returned:
21 | distance -- total distance as a float
22 | """
23 | distance = 0
24 | for p1, p2 in zip(coords[:-1], coords[1:]):
25 | distance += ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
26 | return distance
27 |
28 |
29 | def new_path(existing_path):
30 | """Switch two random consecutive points on a path
31 |
32 | Arguments received:
33 | existing_path -- list of coordinates representing a path
34 |
35 | Arguments returned:
36 | path -- list of coordinates representing the mutated path
37 | """
38 | path = existing_path[:]
39 | point = random.randint(0, len(path)-2) # randomly choose a point between 1st and 2nd-to-last points on path
40 | path[point+1], path[point] = path[point], path[point+1] # switch this point with the next point
41 | return path
42 |
43 | # Our simulated annealing function generated a reasonable solution but there were signs that the approach was
44 | # limited by our function for creating new paths. Create a new function to generate paths in a different way.
45 | # Does this improve the performance of the simulated annealing function? Answer in workspace.py, along with timer.
46 |
47 |
48 | def new_path_modified(existing_path):
49 | """Switch two random points on a path
50 |
51 | Arguments received:
52 | existing_path -- list of coordinates representing a path
53 |
54 | Arguments returned:
55 | path -- list of coordinates representing the mutated path
56 | """
57 | path = existing_path[:]
58 | point = random.randint(0, len(path)-1) # randomly choose any point on path
59 | point2 = random.randint(0, len(path)-1) # randomly choose any other point on path
60 | while point2 == point:
61 | point2 = random.randint(0, len(path)-1)
62 | temp = path[point] # temporary placeholder for 1st point
63 | path[point], path[point2] = path[point2], temp # switch 1st point with 2nd point
64 | return path
65 |
66 |
67 | def simulated_annealing_optimizer(starting_path, cost_func, new_path_func, start_temp, min_temp, steps):
68 | """Calculate the best path between multiple points using a simulated annealing algorithm
69 |
70 | The simulated annealing algorithm begins with a given path and calculates its cost.
71 | Each iteration generates a new path with two random consecutive points switched.
72 | If the new path has a lower cost, it is better and will replace the current path.
73 | If it has a higher cost, it is a worse path and may replace the current path, as
74 | decided by comparing a random number with an acceptance probability that depends on
75 | the temperature. The temperature decreases a bit in each iteration, giving worse paths
76 | a lesser chance of replacing the current path. Allowing worse paths at the beginning
77 | helps to avoid converging to a local minimum rather than the global minimum.
78 |
79 | Arugments received:
80 | starting_path -- list of coordinates representing a path
81 | cost_func -- function to calculate cost of a path
82 | new_path_func -- function to generate a new path with two random consecutive points switched
83 | start_temp -- maximum temperature
84 | min_temp -- minimum temperature
85 | steps -- number of iterations
86 |
87 | Arguments returned:
88 | current_path -- list of coordinates representing the best path
89 | current_cost -- cost of the best path
90 | history -- an array of objects, each object containing information about each tested path
91 | """
92 | current_path = starting_path[:]
93 | current_cost = cost_func(current_path)
94 | temp_factor = -np.log(start_temp / min_temp)
95 | history = []
96 | for s in range(0, steps):
97 | temp = start_temp * np.exp(temp_factor * s / steps)
98 | new_path = new_path_func(current_path)
99 | new_cost = cost_func(new_path)
100 | if (new_cost < current_cost) or (random.random() <= np.exp(-(new_cost - current_cost)/temp)):
101 | current_path = new_path
102 | current_cost = new_cost
103 | record = {'step': s, 'temperature': temp, 'current_cost': current_cost, }
104 | history.append(record)
105 | return (current_path, current_cost, history)
106 |
--------------------------------------------------------------------------------
/Wk02/genetic_algorithm_optimizer.py:
--------------------------------------------------------------------------------
1 | """Module to calculate best path between multiple points, using genetic algorithm
2 |
3 | Functions:
4 | new_path -- path altering function that creates a new path
5 | distance -- cost function that calculates distance as the cost of a path
6 | select_best -- function that selects the best paths in a population
7 | recombine -- path altering function that returns a child path recombined from two parent paths
8 | genetic_algorithm_optimizer -- objective function that implements the genetic algorithm
9 | """
10 |
11 | import random
12 |
13 |
14 | def new_path(existing_path):
15 | """Switch two random consecutive points on a path
16 |
17 | Arguments received:
18 | existing_path -- list of coordinates, e.g. [(0, 0), (10, 5), (10, 10)], representing a path
19 |
20 | Arguments returned:
21 | path -- list of coordinates representing the mutated path
22 | """
23 | path = existing_path[:]
24 | point = random.randint(0, len(path)-2) # randomly choose a point between 1st and 2nd-to-last points on path
25 | path[point+1], path[point] = path[point], path[point+1] # switch this point with the next point
26 | return path
27 |
28 |
29 | def distance(coords):
30 | """Calculate the distance of a path between multiple points
31 |
32 | Arguments received:
33 | coords — list of coordinates representing a path
34 |
35 | Arguments returned:
36 | distance -- total distance as a float
37 | """
38 | distance = 0
39 | for p1, p2 in zip(coords[:-1], coords[1:]):
40 | distance += ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
41 | return distance
42 |
43 |
44 | def select_best(population, cost_func, num_to_keep):
45 | """Select a given number of paths with the lowest cost (the best paths)
46 |
47 | Arguments received:
48 | population -- an array of lists of coordinates representing paths
49 | cost_func -- function to calculate cost of a path
50 | num_to_keep -- number of paths to select
51 |
52 | Arguments returned:
53 | [i[0] for i in scored_population[:num_to_keep]] -- an array of lists of coordinates representing the best paths
54 | """
55 | scored_population = [(i, cost_func(i)) for i in population] # create a list of tuples: (path, cost)
56 | scored_population.sort(key=lambda x: x[1]) # sort list by cost, lowest to highest
57 | return [i[0] for i in scored_population[:num_to_keep]] # return num_to_keep paths with the lowest cost
58 |
59 |
60 | def recombine(population):
61 | """Cross over two parent paths and return the resulting child path
62 |
63 | Arguments received:
64 | population -- an array of lists of coordinates representing paths
65 |
66 | Arguments returned:
67 | child -- list of coordinates representing a recombined child path
68 | """
69 | # Randomly choose two parents
70 | options = list(range(len(population))) # from 1 to 125
71 | random.shuffle(options)
72 | partner1 = options[0]
73 | partner2 = options[1]
74 | # Choose a split point, take the first parent's order to that split point,
75 | # then the second parent's order for all remaining points
76 | split_point = random.randint(0, len(population[0])-1)
77 | child = population[partner1][:split_point]
78 | for point in population[partner2]:
79 | if point not in child:
80 | child.append(point)
81 | return child
82 |
83 |
84 | # Our genetic algorithm function currently only uses recombination. As we saw from the simulated
85 | # annealing approach mutation is also a powerful tool in locating the optimal solution.
86 | # Add mutation to the genetic algorithm function using the new_path function we created.
87 |
88 | def genetic_algorithm_optimizer(starting_path, cost_func, new_path_func, pop_size, generations):
89 | """Calculate the best path between multiple points using a genetic algorithm
90 |
91 | The genetic algorithm begins with a given path, which it shuffles to create a starting population of a given
92 | size. Once the population is generated, the cost of each path is evaluated. The top 25 percent then are sent
93 | through recombination, then mutation -- to hopefully generate 'better' paths -- to form a new population.
94 |
95 | Arugments received:
96 | starting_path -- list of coordinates representing a path
97 | cost_func -- function to calculate cost of a path
98 | new_path_func -- function to generate a new path with two random consecutive points switched
99 | pop_size -- population size, or amount of paths in one generation
100 | generations -- number of iterations
101 |
102 | Arguments returned:
103 | population[0] -- list of coordinates representing the best path
104 | cost_func(population[0]) -- cost of the best path
105 | history -- an array of objects, each object containing information about each tested path
106 | """
107 | # Create a starting population of 500 paths by randomly shuffling the points
108 | population = []
109 | for i in range(pop_size):
110 | new_path = starting_path[:]
111 | random.shuffle(new_path)
112 | population.append(new_path)
113 | history = []
114 | # Take the top 25% of routes and recombine to create new routes, repeating for generations
115 | for i in range(generations):
116 | pop_best = select_best(population, cost_func, int(pop_size / 4))
117 | new_population = []
118 | mutated_population = []
119 | for i in range(pop_size):
120 | new_population.append(recombine(pop_best))
121 | if (random.random() <= 1/len(new_population[i])): # mutation probability, 1/path length
122 | mutated_population.append(new_path_func(new_population[i])) # mutate
123 | else:
124 | mutated_population.append(new_population[i]) # don't mutate
125 | population = mutated_population
126 | record = {'generation': i, 'current_cost': cost_func(population[0]), }
127 | history.append(record)
128 | return (population[0], cost_func(population[0]), history)
129 |
--------------------------------------------------------------------------------
/Wk05/Wk05-OOP-Public-interface-Solution.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "##Assignments\n",
8 | "\n",
9 | "Modify the Ingredient and Recipe classes so that the following code works.\n",
10 | "\n"
11 | ]
12 | },
13 | {
14 | "cell_type": "code",
15 | "execution_count": 46,
16 | "metadata": {
17 | "collapsed": true
18 | },
19 | "outputs": [],
20 | "source": [
21 | "class Ingredient(object):\n",
22 | " \"\"\"The ingredient object that contains nutritional information\"\"\"\n",
23 | " \n",
24 | " def __init__(self, name, data, protein=0, fat=0):\n",
25 | " if type(data) == dict:\n",
26 | " self.nutrition_store = data\n",
27 | " else:\n",
28 | " self.nutrition_store = {'carbs': data, 'protein':protein, 'fat': fat}\n",
29 | " self.name = name\n",
30 | " \n",
31 | " \n",
32 | " def __repr__(self):\n",
33 | " return 'Ingredient({0}, {1})'.format(self.name, self.nutrition_store)\n",
34 | " \n",
35 | " @property\n",
36 | " def nutrition(self):\n",
37 | " \"\"\"Returns the nutritional information for the ingredient\"\"\"\n",
38 | " return self.nutrition_store \n",
39 | "\n",
40 | "class Recipe(object):\n",
41 | " \"\"\"The Recipe object containing the ingredients\"\"\"\n",
42 | " \n",
43 | " def __init__(self, name, ingredients):\n",
44 | " self.name = name\n",
45 | " self.ingredients = ingredients\n",
46 | " \n",
47 | " def __repr__(self):\n",
48 | " temp_str = []\n",
49 | " for amount, ingredient in self.ingredients:\n",
50 | " temp_str.append('({0}, {1})'.format(amount, ingredient))\n",
51 | " return 'Recipe({0}, [{1}])'.format(self.name, ', '.join(temp_str))\n",
52 | " \n",
53 | " \n",
54 | " @property \n",
55 | " def nutrition(self):\n",
56 | " \"\"\"Returns the nutritional information for the recipe\"\"\"\n",
57 | " nutrition = {}\n",
58 | " for amount, ingredient in self.ingredients:\n",
59 | " for key in ingredient.nutrition:\n",
60 | " nutrition[key] = nutrition.get(key, 0) + amount * ingredient.nutrition[key]\n",
61 | " return nutrition"
62 | ]
63 | },
64 | {
65 | "cell_type": "code",
66 | "execution_count": 47,
67 | "metadata": {
68 | "collapsed": false
69 | },
70 | "outputs": [
71 | {
72 | "name": "stdout",
73 | "output_type": "stream",
74 | "text": [
75 | "[(820, Ingredient(Flour, {'carbs': 0.77, 'fat': 0.01, 'protein': 0.1})), (30, Ingredient(Oil, {'carbs': 0, 'fat': 1, 'protein': 0})), (36, Ingredient(Sugar, {'carbs': 1, 'fat': 0, 'protein': 0})), (7, Ingredient(Yeast, {'carbs': 0.3125, 'fat': 0.0625, 'protein': 0.5})), (560, Ingredient(Water, {'carbs': 0, 'fat': 0, 'protein': 0}))]\n"
76 | ]
77 | }
78 | ],
79 | "source": [
80 | "bread = Recipe('Bread', [(820, Ingredient('Flour', 0.77, 0.10, 0.01)), \n",
81 | " (30, Ingredient('Oil', 0, 0, 1)), \n",
82 | " (36, Ingredient('Sugar', 1, 0, 0)), \n",
83 | " (7, Ingredient('Yeast', 0.3125, 0.5, 0.0625)),\n",
84 | " (560, Ingredient('Water', 0, 0, 0))])\n",
85 | "print(bread.ingredients)\n",
86 | "# Should be roughly [(820, Ingredient(Flour, 0.77, 0.1, 0.01)), (30, Ingredient(Oil, 0, 0, 1)), \n",
87 | "# (36, Ingredient(Sugar, 1, 0, 0)), (7, Ingredient(Yeast, 0.3125, 0.5, 0.0625)), (560, Ingredient(Water, 0, 0, 0))]"
88 | ]
89 | },
90 | {
91 | "cell_type": "code",
92 | "execution_count": 48,
93 | "metadata": {
94 | "collapsed": false
95 | },
96 | "outputs": [
97 | {
98 | "name": "stdout",
99 | "output_type": "stream",
100 | "text": [
101 | "{'carbs': 669.5875, 'fat': 38.6375, 'protein': 85.5}\n"
102 | ]
103 | }
104 | ],
105 | "source": [
106 | "print(bread.nutrition)\n",
107 | "#Should be roughly {'carbs': 669.5875, 'protein': 85.5, 'fat': 38.6375} the order is not important"
108 | ]
109 | },
110 | {
111 | "cell_type": "code",
112 | "execution_count": 49,
113 | "metadata": {
114 | "collapsed": false
115 | },
116 | "outputs": [
117 | {
118 | "name": "stdout",
119 | "output_type": "stream",
120 | "text": [
121 | "[(300, Ingredient(Egg, {'carbs': 0.0077, 'fat': 0.0994, 'protein': 0.1258, 'cholesterol': 0.00423})), (0.25, Recipe(Bread, [(820, Ingredient(Flour, {'carbs': 0.77, 'fat': 0.01, 'protein': 0.1})), (30, Ingredient(Oil, {'carbs': 0, 'fat': 1, 'protein': 0})), (36, Ingredient(Sugar, {'carbs': 1, 'fat': 0, 'protein': 0})), (7, Ingredient(Yeast, {'carbs': 0.3125, 'fat': 0.0625, 'protein': 0.5})), (560, Ingredient(Water, {'carbs': 0, 'fat': 0, 'protein': 0}))]))]\n"
122 | ]
123 | }
124 | ],
125 | "source": [
126 | "#Points to note:\n",
127 | "# - The different call to Ingredient, you can use isinstance or type to change the \n",
128 | "# behaviour depending on the arguments supplied\n",
129 | "# - Cholesterol as an extra nutrient, your implementation should accept any nutrient\n",
130 | "# - Use of Recipe (bread) as an ingredient\n",
131 | "basic_french_toast = Recipe('Basic French Toast', [(300, Ingredient('Egg', {'carbs': 0.0077, 'protein': 0.1258, \n",
132 | " 'fat': 0.0994, 'cholesterol': 0.00423})), \n",
133 | " (0.25, bread)])\n",
134 | "print(basic_french_toast.ingredients)\n",
135 | "# Should be roughly:\n",
136 | "# [(300, Ingredient(Egg, 0.0077, 0.1258, 0.0994)), (0.25, Recipe(Bread, [(820, Ingredient(Flour, 0.77, 0.1, 0.01)), \n",
137 | "# (30, Ingredient(Oil, 0, 0, 1)), (36, Ingredient(Sugar, 1, 0, 0)), (7, Ingredient(Yeast, 0.3125, 0.5, 0.0625)), \n",
138 | "# (560, Ingredient(Water, 0, 0, 0))]))]\n",
139 | "# Note the formatting for the Recipe object, a __repr__ method will be needed"
140 | ]
141 | },
142 | {
143 | "cell_type": "code",
144 | "execution_count": 50,
145 | "metadata": {
146 | "collapsed": false
147 | },
148 | "outputs": [
149 | {
150 | "name": "stdout",
151 | "output_type": "stream",
152 | "text": [
153 | "{'carbs': 169.706875, 'fat': 39.479375000000005, 'protein': 59.115, 'cholesterol': 1.2690000000000001}\n"
154 | ]
155 | }
156 | ],
157 | "source": [
158 | "print(basic_french_toast.nutrition)\n",
159 | "# Should be roughly {'protein': 59.115, 'carbs': 169.706875, 'cholesterol': 1.2690000000000001, 'fat': 39.479375000000005}\n",
160 | "# The order is not important"
161 | ]
162 | }
163 | ],
164 | "metadata": {
165 | "kernelspec": {
166 | "display_name": "Python 3",
167 | "language": "python",
168 | "name": "python3"
169 | },
170 | "language_info": {
171 | "codemirror_mode": {
172 | "name": "ipython",
173 | "version": 3
174 | },
175 | "file_extension": ".py",
176 | "mimetype": "text/x-python",
177 | "name": "python",
178 | "nbconvert_exporter": "python",
179 | "pygments_lexer": "ipython3",
180 | "version": "3.5.1"
181 | }
182 | },
183 | "nbformat": 4,
184 | "nbformat_minor": 0
185 | }
186 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Syllabus
2 | ========
3 |
4 | **BIOF509 - Machine Learning and Object-Oriented Programming with Python**
5 |
6 |
7 | **Spring 2016**
8 |
9 |
10 | Instructors:
11 |
12 | * Jonathan Street (jonathan.street@nih.gov)
13 | * \R. Burke Squires (richard.squires@nih.gov)
14 |
15 | First class: 4th February 2016
16 |
17 | Final class: 12th May 2016
18 |
19 | *This document is subject to revision. Last revised 2nd Feb 2016.*
20 |
21 | Course Description
22 | ------------------
23 |
24 | Learning Objectives
25 | -------------------
26 |
27 | By the end of this course you should be able to:
28 |
29 | 1. Create working python programs using the basic features of the python language together with numpy, pandas, and biopython (A brief refresh)
30 | 2. Demonstrate the tools commonly used in professional settings to aid development
31 | 3. Compare different programming paradigms including procedural, functional and object oriented.
32 | 4. Define what an object is in the context of programming
33 | 5. Identify the features of an object definition
34 | 6. Contrast attributes, properties and methods
35 | 7. Review special methods
36 | 8. Design a public interface for a class
37 | 9. Utilize inheritance and abstraction
38 | 10. Choose when and how to raise and handle exceptions appropriately
39 | 11. Describe the common types of machine learning tasks
40 | 12. Implement a simple linear regression model utilizing numpy
41 | 13. List the advantages and disadvantages of different machine learning algorithms
42 | 14. Apply machine learning algorithms for both regression and classification
43 | 15. Convert a data set into a form suitable for use by machine learning algorithms
44 | 16. Apply dimensionality reduction to a data set for visualization and further processing
45 | 17. Identify subpopulations using clustering algorithms
46 | 18. Choose appropriate model parameters
47 | 19. Evaluate the results of a machine learning model
48 | 20. Integrate a machine learning model in a workflow
49 |
50 |
51 | Logistics
52 | ---------
53 |
54 | This is a 15 week course starting on the 4th February 2016, and finishing on 12th May 2016. Classes will take place between 5:30pm and 7:30pm each Thursday in building 10, room B1C207 within the FAES Academic Center.
55 |
56 | Attendance in class is strongly recommended; however, we realize other commitments will occasionally prevent attendance. Class materials will generally be sent to all learners via email.
57 |
58 | Most classes will have hands-on tutorials and assignments. Both practice and graded assignments will generally be provided. Graded assignments should be submitted prior to the following class. So that you can follow along during class bringing a laptop to each class is strongly encouraged.
59 |
60 | Important dates:
61 |
62 | * 04 Mar 2016 - Last day to drop/withdraw
63 | * 08 Apr 2016 - Last day to change status (credit or audit)
64 |
65 | Required Materials
66 | ------------------
67 |
68 | **Each student is encouraged to bring their own laptop to each class.** For the course, we will use Python 3. Any python installation should work, but you must be able to install packages. The Anaconda Scientific Python Distribution from Continuum Analytics will likely be the easiest approach to configuring python if you do not already have python installed. The Anaconda installer will automatically install many of the packages we will use during the course.
69 |
70 | Recommended Books
71 | -----------------
72 |
73 | **There is no required textbook for this course.**
74 |
75 | We will link to relevant online resources throughout the course.
76 |
77 | If you would like a refresher on the basics, the following resources may be useful:
78 |
79 | * `Learn python the hard way (ebook freely available from the author) `_ by Zed A. Shaw. A video course is also `available `_.
80 | * `Think python (ebook freely available from the author) `_ by Allen B. Downey.
81 |
82 | The following books cover some of the same material we will cover during the course. These books are not required, and presented solely as an alternative starting point covering the course objectives.
83 |
84 | * `The Elements of statistical learning (ebook freely available from the authors) `_ by Trevor Hastie, Robert Tibshirani, and Jerome Firedman.
85 | * `Python Machine Learning `_ by Sebastian Rashka.
86 | * `Python 3 Object Oriented Programming `_ by Dusty Phillips
87 |
88 | Assignments and Grading
89 | -----------------------
90 |
91 | The emphasis of the course is on learning and mastering the skills covered. It is our hope that everyone will be able to complete the assignments and project. If some of the material appears unclear please ask for clarification.
92 |
93 | Grading assignments will follow the following rubric:
94 |
95 | * Program runs, produces correct result, contains useful comments, meaningful variable names, follows coding conventions: A+
96 | * Program runs, produces correct result: A
97 | * Program runs, produces something close to the correct result: B
98 | * Program runs, does not produce correct result: C
99 | * Program does not run: Incomplete (I)
100 |
101 | Grading the final project will follow the following rubric:
102 |
103 |
104 | * Project description / Specification
105 |
106 | - Goals unclear, difficulty demonstrating functionality (1-3)
107 | - Goals for the project and functionality are discussed but difficult to follow (4-6)
108 | - Goals for the project and functionality are discussed (7-9)
109 | - Goals for the project and functionality are logically presented and clearly communicated (10-12)
110 |
111 |
112 | * Documentation
113 |
114 | - Only comments embedded in the code (1-3)
115 | - Objects and methods have docstrings (4-6)
116 | - Objects and methods have docstrings, additional standalone documentation (7-9)
117 | - Objects and methods have docstrings, extensive standalone documentation with example usage (10-12)
118 |
119 |
120 | * Readability
121 |
122 | - The code is poorly organized and very difficult to read (1-3)
123 | - The code is readable, but challenging to understand (4-6)
124 | - The code is fairly easy to read (7-9)
125 | - The code is well organized and very easy to read (10-12)
126 |
127 |
128 | * Reusability
129 |
130 | - The code is not organized for reusability (1-3)
131 | - Some parts of the code could be reused (4-6)
132 | - Most of the code could be reused (7-9)
133 | - Each part of the code, and the whole, could be reused (10-12)
134 |
135 |
136 | * Performance
137 |
138 | - Program does not run (1-6)
139 | - Program runs, but does not produce correct output (7-12)
140 | - Program runs, produces correct output under most conditions (13-18)
141 | - Program runs, produces correct output with robust error checking (19-24)
142 |
143 |
144 | Course Materials
145 | ----------------
146 |
147 | Course materials are available from
148 | `the github repository `_.
149 |
150 |
151 | Schedule
152 | --------
153 |
154 | **Week 1 (04 Feb 2016):** Course overview, troubleshooting software installation, and a refresher on the basics of python
155 |
156 | **Week 2 (11 Feb 2016):** The tools used to aid developemt. Recording experiments performed. Our first machine learning model.
157 |
158 | **Week 3 (18 Feb 2016):** Different programming paradigms, including object-oriented programming. The class definition - Attributes, properties, methods, and special methods.
159 |
160 | **Week 4 (25 Feb 2016):** Inheritance and abstraction. Graphical User Interfaces (GUIs)
161 |
162 | **Week 5 (03 Mar 2016):** Crafting the public interface. Choosing when and how to raise and handle exceptions.
163 |
164 | **Week 6 (10 Mar 2016):** WSGI as an example interface. Creating web applications.
165 |
166 | **Week 7 (17 Mar 2016):** Common machine learning tasks.
167 |
168 | **Week 8 (24 Mar 2016):** Linear regression with numpy. Overview of scikit-learn.
169 |
170 | **Week 9 (31 Mar 2016):** Dataset preprocessing.
171 |
172 | **Week 10 (07 Apr 2016):** Dimensionality reduction and clustering
173 |
174 | **Week 11 (14 Apr 2016):** Regression and classification.
175 |
176 | **Week 12 (21 Apr 2016):** The machine learning workflow.
177 |
178 | **Week 13 (28 Apr 2016):** Advanced ML tasks.
179 |
180 | **Week 14 (05 May 2016):** Project presentations.
181 |
182 | **Week 15 (12 May 2016):** Project presentations.
--------------------------------------------------------------------------------
/Wk04/Wk04-GUI.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Graphical User Interfaces\n",
8 | "\n",
9 | "Object oriented programming and particularly inheritance is commonly used for creating GUIs. There are [a large number](https://wiki.python.org/moin/GuiProgramming) of different frameworks supporting building GUIs. The following are particularly relevant:\n",
10 | "\n",
11 | "* [TkInter](https://docs.python.org/3.5/library/tkinter.html) - This is the official/default GUI framework\n",
12 | "* [guidata](https://pythonhosted.org/guidata/) - A GUI framework for dataset display and editing\n",
13 | "* [VTK](http://www.vtk.org/) - A GUI framework for data visualization\n",
14 | "* [pyqtgraph](http://www.pyqtgraph.org/documentation/index.html) - A GUI framework for data visualization, easily installed with `conda install pyqtgraph`\n",
15 | "* [matplotlib](http://matplotlib.org/) - As well as creating plots matplotlib can support interaction"
16 | ]
17 | },
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {},
21 | "source": [
22 | "## TkInter\n",
23 | "\n",
24 | "TkInter is widely used with plenty of documentation available but may prove somewhat limited for more data intensive applications.\n",
25 | "\n",
26 | "* [Documentation from the standard library](https://docs.python.org/3/library/tk.html)\n",
27 | "* [Further documentation from python.org](https://docs.python.org/3.5/library/tkinter.html)\n",
28 | "* [TkDocs](http://www.tkdocs.com/index.html)\n",
29 | "\n",
30 | "Let's look at a simple example from the documentation"
31 | ]
32 | },
33 | {
34 | "cell_type": "code",
35 | "execution_count": 37,
36 | "metadata": {
37 | "collapsed": true
38 | },
39 | "outputs": [],
40 | "source": [
41 | "import tkinter as tk\n",
42 | "\n",
43 | "class Application(tk.Frame):\n",
44 | " def __init__(self, master=None):\n",
45 | " tk.Frame.__init__(self, master)\n",
46 | " self.pack()\n",
47 | " self.createWidgets()\n",
48 | "\n",
49 | " def createWidgets(self):\n",
50 | " self.hi_there = tk.Button(self)\n",
51 | " self.hi_there[\"text\"] = \"Hello World\\n(click me)\"\n",
52 | " self.hi_there[\"command\"] = self.say_hi\n",
53 | " self.hi_there.pack(side=\"top\")\n",
54 | "\n",
55 | " self.QUIT = tk.Button(self, text=\"QUIT\", fg=\"red\",\n",
56 | " command=root.destroy)\n",
57 | " self.QUIT.pack(side=\"bottom\")\n",
58 | "\n",
59 | " def say_hi(self):\n",
60 | " print(\"hi there, everyone!\")\n",
61 | "\n",
62 | "root = tk.Tk()\n",
63 | "app = Application(master=root)\n",
64 | "app.mainloop()"
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {},
70 | "source": [
71 | "Although this works, it is visually unappealing. We can improve on this using styles and themes."
72 | ]
73 | },
74 | {
75 | "cell_type": "code",
76 | "execution_count": 48,
77 | "metadata": {
78 | "collapsed": false
79 | },
80 | "outputs": [],
81 | "source": [
82 | "import tkinter as tk\n",
83 | "from tkinter import ttk\n",
84 | "\n",
85 | "\n",
86 | "class Application(ttk.Frame):\n",
87 | " def __init__(self, master=None):\n",
88 | " super().__init__(master, padding=\"3 3 12 12\")\n",
89 | " self.grid(column=0, row=0, )\n",
90 | " self.createWidgets()\n",
91 | " self.master.title('Test')\n",
92 | "\n",
93 | " def createWidgets(self):\n",
94 | " self.hi_there = ttk.Button(self)\n",
95 | " self.hi_there[\"text\"] = \"Hello World\\n(click me)\"\n",
96 | " self.hi_there[\"command\"] = self.say_hi\n",
97 | "\n",
98 | " self.QUIT = ttk.Button(self, text=\"QUIT\", style='Alert.TButton', command=root.destroy)\n",
99 | "\n",
100 | " for child in self.winfo_children(): \n",
101 | " child.grid_configure(padx=10, pady=10)\n",
102 | "\n",
103 | " def say_hi(self):\n",
104 | " print(\"hi there, everyone!\")\n",
105 | "\n",
106 | " \n",
107 | "\n",
108 | "root = tk.Tk()\n",
109 | "app = Application(master=root)\n",
110 | "s = ttk.Style()\n",
111 | "s.configure('TButton', font='helvetica 24')\n",
112 | "s.configure('Alert.TButton', foreground='red')\n",
113 | "root.mainloop()"
114 | ]
115 | },
116 | {
117 | "cell_type": "markdown",
118 | "metadata": {},
119 | "source": [
120 | "As our applications get more complicated we must give greater thought to the layout. The following example comes from the [TkDocs site](http://www.tkdocs.com/tutorial/firstexample.html)."
121 | ]
122 | },
123 | {
124 | "cell_type": "code",
125 | "execution_count": 28,
126 | "metadata": {
127 | "collapsed": false
128 | },
129 | "outputs": [],
130 | "source": [
131 | "from tkinter import *\n",
132 | "from tkinter import ttk\n",
133 | "\n",
134 | "def calculate(*args):\n",
135 | " try:\n",
136 | " value = float(feet.get())\n",
137 | " meters.set((0.3048 * value * 10000.0 + 0.5)/10000.0)\n",
138 | " except ValueError:\n",
139 | " pass\n",
140 | " \n",
141 | "root = Tk()\n",
142 | "root.title(\"Feet to Meters\")\n",
143 | "\n",
144 | "mainframe = ttk.Frame(root, padding=\"3 3 12 12\")\n",
145 | "mainframe.grid(column=0, row=0, sticky=(N, W, E, S))\n",
146 | "mainframe.columnconfigure(0, weight=1)\n",
147 | "mainframe.rowconfigure(0, weight=1)\n",
148 | "\n",
149 | "feet = StringVar()\n",
150 | "meters = StringVar()\n",
151 | "\n",
152 | "feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet)\n",
153 | "feet_entry.grid(column=2, row=1, sticky=(W, E))\n",
154 | "\n",
155 | "ttk.Label(mainframe, textvariable=meters).grid(column=2, row=2, sticky=(W, E))\n",
156 | "ttk.Button(mainframe, text=\"Calculate\", command=calculate).grid(column=3, row=3, sticky=W)\n",
157 | "\n",
158 | "ttk.Label(mainframe, text=\"feet\").grid(column=3, row=1, sticky=W)\n",
159 | "ttk.Label(mainframe, text=\"is equivalent to\").grid(column=1, row=2, sticky=E)\n",
160 | "ttk.Label(mainframe, text=\"meters\").grid(column=3, row=2, sticky=W)\n",
161 | "\n",
162 | "for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)\n",
163 | "\n",
164 | "feet_entry.focus()\n",
165 | "root.bind('', calculate)\n",
166 | "\n",
167 | "root.mainloop()"
168 | ]
169 | },
170 | {
171 | "cell_type": "markdown",
172 | "metadata": {},
173 | "source": [
174 | "## Matplotlib\n",
175 | "\n",
176 | "For simple programs, displaying data and taking basic input, often a command line application will be much faster to implement than a GUI. The times when I have moved away from the command line it has been to interact with image data and plots. Here, matplotlib often works very well. Either it can be embedded in a larger application or it can be used directly.\n",
177 | "\n",
178 | "There are a number of examples on the [matplotlib site](http://matplotlib.org/examples/index.html).\n",
179 | "\n",
180 | "Here is one stripped down example of one recent GUI I have used."
181 | ]
182 | },
183 | {
184 | "cell_type": "code",
185 | "execution_count": null,
186 | "metadata": {
187 | "collapsed": false
188 | },
189 | "outputs": [],
190 | "source": [
191 | "\"\"\"\n",
192 | "Do a mouseclick somewhere, move the mouse to some destination, release\n",
193 | "the button. This class gives click- and release-events and also draws\n",
194 | "a line or a box from the click-point to the actual mouseposition\n",
195 | "(within the same axes) until the button is released. Within the\n",
196 | "method 'self.ignore()' it is checked wether the button from eventpress\n",
197 | "and eventrelease are the same.\n",
198 | "\n",
199 | "\"\"\"\n",
200 | "from matplotlib.widgets import RectangleSelector\n",
201 | "import matplotlib.pyplot as plt\n",
202 | "import matplotlib.cbook as cbook\n",
203 | "\n",
204 | "\n",
205 | "def line_select_callback(eclick, erelease):\n",
206 | " 'eclick and erelease are the press and release events'\n",
207 | " x1, y1 = eclick.xdata, eclick.ydata\n",
208 | " x2, y2 = erelease.xdata, erelease.ydata\n",
209 | " print (\"(%3.2f, %3.2f) --> (%3.2f, %3.2f)\" % (x1, y1, x2, y2))\n",
210 | " print (\" The button you used were: %s %s\" % (eclick.button, erelease.button))\n",
211 | "\n",
212 | " \n",
213 | "def toggle_selector(event):\n",
214 | " print (' Key pressed.')\n",
215 | " if event.key in ['Q', 'q'] and toggle_selector.RS.active:\n",
216 | " print (' RectangleSelector deactivated.')\n",
217 | " toggle_selector.RS.set_active(False)\n",
218 | " if event.key in ['A', 'a'] and not toggle_selector.RS.active:\n",
219 | " print (' RectangleSelector activated.')\n",
220 | " toggle_selector.RS.set_active(True)\n",
221 | "\n",
222 | "\n",
223 | " \n",
224 | "image_file = cbook.get_sample_data('grace_hopper.png')\n",
225 | "image = plt.imread(image_file)\n",
226 | "fig, current_ax = plt.subplots()\n",
227 | "plt.imshow(image)\n",
228 | "toggle_selector.RS = RectangleSelector(current_ax, \n",
229 | " line_select_callback,\n",
230 | " drawtype='box', useblit=True,\n",
231 | " button=[1,3], # don't use middle button\n",
232 | " minspanx=5, minspany=5,\n",
233 | " spancoords='pixels')\n",
234 | "plt.connect('key_press_event', toggle_selector)\n",
235 | "plt.show()\n"
236 | ]
237 | },
238 | {
239 | "cell_type": "code",
240 | "execution_count": null,
241 | "metadata": {
242 | "collapsed": true
243 | },
244 | "outputs": [],
245 | "source": []
246 | }
247 | ],
248 | "metadata": {
249 | "kernelspec": {
250 | "display_name": "Python 3",
251 | "language": "python",
252 | "name": "python3"
253 | },
254 | "language_info": {
255 | "codemirror_mode": {
256 | "name": "ipython",
257 | "version": 3
258 | },
259 | "file_extension": ".py",
260 | "mimetype": "text/x-python",
261 | "name": "python",
262 | "nbconvert_exporter": "python",
263 | "pygments_lexer": "ipython3",
264 | "version": "3.4.3"
265 | }
266 | },
267 | "nbformat": 4,
268 | "nbformat_minor": 0
269 | }
270 |
--------------------------------------------------------------------------------
/Wk04/Wk04-OOP-Inheritance-abstraction.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Week 4 - Inheritance and abstraction. Graphical User Interfaces (GUIs)\n",
8 | "\n",
9 | "\n",
10 | "## Learning Objectives\n",
11 | "\n",
12 | "* Describe inheritance in the context of object oriented programming\n",
13 | "* List situations in which inheritance is useful\n",
14 | "* Create an abstract class\n",
15 | "* Contrast control abstraction with data abstraction\n",
16 | "* Implement a simple graphic user interface"
17 | ]
18 | },
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {},
22 | "source": [
23 | "Last week we looked at several example projects and the classes we might use to implement them."
24 | ]
25 | },
26 | {
27 | "cell_type": "markdown",
28 | "metadata": {},
29 | "source": [
30 | "###Example 1: A Laboratory Inventory\n",
31 | "\n",
32 | "I would like to keep track of all the __items__ in the __laboratory__ so I can easily find them the next time I need them. Both __equipment__ and __consumables__ would be tracked. We have multiple __rooms__, and items can be on __shelves__, in __refrigerators__, in __freezers__, etc. Items can also be in __boxes__ containing other items in all these places.\n",
33 | "\n",
34 | "The words in __bold__ would all be good ideas to turn into classes. Now we know some of the classes we will need we can start to think about what each of these classes should do, what the methods will be. Let's consider the consumables class:\n",
35 | "\n",
36 | "For consumables we will need to manage their use so there should be an initial quantity and a quantity remaining that is updated every time we use some. We want to make sure that temperature sensitive consumables are always stored at the correct temperature, and that flammables are stored in a flammables cabinet etc.\n",
37 | "\n",
38 | "The consumable class will need a number of attributes:\n",
39 | "\n",
40 | "* Initial quantity\n",
41 | "* Current quantity\n",
42 | "* Storage temperature\n",
43 | "* Flammability\n",
44 | "\n",
45 | "The consumable class will need methods to:\n",
46 | "\n",
47 | "* Update the quantity remaining\n",
48 | "* Check for improper storage?\n",
49 | "\n",
50 | "The consumable class might interact with the shelf, refrigerator, freezer, and/or box classes.\n",
51 | "\n",
52 | "Reading back through our description of consumables there is reference to a flammables cabinet that was not mentioned in our initial description of the problem. This is an iterative design process so we should go back and add a flammables cabinet class. "
53 | ]
54 | },
55 | {
56 | "cell_type": "markdown",
57 | "metadata": {},
58 | "source": [
59 | "If we expand our list to all the classes we plan to use we get the following:\n",
60 | "\n",
61 | "* __Items__\n",
62 | " * Attributes\n",
63 | " * Name\n",
64 | " * Description\n",
65 | " * Location\n",
66 | " * Methods\n",
67 | " * Update location\n",
68 | " * Interactions\n",
69 | " * Every other class except items and consumables\n",
70 | "* __Laboratory__\n",
71 | " * Attributes\n",
72 | " * ?\n",
73 | " * Methods\n",
74 | " * Search\n",
75 | " * Interactions\n",
76 | " * Every other class\n",
77 | "* __Equipment__\n",
78 | " * Attributes\n",
79 | " * Name\n",
80 | " * Description\n",
81 | " * Location\n",
82 | " * Methods\n",
83 | " * Update location\n",
84 | " * Interactions\n",
85 | " * Every other class except items and consumables\n",
86 | "* __Consumables__\n",
87 | " * Attributes\n",
88 | " * Name\n",
89 | " * Description\n",
90 | " * Location\n",
91 | " * Initial quantity\n",
92 | " * Current quantity\n",
93 | " * Storage temperature\n",
94 | " * Flammability\n",
95 | " * Methods\n",
96 | " * Update location\n",
97 | " * Update quantity remaining\n",
98 | " * Check for appropriate storage\n",
99 | " * Interactions\n",
100 | " * Every other class except equipment and items\n",
101 | "* __Rooms__\n",
102 | " * Attributes\n",
103 | " * Name\n",
104 | " * Description\n",
105 | " * Location\n",
106 | " * Storage locations within this location\n",
107 | " * Items stored here\n",
108 | " * Methods\n",
109 | " * Search\n",
110 | " * Interactions\n",
111 | " * Every other class\n",
112 | "* __Shelves__\n",
113 | " * Attributes\n",
114 | " * Name\n",
115 | " * Description\n",
116 | " * Location\n",
117 | " * Storage locations within this location\n",
118 | " * Items stored here\n",
119 | " * Methods\n",
120 | " * Search\n",
121 | " * Interactions\n",
122 | " * Every other class possible although refrigerator and freezer are unlikely\n",
123 | "* __Refrigerators__\n",
124 | " * Attributes\n",
125 | " * Name\n",
126 | " * Description\n",
127 | " * Location\n",
128 | " * Storage locations within this location\n",
129 | " * Items stored here\n",
130 | " * Temperature\n",
131 | " * Methods\n",
132 | " * Search\n",
133 | " * Interactions\n",
134 | " * Every other class possible although freezer and flammables cabinet unlikely\n",
135 | "* __Freezers__\n",
136 | " * Attributes\n",
137 | " * Name\n",
138 | " * Description\n",
139 | " * Location\n",
140 | " * Storage locations within this location\n",
141 | " * Items stored here\n",
142 | " * Temperature\n",
143 | " * Methods\n",
144 | " * Search\n",
145 | " * Interactions\n",
146 | " * Every other class possible although refrigerator and flammables cabinet unlikely\n",
147 | "* __Boxes__\n",
148 | " * Attributes\n",
149 | " * Name\n",
150 | " * Description\n",
151 | " * Location\n",
152 | " * Storage locations within this location\n",
153 | " * Items stored here\n",
154 | " * Methods\n",
155 | " * Search\n",
156 | " * Interactions\n",
157 | " * Every other class\n",
158 | "* __Flammables Cabinet__\n",
159 | " * Attributes\n",
160 | " * Name\n",
161 | " * Description\n",
162 | " * Location\n",
163 | " * Storage locations within this location\n",
164 | " * Items stored here\n",
165 | " * Methods\n",
166 | " * Search\n",
167 | " * Interactions\n",
168 | " * Every other class possible although refrigerator and freezer unlikely"
169 | ]
170 | },
171 | {
172 | "cell_type": "markdown",
173 | "metadata": {},
174 | "source": [
175 | "Although this is a long list careful examination reveals that there is a lot of repetition.\n",
176 | "\n",
177 | "Items and equipment are identical and consumables is similar, adding several extra attributes and methods.\n",
178 | "\n",
179 | "Rooms, shelves, refrigerators, freezers, boxes and flammables cabinet are all similar, only differing in the occasional attribute.\n",
180 | "\n",
181 | "Our three main groups are:\n",
182 | "* Laboratory\n",
183 | "* Items (Items, equipment, and consumables)\n",
184 | "* Locations (Rooms, shelves, refrigerators, freezers, boxes and flammables cabinet)\n",
185 | "\n",
186 | "So much duplication is problematic, it is diffcult to maintain and subject to greater risk of bugs. \n",
187 | "\n",
188 | "There is a better way - we can create a generic class with the shared functionality and then __inherit__ from it when we create the other classes.\n",
189 | "\n",
190 | "For example an Item class would contain the basic attributes and methods. The Equipment class could then inherit from this class without modification. The Consumable class would also inherit from Item and only add the extra attributes and methods uniquely need by the Consumable class."
191 | ]
192 | },
193 | {
194 | "cell_type": "code",
195 | "execution_count": null,
196 | "metadata": {
197 | "collapsed": true
198 | },
199 | "outputs": [],
200 | "source": [
201 | "class Item(object):\n",
202 | " \n",
203 | " \n",
204 | " def __init__(self, name, description, location):\n",
205 | " self.name = name\n",
206 | " self.description = description\n",
207 | " self.location = location\n",
208 | " \n",
209 | " \n",
210 | " def update_location(self, new_location):\n",
211 | " pass\n",
212 | "\n",
213 | "class Equipment(Item):\n",
214 | " pass\n",
215 | "\n",
216 | "class Consumable(Item):\n",
217 | " \n",
218 | " \n",
219 | " def __init__(self, name, description, location, initial_quantity, current_quantity, storage_temp, flammability):\n",
220 | " self.name = name\n",
221 | " self.description = description\n",
222 | " self.location = location\n",
223 | " self.initial_quantity = initial_quantity\n",
224 | " self.current_quantity = current_quantity\n",
225 | " self.flammability = flammability\n",
226 | " \n",
227 | " \n",
228 | " def update_quantity_remaining(self, amount):\n",
229 | " pass"
230 | ]
231 | },
232 | {
233 | "cell_type": "markdown",
234 | "metadata": {},
235 | "source": [
236 | "There is one other situation we should consider. Occasionally we will want a class of a particular type to always implement a particular method even though we are unable to implement that method in our parent class. We need some way of raising an error when the parent class is inherited and the method is not implemented.\n",
237 | "\n",
238 | "As a simple example consider a class representing length. We might create classes for meters, miles, feet, etc. Keeping the original units when performing operations (adding, subtracting, etc) would prevent rounding errors but each class would need custom logic.\n",
239 | "\n",
240 | "Returning to our laboratory inventory system one way we can implement this is below:"
241 | ]
242 | },
243 | {
244 | "cell_type": "code",
245 | "execution_count": 2,
246 | "metadata": {
247 | "collapsed": false
248 | },
249 | "outputs": [],
250 | "source": [
251 | "class Item(object):\n",
252 | " def safely_stored(self):\n",
253 | " raise NotImplementedError('override in subclass')\n",
254 | " \n",
255 | "class Consumable(Item):\n",
256 | " def safely_stored(self):\n",
257 | " return True"
258 | ]
259 | },
260 | {
261 | "cell_type": "code",
262 | "execution_count": 3,
263 | "metadata": {
264 | "collapsed": true
265 | },
266 | "outputs": [],
267 | "source": [
268 | "a = Item()"
269 | ]
270 | },
271 | {
272 | "cell_type": "code",
273 | "execution_count": 4,
274 | "metadata": {
275 | "collapsed": false
276 | },
277 | "outputs": [
278 | {
279 | "ename": "NotImplementedError",
280 | "evalue": "override in subclass",
281 | "output_type": "error",
282 | "traceback": [
283 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
284 | "\u001b[1;31mNotImplementedError\u001b[0m Traceback (most recent call last)",
285 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0ma\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msafely_stored\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
286 | "\u001b[1;32m\u001b[0m in \u001b[0;36msafely_stored\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mclass\u001b[0m \u001b[0mItem\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0msafely_stored\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mNotImplementedError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'override in subclass'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;32mclass\u001b[0m \u001b[0mConsumable\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mItem\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
287 | "\u001b[1;31mNotImplementedError\u001b[0m: override in subclass"
288 | ]
289 | }
290 | ],
291 | "source": [
292 | "a.safely_stored()"
293 | ]
294 | },
295 | {
296 | "cell_type": "code",
297 | "execution_count": 5,
298 | "metadata": {
299 | "collapsed": true
300 | },
301 | "outputs": [],
302 | "source": [
303 | "b = Consumable()"
304 | ]
305 | },
306 | {
307 | "cell_type": "code",
308 | "execution_count": 6,
309 | "metadata": {
310 | "collapsed": false
311 | },
312 | "outputs": [
313 | {
314 | "data": {
315 | "text/plain": [
316 | "True"
317 | ]
318 | },
319 | "execution_count": 6,
320 | "metadata": {},
321 | "output_type": "execute_result"
322 | }
323 | ],
324 | "source": [
325 | "b.safely_stored()"
326 | ]
327 | },
328 | {
329 | "cell_type": "markdown",
330 | "metadata": {},
331 | "source": [
332 | "A disadvantage with this approach is we only see the error message when we call the method. The error is in the way we implemented the class so it would be more intuitive to get an error earlier, when we first create the object.\n",
333 | "\n",
334 | "This can be achieved using the [abstract method decorator](https://docs.python.org/3.5/library/abc.html)."
335 | ]
336 | },
337 | {
338 | "cell_type": "code",
339 | "execution_count": 7,
340 | "metadata": {
341 | "collapsed": false
342 | },
343 | "outputs": [],
344 | "source": [
345 | "from abc import ABCMeta, abstractmethod\n",
346 | "\n",
347 | "class Item(metaclass=ABCMeta):\n",
348 | " @abstractmethod\n",
349 | " def safely_stored(self):\n",
350 | " pass\n",
351 | "\n",
352 | "class Consumable(Item):\n",
353 | " def safely_stored(self):\n",
354 | " return True"
355 | ]
356 | },
357 | {
358 | "cell_type": "code",
359 | "execution_count": 8,
360 | "metadata": {
361 | "collapsed": false
362 | },
363 | "outputs": [
364 | {
365 | "ename": "TypeError",
366 | "evalue": "Can't instantiate abstract class Item with abstract methods safely_stored",
367 | "output_type": "error",
368 | "traceback": [
369 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
370 | "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)",
371 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0ma\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mItem\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
372 | "\u001b[1;31mTypeError\u001b[0m: Can't instantiate abstract class Item with abstract methods safely_stored"
373 | ]
374 | }
375 | ],
376 | "source": [
377 | "a = Item()"
378 | ]
379 | },
380 | {
381 | "cell_type": "code",
382 | "execution_count": 9,
383 | "metadata": {
384 | "collapsed": false
385 | },
386 | "outputs": [
387 | {
388 | "data": {
389 | "text/plain": [
390 | "True"
391 | ]
392 | },
393 | "execution_count": 9,
394 | "metadata": {},
395 | "output_type": "execute_result"
396 | }
397 | ],
398 | "source": [
399 | "b = Consumable()\n",
400 | "b.safely_stored()"
401 | ]
402 | },
403 | {
404 | "cell_type": "markdown",
405 | "metadata": {
406 | "collapsed": true
407 | },
408 | "source": [
409 | "Either of these approaches work well for adding new methods or completely changing the behaviour of a method. Often we only need to make a more subtle change. In this situation it can be useful to call a method from a parent class while only implementing our new functionality in the child class.\n",
410 | "\n",
411 | "\n",
412 | "There are two approaches for this."
413 | ]
414 | },
415 | {
416 | "cell_type": "code",
417 | "execution_count": 1,
418 | "metadata": {
419 | "collapsed": false
420 | },
421 | "outputs": [
422 | {
423 | "name": "stdout",
424 | "output_type": "stream",
425 | "text": [
426 | "a in class A\n",
427 | "a in class A\n",
428 | "b in class B\n"
429 | ]
430 | }
431 | ],
432 | "source": [
433 | "class A(object):\n",
434 | " def a(self):\n",
435 | " print('a in class A')\n",
436 | "\n",
437 | "class B(A):\n",
438 | " def a(self):\n",
439 | " A.a(self)\n",
440 | " print('b in class B')\n",
441 | "\n",
442 | "a = A()\n",
443 | "a.a()\n",
444 | "\n",
445 | "b = B()\n",
446 | "b.a()"
447 | ]
448 | },
449 | {
450 | "cell_type": "code",
451 | "execution_count": 2,
452 | "metadata": {
453 | "collapsed": false
454 | },
455 | "outputs": [
456 | {
457 | "name": "stdout",
458 | "output_type": "stream",
459 | "text": [
460 | "a in class A\n",
461 | "a in class A\n",
462 | "b in class B\n"
463 | ]
464 | }
465 | ],
466 | "source": [
467 | "class A(object):\n",
468 | " def a(self):\n",
469 | " print('a in class A')\n",
470 | "\n",
471 | "class B(A):\n",
472 | " def a(self):\n",
473 | " super().a()\n",
474 | " print('b in class B')\n",
475 | "\n",
476 | "a = A()\n",
477 | "a.a()\n",
478 | "\n",
479 | "b = B()\n",
480 | "b.a()"
481 | ]
482 | },
483 | {
484 | "cell_type": "markdown",
485 | "metadata": {},
486 | "source": [
487 | "Using super() is usually the best approach, the reasons for this are covered in detail in [this blog post](https://rhettinger.wordpress.com/2011/05/26/super-considered-super/)"
488 | ]
489 | },
490 | {
491 | "cell_type": "markdown",
492 | "metadata": {},
493 | "source": [
494 | "## Multiple Inheritance\n",
495 | "\n",
496 | "We are not limited to inheriting from a single class. It is possible to merge functionality from multiple different classes simply by inheriting from them.\n",
497 | "\n",
498 | "When inheriting from multiple classes that contain a method or attribute with the same name there is a particular order in which the names are resolved."
499 | ]
500 | },
501 | {
502 | "cell_type": "code",
503 | "execution_count": 18,
504 | "metadata": {
505 | "collapsed": false
506 | },
507 | "outputs": [
508 | {
509 | "name": "stdout",
510 | "output_type": "stream",
511 | "text": [
512 | "A-a\n",
513 | "A2-a\n",
514 | "A-a\n"
515 | ]
516 | }
517 | ],
518 | "source": [
519 | "class A(object):\n",
520 | " def a(self):\n",
521 | " print('A-a')\n",
522 | "\n",
523 | "class A2(object):\n",
524 | " def a(self):\n",
525 | " print('A2-a')\n",
526 | "\n",
527 | "class B(A, A2):\n",
528 | " pass\n",
529 | "\n",
530 | "a = A()\n",
531 | "a.a()\n",
532 | "\n",
533 | "a2 = A2()\n",
534 | "a2.a()\n",
535 | "\n",
536 | "b = B()\n",
537 | "b.a()"
538 | ]
539 | },
540 | {
541 | "cell_type": "code",
542 | "execution_count": 21,
543 | "metadata": {
544 | "collapsed": false
545 | },
546 | "outputs": [
547 | {
548 | "name": "stdout",
549 | "output_type": "stream",
550 | "text": [
551 | "A-a\n",
552 | "A2-a\n",
553 | "A-a\n"
554 | ]
555 | }
556 | ],
557 | "source": [
558 | "class A(object):\n",
559 | " def a(self):\n",
560 | " print('A-a')\n",
561 | "\n",
562 | "class A2(object):\n",
563 | " def a(self):\n",
564 | " print('A2-a')\n",
565 | "\n",
566 | "class B(A):\n",
567 | " pass\n",
568 | "\n",
569 | "class C(B, A2):\n",
570 | " pass\n",
571 | "\n",
572 | "a = A()\n",
573 | "a.a()\n",
574 | "\n",
575 | "a2 = A2()\n",
576 | "a2.a()\n",
577 | "\n",
578 | "c = C()\n",
579 | "c.a()"
580 | ]
581 | },
582 | {
583 | "cell_type": "markdown",
584 | "metadata": {},
585 | "source": [
586 | "A simple rule-of-thumb is that search is depth first. [The details](https://en.wikipedia.org/wiki/C3_linearization) are a little more complicated."
587 | ]
588 | },
589 | {
590 | "cell_type": "markdown",
591 | "metadata": {},
592 | "source": [
593 | "## isinstance\n",
594 | "\n",
595 | "Often we need to check whether a particular variable is an instance of a particular class. For example, returning to our laboratory inventory system we would want to check that we only add instances of `Item` or its subclasses to our storage locations."
596 | ]
597 | },
598 | {
599 | "cell_type": "code",
600 | "execution_count": 11,
601 | "metadata": {
602 | "collapsed": false
603 | },
604 | "outputs": [
605 | {
606 | "data": {
607 | "text/plain": [
608 | "True"
609 | ]
610 | },
611 | "execution_count": 11,
612 | "metadata": {},
613 | "output_type": "execute_result"
614 | }
615 | ],
616 | "source": [
617 | "isinstance(a, Item)"
618 | ]
619 | },
620 | {
621 | "cell_type": "code",
622 | "execution_count": 12,
623 | "metadata": {
624 | "collapsed": false
625 | },
626 | "outputs": [
627 | {
628 | "data": {
629 | "text/plain": [
630 | "True"
631 | ]
632 | },
633 | "execution_count": 12,
634 | "metadata": {},
635 | "output_type": "execute_result"
636 | }
637 | ],
638 | "source": [
639 | "isinstance(b, Consumable)"
640 | ]
641 | },
642 | {
643 | "cell_type": "code",
644 | "execution_count": 13,
645 | "metadata": {
646 | "collapsed": false
647 | },
648 | "outputs": [
649 | {
650 | "data": {
651 | "text/plain": [
652 | "True"
653 | ]
654 | },
655 | "execution_count": 13,
656 | "metadata": {},
657 | "output_type": "execute_result"
658 | }
659 | ],
660 | "source": [
661 | "isinstance(b, Item)"
662 | ]
663 | },
664 | {
665 | "cell_type": "code",
666 | "execution_count": 14,
667 | "metadata": {
668 | "collapsed": false
669 | },
670 | "outputs": [
671 | {
672 | "data": {
673 | "text/plain": [
674 | "False"
675 | ]
676 | },
677 | "execution_count": 14,
678 | "metadata": {},
679 | "output_type": "execute_result"
680 | }
681 | ],
682 | "source": [
683 | "isinstance(a, Consumable)"
684 | ]
685 | },
686 | {
687 | "cell_type": "markdown",
688 | "metadata": {},
689 | "source": [
690 | "##Duck typing\n",
691 | "\n",
692 | "A popular alternative in python is duck typing, an approach named after the idea that,\n",
693 | "\n",
694 | "`If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.`\n",
695 | "\n",
696 | "What this means for programming is that instead of checking for a particular class, instead the methods and attributes that are actually needed are checked for."
697 | ]
698 | },
699 | {
700 | "cell_type": "markdown",
701 | "metadata": {},
702 | "source": [
703 | "## Graphical User Interfaces\n",
704 | "\n",
705 | "Object oriented programming and particularly inheritance is commonly used for creating GUIs. There are [a large number](https://wiki.python.org/moin/GuiProgramming) of different frameworks supporting building GUIs. The following are particularly relevant:\n",
706 | "\n",
707 | "* [TkInter](https://docs.python.org/3.5/library/tkinter.html) - This is the official/default GUI framework\n",
708 | "* [guidata](https://pythonhosted.org/guidata/) - A GUI framework for dataset display and editing\n",
709 | "* [VTK](http://www.vtk.org/) - A GUI framework for data visualization\n",
710 | "* [pyqtgraph](http://www.pyqtgraph.org/documentation/index.html) - A GUI framework for data visualization, easily installed with `conda install pyqtgraph`\n",
711 | "* [matplotlib](http://matplotlib.org/) - As well as creating plots matplotlib can support interaction"
712 | ]
713 | },
714 | {
715 | "cell_type": "code",
716 | "execution_count": null,
717 | "metadata": {
718 | "collapsed": true
719 | },
720 | "outputs": [],
721 | "source": []
722 | }
723 | ],
724 | "metadata": {
725 | "kernelspec": {
726 | "display_name": "Python 3",
727 | "language": "python",
728 | "name": "python3"
729 | },
730 | "language_info": {
731 | "codemirror_mode": {
732 | "name": "ipython",
733 | "version": 3
734 | },
735 | "file_extension": ".py",
736 | "mimetype": "text/x-python",
737 | "name": "python",
738 | "nbconvert_exporter": "python",
739 | "pygments_lexer": "ipython3",
740 | "version": "3.4.3"
741 | }
742 | },
743 | "nbformat": 4,
744 | "nbformat_minor": 0
745 | }
746 |
--------------------------------------------------------------------------------
/Wk03/Wk03-Paradigms.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Week 3 - Programming Paradigms\n",
8 | "\n",
9 | "## Learning Objectives\n",
10 | "\n",
11 | "* List popular programming paradigms\n",
12 | "* Demonstrate object oriented programming\n",
13 | "* Compare procedural programming and object oriented programming\n",
14 | "* Apply object oriented programming to solve sample problems"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {
20 | "collapsed": false
21 | },
22 | "source": [
23 | "Computer programs and the elements they contain can be built in a variety of different ways. Several different styles, or paradigms, exist with differing popularity and usefulness for different tasks.\n",
24 | "\n",
25 | "Some programming languages are designed to support a particular paradigm, while other languages support several different paradigms.\n",
26 | "\n",
27 | "Three of the most commonly used paradigms are:\n",
28 | "\n",
29 | "* Procedural\n",
30 | "* Object oriented\n",
31 | "* Functional\n",
32 | "\n",
33 | "Python supports each of these paradigms. "
34 | ]
35 | },
36 | {
37 | "cell_type": "markdown",
38 | "metadata": {
39 | "collapsed": true
40 | },
41 | "source": [
42 | "## Procedural"
43 | ]
44 | },
45 | {
46 | "cell_type": "markdown",
47 | "metadata": {},
48 | "source": [
49 | "You may not have realized it but the procedural programming paradigm is probably the approach you are currently taking with your programs.\n",
50 | "\n",
51 | "Programs and functions are simply a series of steps to be performed. \n",
52 | "\n",
53 | "For example:"
54 | ]
55 | },
56 | {
57 | "cell_type": "code",
58 | "execution_count": 67,
59 | "metadata": {
60 | "collapsed": false
61 | },
62 | "outputs": [
63 | {
64 | "name": "stdout",
65 | "output_type": "stream",
66 | "text": [
67 | "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]\n"
68 | ]
69 | }
70 | ],
71 | "source": [
72 | "primes = []\n",
73 | "i = 2\n",
74 | "while len(primes) < 25:\n",
75 | " for p in primes:\n",
76 | " if i % p == 0:\n",
77 | " break\n",
78 | " else:\n",
79 | " primes.append(i)\n",
80 | " i += 1\n",
81 | "\n",
82 | "print(primes)"
83 | ]
84 | },
85 | {
86 | "cell_type": "markdown",
87 | "metadata": {},
88 | "source": [
89 | "## Functional"
90 | ]
91 | },
92 | {
93 | "cell_type": "markdown",
94 | "metadata": {
95 | "collapsed": true
96 | },
97 | "source": [
98 | "Functional programming is based on the evaluation of mathematical functions. This is a more restricted form of function than you may have used previously - mutable data and changing state is avoided. This makes understanding how a program will behave more straightforward.\n",
99 | "\n",
100 | "Python does support functional programming although it is not as widely used as procedural and object oriented programming. Some languages better known for supporting functional programming include Lisp, Clojure, Erlang, and Haskell."
101 | ]
102 | },
103 | {
104 | "cell_type": "markdown",
105 | "metadata": {},
106 | "source": [
107 | "### Functions - Mathematical vs subroutines\n",
108 | "\n",
109 | "In the general sense, functions can be thought of as simply wrappers around blocks of code. In this sense they can also be thought of as subroutines. Importantly they can be written to fetch data and change the program state independently of the function arguments.\n",
110 | "\n",
111 | "In functional programming the output of a function should depend solely on the function arguments."
112 | ]
113 | },
114 | {
115 | "cell_type": "markdown",
116 | "metadata": {},
117 | "source": [
118 | "There is an extensive howto in the [python documentation](https://docs.python.org/3.5/howto/functional.html).\n",
119 | "\n",
120 | "[This presentation from PyCon US 2013](https://www.youtube.com/watch?v=Ta1bAMOMFOI) is also worth watching.\n",
121 | "\n",
122 | "[This presentation from PyGotham 2014](https://www.youtube.com/watch?v=yW0cK3IxlHc) covers decorators specifically."
123 | ]
124 | },
125 | {
126 | "cell_type": "code",
127 | "execution_count": 68,
128 | "metadata": {
129 | "collapsed": false
130 | },
131 | "outputs": [
132 | {
133 | "name": "stdout",
134 | "output_type": "stream",
135 | "text": [
136 | "0\n",
137 | "1\n",
138 | "2\n",
139 | "3\n",
140 | "4\n",
141 | "Squared from list:\n",
142 | "[0, 1, 4, 9, 16]\n",
143 | "Squared from iterable:\n",
144 | " at 0x7fa208be2510>\n"
145 | ]
146 | }
147 | ],
148 | "source": [
149 | "def square(val):\n",
150 | " print(val)\n",
151 | " return val ** 2\n",
152 | "\n",
153 | "squared_numbers = [square(i) for i in range(5)]\n",
154 | "print('Squared from list:')\n",
155 | "print(squared_numbers)\n",
156 | "\n",
157 | "squared_numbers = (square(i) for i in range(5))\n",
158 | "print('Squared from iterable:')\n",
159 | "print(squared_numbers)"
160 | ]
161 | },
162 | {
163 | "cell_type": "code",
164 | "execution_count": 69,
165 | "metadata": {
166 | "collapsed": false
167 | },
168 | "outputs": [
169 | {
170 | "name": "stdout",
171 | "output_type": "stream",
172 | "text": [
173 | "\n",
174 | "0\n",
175 | "1\n",
176 | "4\n",
177 | "9\n",
178 | "16\n",
179 | "This is only printed after all the numbers output have been consumed\n"
180 | ]
181 | }
182 | ],
183 | "source": [
184 | "def squared_numbers(num):\n",
185 | " for i in range(num):\n",
186 | " yield i ** 2\n",
187 | " print('This is only printed after all the numbers output have been consumed')\n",
188 | "\n",
189 | "print(squared_numbers(5))\n",
190 | "for i in squared_numbers(5):\n",
191 | " print(i)"
192 | ]
193 | },
194 | {
195 | "cell_type": "code",
196 | "execution_count": 70,
197 | "metadata": {
198 | "collapsed": false
199 | },
200 | "outputs": [
201 | {
202 | "data": {
203 | "text/plain": [
204 | "10"
205 | ]
206 | },
207 | "execution_count": 70,
208 | "metadata": {},
209 | "output_type": "execute_result"
210 | }
211 | ],
212 | "source": [
213 | "import functools\n",
214 | "\n",
215 | "def plus(val, n):\n",
216 | " return val + n\n",
217 | "\n",
218 | "\n",
219 | "f = functools.partial(plus, 5)\n",
220 | "f(5)"
221 | ]
222 | },
223 | {
224 | "cell_type": "code",
225 | "execution_count": 71,
226 | "metadata": {
227 | "collapsed": false
228 | },
229 | "outputs": [
230 | {
231 | "name": "stdout",
232 | "output_type": "stream",
233 | "text": [
234 | "before\n",
235 | "decorated\n",
236 | "after\n"
237 | ]
238 | }
239 | ],
240 | "source": [
241 | "def decorator(inner):\n",
242 | " def inner_decorator():\n",
243 | " print('before')\n",
244 | " inner()\n",
245 | " print('after')\n",
246 | " return inner_decorator\n",
247 | "\n",
248 | "def decorated():\n",
249 | " print('decorated')\n",
250 | "\n",
251 | "f = decorator(decorated)\n",
252 | "f()"
253 | ]
254 | },
255 | {
256 | "cell_type": "code",
257 | "execution_count": 72,
258 | "metadata": {
259 | "collapsed": false
260 | },
261 | "outputs": [
262 | {
263 | "name": "stdout",
264 | "output_type": "stream",
265 | "text": [
266 | "before\n",
267 | "decorated\n",
268 | "after\n"
269 | ]
270 | }
271 | ],
272 | "source": [
273 | "@decorator\n",
274 | "def decorated():\n",
275 | " print('decorated')\n",
276 | " \n",
277 | "decorated()"
278 | ]
279 | },
280 | {
281 | "cell_type": "code",
282 | "execution_count": 73,
283 | "metadata": {
284 | "collapsed": false
285 | },
286 | "outputs": [
287 | {
288 | "name": "stdout",
289 | "output_type": "stream",
290 | "text": [
291 | "1\n",
292 | "1.0271596908569336\n",
293 | "0.0001976490020751953\n",
294 | "2\n",
295 | "1.0024516582489014\n"
296 | ]
297 | }
298 | ],
299 | "source": [
300 | "import time\n",
301 | "\n",
302 | "@functools.lru_cache()\n",
303 | "def slow_compute(n):\n",
304 | " time.sleep(1)\n",
305 | " print(n)\n",
306 | "\n",
307 | "start = time.time()\n",
308 | "slow_compute(1)\n",
309 | "print(time.time() - start)\n",
310 | "\n",
311 | "start = time.time()\n",
312 | "slow_compute(1)\n",
313 | "print(time.time() - start)\n",
314 | "\n",
315 | "start = time.time()\n",
316 | "slow_compute(2)\n",
317 | "print(time.time() - start)"
318 | ]
319 | },
320 | {
321 | "cell_type": "markdown",
322 | "metadata": {},
323 | "source": [
324 | "## Object oriented"
325 | ]
326 | },
327 | {
328 | "cell_type": "markdown",
329 | "metadata": {},
330 | "source": [
331 | "Object oriented programming is a paradigm that combines data with code into objects. The code can interact with and modify the data in an object. A program will be separated out into a number of different objects that interact with each other.\n",
332 | "\n",
333 | "Object oriented programming is a widely used paradigm and a variety of different languages support it including Python, C++, Java, PHP, Ruby, and many others.\n",
334 | "\n",
335 | "Each of these languages use slightly different syntax but the underlying design choices will be the same in each language. \n",
336 | "\n",
337 | "Objects __are__ things, their names often recognise this and are nouns. These might be physical things like a chair, or concepts like a number. \n",
338 | "\n",
339 | "While procedural programs make use of global information, object oriented design forgoes this global knowledge in favor of local knowledge. Objects contain information and can __do__ things. The information they contain are in attributes. The things they can do are in their methods (similar to functions, but attached to the object).\n",
340 | "\n",
341 | "Finally, to achieve the objective of the program objects must interact.\n",
342 | "\n",
343 | "We will look at the python syntax for creating objects later, first let's explore how objects might work in various scenarios. "
344 | ]
345 | },
346 | {
347 | "cell_type": "markdown",
348 | "metadata": {},
349 | "source": [
350 | "##Designing Object Oriented Programs\n",
351 | "\n",
352 | "These are the simple building blocks for classes and objects. Just as with the other programming constructs available in python, although the language is relatively simple if used effectively they are very powerful.\n",
353 | "\n",
354 | "[Learn Python the Hard Way](http://learnpythonthehardway.org/book/ex43.html) has a very good description of how to design a program using the object oriented programming paradigm. The linked exercise particularly is worth reading.\n",
355 | "\n",
356 | "The best place to start is describing the problem. What are you trying to do? What are the items involved?"
357 | ]
358 | },
359 | {
360 | "cell_type": "markdown",
361 | "metadata": {
362 | "collapsed": false
363 | },
364 | "source": [
365 | "###Example 1: A Laboratory Inventory\n",
366 | "\n",
367 | "I would like to keep track of all the __items__ in the __laboratory__ so I can easily find them the next time I need them. Both __equipment__ and __consumables__ would be tracked. We have multiple __rooms__, and items can be on __shelves__, in __refrigerators__, in __freezers__, etc. Items can also be in __boxes__ containing other items in all these places.\n",
368 | "\n",
369 | "The words in __bold__ would all be good ideas to turn into classes. Now we know some of the classes we will need we can start to think about what each of these classes should do, what the methods will be. Let's consider the consumables class:\n",
370 | "\n",
371 | "For consumables we will need to manage their use so there should be an initial quantity and a quantity remaining that is updated every time we use some. We want to make sure that temperature sensitive consumables are always stored at the correct temperature, and that flammables are stored in a flammables cabinet etc.\n",
372 | "\n",
373 | "The consumable class will need a number of attributes:\n",
374 | "\n",
375 | "* Initial quantity\n",
376 | "* Current quantity\n",
377 | "* Storage temperature\n",
378 | "* Flammability\n",
379 | "\n",
380 | "The consumable class will need methods to:\n",
381 | "\n",
382 | "* Update the quantity remaining\n",
383 | "* Check for improper storage?\n",
384 | "\n",
385 | "The consumable class might interact with the shelf, refrigerator, freezer, and/or box classes.\n",
386 | "\n",
387 | "Reading back through our description of consumables there is reference to a flammables cabinet that was not mentioned in our initial description of the problem. This is an iterative design process so we should go back and add a flammables cabinet class. "
388 | ]
389 | },
390 | {
391 | "cell_type": "markdown",
392 | "metadata": {},
393 | "source": [
394 | "###Exercise: A Chart\n",
395 | "\n",
396 | "We have used matplotlib several times now to generate charts. If we were to create a charting library ourselves what are the objects we would use?\n",
397 | "\n",
398 | "I would like to plot some data on a chart. The data, as a series of points and lines, would be placed on a set of x-y axes that are numbered and labeled to accurately describe the data. There should be a grid so that values can be easily read from the chart.\n",
399 | "\n",
400 | "What are the classes you would use to create this plot?\n",
401 | "\n",
402 | "Pick one class and describe the methods it would have, and the other classes it might interact with."
403 | ]
404 | },
405 | {
406 | "cell_type": "code",
407 | "execution_count": null,
408 | "metadata": {
409 | "collapsed": true
410 | },
411 | "outputs": [],
412 | "source": [
413 | "DISCUSSED IN CLASS\n",
414 | "\n",
415 | "Classes: \n",
416 | "data\n",
417 | "style\n",
418 | "source\n",
419 | "axes\n",
420 | "grid \n",
421 | "legend\n",
422 | "points\n",
423 | "lines\n",
424 | " - draw\n",
425 | " - position\n",
426 | " - color\n",
427 | " - size / thickness\n",
428 | " - symbol\n",
429 | " - slope / intercept\n",
430 | " - text representation\n",
431 | "figure\n",
432 | "plot\n",
433 | "title\n",
434 | "labels\n",
435 | "text"
436 | ]
437 | },
438 | {
439 | "cell_type": "markdown",
440 | "metadata": {},
441 | "source": [
442 | "###Exercise 2: A Cookbook\n",
443 | "\n",
444 | "A system to manage different recipes, with their ingredients, equipment needed and instructions. Recipes should be scalable to different numbers of servings with the amount of ingredients adjusted appropriately and viewable in metric and imperial units. Nutritional information should be tracked.\n",
445 | "\n",
446 | "What are the classes you would use to create this system?\n",
447 | "\n",
448 | "Pick one class and describe the methods it would have, and the other classes it might interact with."
449 | ]
450 | },
451 | {
452 | "cell_type": "code",
453 | "execution_count": null,
454 | "metadata": {
455 | "collapsed": true
456 | },
457 | "outputs": [],
458 | "source": [
459 | "DISCUSSED IN CLASS\n",
460 | "\n",
461 | "classes:\n",
462 | "appetizers\n",
463 | "main courses\n",
464 | "desserts\n",
465 | "recipe\n",
466 | " __Attributes/Methods__\n",
467 | " - preparation time\n",
468 | " - cooking time\n",
469 | " - serving portion\n",
470 | " - servings\n",
471 | " - name\n",
472 | " - nutritional information\n",
473 | " - ingredients\n",
474 | " - methods\n",
475 | " - scaling\n",
476 | " - equipment\n",
477 | " - special occasion \n",
478 | " - instructions\n",
479 | " __Interactions__\n",
480 | " - Cookbook\n",
481 | " - Ingredients\n",
482 | " - Instructions\n",
483 | " - Nutrition\n",
484 | " - Equipment\n",
485 | " - Scaling\n",
486 | " - Portions\n",
487 | "servings\n",
488 | "ingredients\n",
489 | " - quantity (mass/volume)\n",
490 | " - units\n",
491 | " - nutritional info\n",
492 | " - specific dietary info\n",
493 | " - cost\n",
494 | " - storage temperature\n",
495 | " - sustitute options\n",
496 | " - name\n",
497 | " - translations\n",
498 | " - alternative names\n",
499 | " - special handling instructions\n",
500 | " - sources\n",
501 | " * can interact with the following classes:\n",
502 | " * recipe\n",
503 | " * Instructions\n",
504 | " * Equipment\n",
505 | " * nutrition \n",
506 | " * scaling\n",
507 | " * portions \n",
508 | " * cookbook\n",
509 | " * units\n",
510 | "solid ingredients\n",
511 | "liquid ingredients\n",
512 | "equipment\n",
513 | "instructions\n",
514 | "nutritional info\n",
515 | "style\n",
516 | "units conversion\n",
517 | "scaling \n",
518 | "portions\n",
519 | "cookbook\n",
520 | "\n",
521 | "(recipe class can have an attribute, list of ingredients which are instances of another class themselves)\n",
522 | "(classes interact with each other often in an app like this)\n",
523 | "(instructions can be a class, and an instance of it can be saved as an attribute in Recipe class)"
524 | ]
525 | },
526 | {
527 | "cell_type": "markdown",
528 | "metadata": {
529 | "collapsed": true
530 | },
531 | "source": [
532 | "[Building Skills in Object Oriented Design](http://www.itmaybeahack.com/homepage/books/oodesign.html) is a good resource to learn more about this process.\n",
533 | "\n",
534 | "##Syntax\n",
535 | "\n",
536 | "Now let's look at the syntax we use to work with objects in python.\n",
537 | "\n",
538 | "There is a tutorial in the [python documentation](https://docs.python.org/3.5/tutorial/classes.html)."
539 | ]
540 | },
541 | {
542 | "cell_type": "markdown",
543 | "metadata": {},
544 | "source": [
545 | "Before we use an object in our program we must first define it. Just as we define a function with the *def* keyword, we use *class* to define a class. What is a class? Think of it as the template, or blueprint from which our objects will be made.\n",
546 | "\n",
547 | "Remember that in addition to code, objects can also contain data that can change so we may have many different instances of an object. Although each may contain different data they are all formed from the same class definition.\n",
548 | "\n",
549 | "As an example:"
550 | ]
551 | },
552 | {
553 | "cell_type": "code",
554 | "execution_count": 74,
555 | "metadata": {
556 | "collapsed": false
557 | },
558 | "outputs": [
559 | {
560 | "name": "stdout",
561 | "output_type": "stream",
562 | "text": [
563 | "<__main__.Person object at 0x7fa208c0b240> <__main__.Person object at 0x7fa208c0b128>\n"
564 | ]
565 | }
566 | ],
567 | "source": [
568 | "class Person(object):\n",
569 | " \"\"\"A class definition for a person. The following attributes are supported:\n",
570 | " \n",
571 | " Attributes:\n",
572 | " name: A string representing the person's name.\n",
573 | " age: An integer representing the person's age.\"\"\"\n",
574 | "\n",
575 | " mammal = True\n",
576 | " \n",
577 | " \n",
578 | " def __init__(self, name, age):\n",
579 | " \"\"\"Return a Person object with name and age set to the values supplied\"\"\"\n",
580 | " self.name = name\n",
581 | " self.age = age\n",
582 | "\n",
583 | "\n",
584 | "person1 = Person('Alice', 25)\n",
585 | "person2 = Person('Bob', 30)\n",
586 | "\n",
587 | "print(person1, person2)\n"
588 | ]
589 | },
590 | {
591 | "cell_type": "markdown",
592 | "metadata": {},
593 | "source": [
594 | "There is a lot happening above.\n",
595 | "\n",
596 | "__class Person(object):__ The *class* keyword begins the definition of our class. Here, we are naming the class *Person*. Next, *(object)* means that this class will inherit from the object class. This is not strictly necessary but is generally good practice. Inheritance will be discussed in greater depth next week. Finally, just as for a function definition we finish with a *colon*.\n",
597 | "\n",
598 | "__\"\"\"Documentation\"\"\"__ Next, a docstring provides important notes on usage.\n",
599 | "\n",
600 | "__mammal = True__ This is a class attribute. This is useful for defining data that our objects will need that is the same for all instances.\n",
601 | "\n",
602 | "**def __init__(self, name, age):** This is a method definition. The *def* keyword is used just as for functions. The first parameter here is *self* which refers to the object this method will be part of. The double underscores around the method name signify that this is a special method. In this case the \\_\\_init\\_\\_ method is called when the object is first instantiated.\n",
603 | "\n",
604 | "__self.name = name__ A common reason to define an \\_\\_init\\_\\_ method is to set instance attributes. In this class, name and age are set to the values supplied.\n",
605 | "\n",
606 | "\n",
607 | "That is all there is to this class definition. Next, we create two instances of this class. The values supplied will be passed to the \\_\\_init\\_\\_ method.\n",
608 | "\n",
609 | "Printing these objects don't provide a useful description of what they are. We can improve on this with another special method."
610 | ]
611 | },
612 | {
613 | "cell_type": "code",
614 | "execution_count": 75,
615 | "metadata": {
616 | "collapsed": false
617 | },
618 | "outputs": [
619 | {
620 | "name": "stdout",
621 | "output_type": "stream",
622 | "text": [
623 | "Alice who is 25 years old. Bob who is 30 years old.\n"
624 | ]
625 | }
626 | ],
627 | "source": [
628 | "class Person(object):\n",
629 | " \"\"\"A class definition for a person. The following attributes are supported:\n",
630 | " \n",
631 | " Attributes:\n",
632 | " name: A string representing the person's name.\n",
633 | " age: An integer representing the person's age.\"\"\"\n",
634 | "\n",
635 | " mammal = True\n",
636 | " \n",
637 | " \n",
638 | " def __init__(self, name, age):\n",
639 | " \"\"\"Return a Person object with name and age set to the values supplied\"\"\"\n",
640 | " self.name = name\n",
641 | " self.age = age\n",
642 | " \n",
643 | " \n",
644 | " def __str__(self):\n",
645 | " return '{0} who is {1} years old.'.format(self.name, self.age)\n",
646 | "\n",
647 | "\n",
648 | "person1 = Person('Alice', 25)\n",
649 | "person2 = Person('Bob', 30)\n",
650 | "\n",
651 | "print(person1, person2)"
652 | ]
653 | },
654 | {
655 | "cell_type": "markdown",
656 | "metadata": {},
657 | "source": [
658 | "[There are many more special methods](https://docs.python.org/3.5/reference/datamodel.html#special-method-names)."
659 | ]
660 | },
661 | {
662 | "cell_type": "markdown",
663 | "metadata": {},
664 | "source": [
665 | "Before we go on a note of caution is needed for class attributes. If only using strings and numbers the behaviour will likely be much as you expect. However, if using a list, dictionary, or other similar type you may get a surprise."
666 | ]
667 | },
668 | {
669 | "cell_type": "code",
670 | "execution_count": 76,
671 | "metadata": {
672 | "collapsed": false
673 | },
674 | "outputs": [
675 | {
676 | "name": "stdout",
677 | "output_type": "stream",
678 | "text": [
679 | "['Charlie', 'Danielle'] ['Charlie', 'Danielle']\n"
680 | ]
681 | }
682 | ],
683 | "source": [
684 | "class Person(object):\n",
685 | " \"\"\"A class definition for a person. The following attributes are supported:\n",
686 | " \n",
687 | " Attributes:\n",
688 | " name: A string representing the person's name.\n",
689 | " age: An integer representing the person's age.\"\"\"\n",
690 | "\n",
691 | " friends = []\n",
692 | " \n",
693 | " \n",
694 | " def __init__(self, name, age):\n",
695 | " \"\"\"Return a Person object with name and age set to the values supplied\"\"\"\n",
696 | " self.name = name\n",
697 | " self.age = age\n",
698 | " \n",
699 | " \n",
700 | " def __str__(self):\n",
701 | " return '{0} who is {1} years old'.format(self.name, self.age)\n",
702 | "\n",
703 | "\n",
704 | "person1 = Person('Alice', 25)\n",
705 | "person2 = Person('Bob', 30)\n",
706 | "\n",
707 | "person1.friends.append('Charlie')\n",
708 | "person2.friends.append('Danielle')\n",
709 | "\n",
710 | "print(person1.friends, person2.friends)"
711 | ]
712 | },
713 | {
714 | "cell_type": "markdown",
715 | "metadata": {},
716 | "source": [
717 | "Both of our objects point to the same instance of the list type so adding a new friend to either object shows up in both.\n",
718 | "\n",
719 | "The solution to this is creating our *friends* attribute only at instantiation of the object. This can be done by creating it in the \\_\\_init\\_\\_ method."
720 | ]
721 | },
722 | {
723 | "cell_type": "code",
724 | "execution_count": 77,
725 | "metadata": {
726 | "collapsed": false
727 | },
728 | "outputs": [
729 | {
730 | "name": "stdout",
731 | "output_type": "stream",
732 | "text": [
733 | "['Charlie'] ['Danielle']\n"
734 | ]
735 | }
736 | ],
737 | "source": [
738 | "class Person(object):\n",
739 | " \"\"\"A class definition for a person. The following attributes are supported:\n",
740 | " \n",
741 | " Attributes:\n",
742 | " name: A string representing the person's name.\n",
743 | " age: An integer representing the person's age.\"\"\"\n",
744 | "\n",
745 | " \n",
746 | " \n",
747 | " def __init__(self, name, age):\n",
748 | " \"\"\"Return a Person object with name and age set to the values supplied\"\"\"\n",
749 | " self.name = name\n",
750 | " self.age = age\n",
751 | " self.friends = []\n",
752 | " \n",
753 | " \n",
754 | " def __str__(self):\n",
755 | " return '{0} who is {1} years old'.format(self.name, self.age)\n",
756 | "\n",
757 | "\n",
758 | "person1 = Person('Alice', 25)\n",
759 | "person2 = Person('Bob', 30)\n",
760 | "\n",
761 | "person1.friends.append('Charlie')\n",
762 | "person2.friends.append('Danielle')\n",
763 | "\n",
764 | "print(person1.friends, person2.friends)"
765 | ]
766 | },
767 | {
768 | "cell_type": "markdown",
769 | "metadata": {
770 | "collapsed": true
771 | },
772 | "source": [
773 | "Objects have their own namespace, although we have created variables called name, age, and friends they can only be accessed in the context of the object."
774 | ]
775 | },
776 | {
777 | "cell_type": "code",
778 | "execution_count": 78,
779 | "metadata": {
780 | "collapsed": false
781 | },
782 | "outputs": [
783 | {
784 | "name": "stdout",
785 | "output_type": "stream",
786 | "text": [
787 | "This works: ['Charlie']\n"
788 | ]
789 | },
790 | {
791 | "ename": "NameError",
792 | "evalue": "name 'friends' is not defined",
793 | "output_type": "error",
794 | "traceback": [
795 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
796 | "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
797 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'This works:'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mperson1\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfriends\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'This does not work:'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfriends\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
798 | "\u001b[1;31mNameError\u001b[0m: name 'friends' is not defined"
799 | ]
800 | }
801 | ],
802 | "source": [
803 | "print('This works:', person1.friends)\n",
804 | "print('This does not work:', friends)"
805 | ]
806 | },
807 | {
808 | "cell_type": "markdown",
809 | "metadata": {},
810 | "source": [
811 | "We are not limited to special methods when creating classes. Standard functions, or in this context methods, are an integral part of object oriented programming. Their definition is identical to special methods and functions outside of classes."
812 | ]
813 | },
814 | {
815 | "cell_type": "code",
816 | "execution_count": 79,
817 | "metadata": {
818 | "collapsed": false
819 | },
820 | "outputs": [
821 | {
822 | "name": "stdout",
823 | "output_type": "stream",
824 | "text": [
825 | "['Charlie'] ['Danielle']\n"
826 | ]
827 | }
828 | ],
829 | "source": [
830 | "class Person(object):\n",
831 | " \"\"\"A class definition for a person. The following attributes are supported:\n",
832 | " \n",
833 | " Attributes:\n",
834 | " name: A string representing the person's name.\n",
835 | " age: An integer representing the person's age.\"\"\"\n",
836 | "\n",
837 | " \n",
838 | " \n",
839 | " def __init__(self, name, age):\n",
840 | " \"\"\"Return a Person object with name and age set to the values supplied\"\"\"\n",
841 | " self.name = name\n",
842 | " self.age = age\n",
843 | " self.friends = []\n",
844 | " \n",
845 | " \n",
846 | " def __str__(self):\n",
847 | " \"\"\"Return a string representation of the object\"\"\"\n",
848 | " return '{0} who is {1} years old'.format(self.name, self.age)\n",
849 | " \n",
850 | " \n",
851 | " def add_friend(self, friend):\n",
852 | " \"\"\"Add a friend\"\"\"\n",
853 | " self.friends.append(friend)\n",
854 | "\n",
855 | " \n",
856 | "person1 = Person('Alice', 25)\n",
857 | "person2 = Person('Bob', 30)\n",
858 | "\n",
859 | "person1.add_friend('Charlie')\n",
860 | "person2.add_friend('Danielle')\n",
861 | "\n",
862 | "print(person1.friends, person2.friends)"
863 | ]
864 | },
865 | {
866 | "cell_type": "markdown",
867 | "metadata": {},
868 | "source": [
869 | "###Private vs Public\n",
870 | "\n",
871 | "Some programming languages support hiding methods and attributes in an object. This can be useful to simplify the public interface someone using the class will see while still breaking up components into manageable blocks 'under-the-hood'. We will discuss designing the public interface in detail in week 5.\n",
872 | "\n",
873 | "Python does not support private variables beyond convention. Names prefixed with a underscore are assumed to be private. This means they may be changed without warning between different versions of the package. For public attributes/methods this is highly discouraged."
874 | ]
875 | },
876 | {
877 | "cell_type": "markdown",
878 | "metadata": {},
879 | "source": [
880 | "### Glossary\n",
881 | "\n",
882 | "__Class__: Our definition, or template, for an object.\n",
883 | "\n",
884 | "__Object__: An instance of a class.\n",
885 | "\n",
886 | "__Method__: A function that belongs to an object\n",
887 | "\n",
888 | "__Attribute__: A characteristic of an object, these can be data attributes and methods."
889 | ]
890 | },
891 | {
892 | "cell_type": "markdown",
893 | "metadata": {},
894 | "source": [
895 | "##Exercises\n",
896 | "\n",
897 | "Please send to me prior to class next week.\n",
898 | "\n"
899 | ]
900 | },
901 | {
902 | "cell_type": "markdown",
903 | "metadata": {},
904 | "source": [
905 | "* Pick one of the examples above (the laboratory inventory manager, the chart or the cookbook) and write out the classes it requires with their methods. You don't need to complete the code in the methods, using the `pass` keyword can act as a placeholder, e.g."
906 | ]
907 | },
908 | {
909 | "cell_type": "code",
910 | "execution_count": 80,
911 | "metadata": {
912 | "collapsed": true
913 | },
914 | "outputs": [],
915 | "source": [
916 | "class Test(object):\n",
917 | " \n",
918 | " \n",
919 | " def do_something(self):\n",
920 | " pass"
921 | ]
922 | },
923 | {
924 | "cell_type": "markdown",
925 | "metadata": {},
926 | "source": [
927 | "* Add documentation to the classes and their methods"
928 | ]
929 | },
930 | {
931 | "cell_type": "code",
932 | "execution_count": null,
933 | "metadata": {
934 | "collapsed": true
935 | },
936 | "outputs": [],
937 | "source": []
938 | }
939 | ],
940 | "metadata": {
941 | "kernelspec": {
942 | "display_name": "Python 3",
943 | "language": "python",
944 | "name": "python3"
945 | },
946 | "language_info": {
947 | "codemirror_mode": {
948 | "name": "ipython",
949 | "version": 3
950 | },
951 | "file_extension": ".py",
952 | "mimetype": "text/x-python",
953 | "name": "python",
954 | "nbconvert_exporter": "python",
955 | "pygments_lexer": "ipython3",
956 | "version": "3.5.1"
957 | }
958 | },
959 | "nbformat": 4,
960 | "nbformat_minor": 0
961 | }
962 |
--------------------------------------------------------------------------------
/Wk01/Wk01-Overview.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Week 1 - Getting Started"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 3,
13 | "metadata": {
14 | "collapsed": false
15 | },
16 | "outputs": [
17 | {
18 | "name": "stdout",
19 | "output_type": "stream",
20 | "text": [
21 | "Numpy: 1.10.4\n"
22 | ]
23 | }
24 | ],
25 | "source": [
26 | "import numpy as np\n",
27 | "\n",
28 | "print(\"Numpy:\", np.__version__)"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "#Python Summary\n",
36 | "\n",
37 | "##Further information\n",
38 | "\n",
39 | "More information is usually available with the `help` function. Using ? brings up the same information in ipython. \n",
40 | "\n",
41 | "Using the `dir` function lists all the options available from a variable."
42 | ]
43 | },
44 | {
45 | "cell_type": "markdown",
46 | "metadata": {},
47 | "source": [
48 | "help(np)\n",
49 | "\n",
50 | "np?\n",
51 | "\n",
52 | "dir(np)"
53 | ]
54 | },
55 | {
56 | "cell_type": "markdown",
57 | "metadata": {},
58 | "source": [
59 | "##Variables\n",
60 | "\n",
61 | "A variable is simply a name for something. One of the simplest tasks is printing the value of a variable.\n",
62 | "\n",
63 | "Printing can be customized using the format method on strings."
64 | ]
65 | },
66 | {
67 | "cell_type": "code",
68 | "execution_count": 13,
69 | "metadata": {
70 | "collapsed": false
71 | },
72 | "outputs": [
73 | {
74 | "name": "stdout",
75 | "output_type": "stream",
76 | "text": [
77 | "We're in Bethesda zip code 20892 , 71.9 m above sea level\n",
78 | "We're in Bethesda zip code 20892, 71.9m above sea level\n",
79 | "We're in Bethesda zip code 20892, 71.9m above sea level\n",
80 | "We're in Bethesda zip code 20892, 7.19e+01m above sea level\n"
81 | ]
82 | }
83 | ],
84 | "source": [
85 | "location = 'Bethesda'\n",
86 | "zip_code = 20892\n",
87 | "elevation = 71.9\n",
88 | "\n",
89 | "print(\"We're in\", location, \"zip code\", zip_code, \", \", elevation, \"m above sea level\")\n",
90 | "print(\"We're in \" + location + \" zip code \" + str(zip_code) + \", \" + str(elevation) + \"m above sea level\")\n",
91 | "print(\"We're in {0} zip code {1}, {2}m above sea level\".format(location, zip_code, elevation))\n",
92 | "print(\"We're in {0} zip code {1}, {2:.2e}m above sea level\".format(location, zip_code, elevation))"
93 | ]
94 | },
95 | {
96 | "cell_type": "markdown",
97 | "metadata": {},
98 | "source": [
99 | "##Types\n",
100 | "\n",
101 | "A number of different types are available as part of the standard library. The following links to the documentation provide a summary.\n",
102 | "\n",
103 | "* https://docs.python.org/3.5/library/stdtypes.html\n",
104 | "* https://docs.python.org/3.5/tutorial/datastructures.html\n",
105 | "\n",
106 | "Other types are available from other packages and can be created to support special situations.\n",
107 | "\n",
108 | "A variety of different methods are available depending on the type."
109 | ]
110 | },
111 | {
112 | "cell_type": "code",
113 | "execution_count": 1,
114 | "metadata": {
115 | "collapsed": false
116 | },
117 | "outputs": [
118 | {
119 | "name": "stdout",
120 | "output_type": "stream",
121 | "text": [
122 | "List: [1, 2, 3, 4, 4] 5 True\n",
123 | "Tuple: (1, 2, 3, 4, 4) 5 True\n",
124 | "Set: {1, 2, 3, 4} 4 True\n",
125 | "Dictionary: {'a': 1, 3: 's', 2.5: 't', 'b': 2} 4 True\n"
126 | ]
127 | }
128 | ],
129 | "source": [
130 | "# Sequences\n",
131 | "\n",
132 | "# Lists\n",
133 | "l = [1,2,3,4,4]\n",
134 | "print(\"List:\", l, len(l), 1 in l)\n",
135 | "\n",
136 | "# Tuples\n",
137 | "t = (1,2,3,4,4)\n",
138 | "print(\"Tuple:\", t, len(t), 1 in t)\n",
139 | "\n",
140 | "# Sets\n",
141 | "s = set([1,2,3,4,4])\n",
142 | "print(\"Set:\", s, len(s), 1 in s)\n",
143 | "\n",
144 | "# Dictionaries\n",
145 | "# Dictionaries map hashable values to arbitrary objects\n",
146 | "d = {'a': 1, 'b': 2, 3: 's', 2.5: 't'}\n",
147 | "print(\"Dictionary:\", d, len(d), 'a' in d)"
148 | ]
149 | },
150 | {
151 | "cell_type": "markdown",
152 | "metadata": {},
153 | "source": [
154 | "##Conditionals\n",
155 | "\n",
156 | "https://docs.python.org/3.5/tutorial/controlflow.html"
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "execution_count": 2,
162 | "metadata": {
163 | "collapsed": false
164 | },
165 | "outputs": [
166 | {
167 | "name": "stdout",
168 | "output_type": "stream",
169 | "text": [
170 | "Should be printed 50% of the time\n"
171 | ]
172 | }
173 | ],
174 | "source": [
175 | "import random\n",
176 | "\n",
177 | "if random.random() < 0.5:\n",
178 | " print(\"Should be printed 50% of the time\")\n",
179 | "elif random.random() < 0.5:\n",
180 | " print(\"Should be primted 25% of the time\")\n",
181 | "else:\n",
182 | " print(\"Should be printed 25% of the time\")\n"
183 | ]
184 | },
185 | {
186 | "cell_type": "markdown",
187 | "metadata": {},
188 | "source": [
189 | "##Loops\n",
190 | "\n",
191 | "https://docs.python.org/3.5/tutorial/controlflow.html"
192 | ]
193 | },
194 | {
195 | "cell_type": "code",
196 | "execution_count": 3,
197 | "metadata": {
198 | "collapsed": false
199 | },
200 | "outputs": [
201 | {
202 | "name": "stdout",
203 | "output_type": "stream",
204 | "text": [
205 | "a\n",
206 | "b\n",
207 | "c\n",
208 | "d\n",
209 | "Else\n",
210 | "a\n",
211 | "c\n"
212 | ]
213 | }
214 | ],
215 | "source": [
216 | "for i in ['a', 'b', 'c', 'd']:\n",
217 | " print(i)\n",
218 | "else:\n",
219 | " print('Else')\n",
220 | " \n",
221 | "for i in ['a', 'b', 'c', 'd']:\n",
222 | " if i == 'b':\n",
223 | " continue\n",
224 | " elif i == 'd':\n",
225 | " break\n",
226 | " print(i)\n",
227 | "else:\n",
228 | " print('Else')"
229 | ]
230 | },
231 | {
232 | "cell_type": "markdown",
233 | "metadata": {},
234 | "source": [
235 | "##Functions\n",
236 | "\n",
237 | "https://docs.python.org/3.5/tutorial/controlflow.html"
238 | ]
239 | },
240 | {
241 | "cell_type": "code",
242 | "execution_count": 4,
243 | "metadata": {
244 | "collapsed": false
245 | },
246 | "outputs": [
247 | {
248 | "name": "stdout",
249 | "output_type": "stream",
250 | "text": [
251 | "False True\n"
252 | ]
253 | }
254 | ],
255 | "source": [
256 | "def is_even(n):\n",
257 | " return not n % 2\n",
258 | "\n",
259 | "print(is_even(1), is_even(2))"
260 | ]
261 | },
262 | {
263 | "cell_type": "code",
264 | "execution_count": 5,
265 | "metadata": {
266 | "collapsed": false
267 | },
268 | "outputs": [
269 | {
270 | "name": "stdout",
271 | "output_type": "stream",
272 | "text": [
273 | "[1, 4, 9, 16, 25]\n"
274 | ]
275 | }
276 | ],
277 | "source": [
278 | "def first_n_squared_numbers(n=5):\n",
279 | " return [i**2 for i in range(1,n+1)]\n",
280 | "\n",
281 | "print(first_n_squared_numbers())"
282 | ]
283 | },
284 | {
285 | "cell_type": "code",
286 | "execution_count": 6,
287 | "metadata": {
288 | "collapsed": false
289 | },
290 | "outputs": [
291 | {
292 | "name": "stdout",
293 | "output_type": "stream",
294 | "text": [
295 | "1 1 2 3 5 8\n"
296 | ]
297 | }
298 | ],
299 | "source": [
300 | "def next_fibonacci(status=[]):\n",
301 | " if len(status) < 2:\n",
302 | " status.append(1)\n",
303 | " return 1\n",
304 | " status.append(status[-2] + status[-1])\n",
305 | " return status[-1]\n",
306 | "\n",
307 | "print(next_fibonacci(), next_fibonacci(), next_fibonacci(), next_fibonacci(), next_fibonacci(), next_fibonacci())"
308 | ]
309 | },
310 | {
311 | "cell_type": "code",
312 | "execution_count": 7,
313 | "metadata": {
314 | "collapsed": false
315 | },
316 | "outputs": [
317 | {
318 | "name": "stdout",
319 | "output_type": "stream",
320 | "text": [
321 | "1\n",
322 | "2\n",
323 | "3\n",
324 | "4\n",
325 | "c 3\n",
326 | "a 1\n",
327 | "b 2\n"
328 | ]
329 | }
330 | ],
331 | "source": [
332 | "def accepts_anything(*args, **kwargs):\n",
333 | " for a in args:\n",
334 | " print(a)\n",
335 | " for k in kwargs:\n",
336 | " print(k, kwargs[k])\n",
337 | " \n",
338 | "accepts_anything(1,2,3,4, a=1, b=2, c=3)"
339 | ]
340 | },
341 | {
342 | "cell_type": "code",
343 | "execution_count": 8,
344 | "metadata": {
345 | "collapsed": false
346 | },
347 | "outputs": [
348 | {
349 | "name": "stdout",
350 | "output_type": "stream",
351 | "text": [
352 | "25\n",
353 | "[{'age': 30, 'name': 'Alice'}, {'age': 35, 'name': 'Bob'}, {'age': 35, 'name': 'Charlie'}, {'age': 25, 'name': 'Dennis'}]\n",
354 | "[{'age': 25, 'name': 'Dennis'}, {'age': 30, 'name': 'Alice'}, {'age': 35, 'name': 'Bob'}, {'age': 35, 'name': 'Charlie'}]\n"
355 | ]
356 | }
357 | ],
358 | "source": [
359 | "# For quick and simple functions a lambda expression can be a useful approach. \n",
360 | "# Standard functions are always a valid alternative and often make code clearer.\n",
361 | "f = lambda x: x**2\n",
362 | "print(f(5))\n",
363 | "\n",
364 | "people = [{'name': 'Alice', 'age': 30}, \n",
365 | " {'name': 'Bob', 'age': 35}, \n",
366 | " {'name': 'Charlie', 'age': 35}, \n",
367 | " {'name': 'Dennis', 'age': 25}]\n",
368 | "print(people)\n",
369 | "people.sort(key=lambda x: x['age'])\n",
370 | "print(people)"
371 | ]
372 | },
373 | {
374 | "cell_type": "markdown",
375 | "metadata": {
376 | "collapsed": true
377 | },
378 | "source": [
379 | "##Numpy\n",
380 | "\n",
381 | "http://docs.scipy.org/doc/numpy/reference/"
382 | ]
383 | },
384 | {
385 | "cell_type": "code",
386 | "execution_count": 21,
387 | "metadata": {
388 | "collapsed": false
389 | },
390 | "outputs": [
391 | {
392 | "name": "stdout",
393 | "output_type": "stream",
394 | "text": [
395 | "[[1 2 3]\n",
396 | " [4 5 6]\n",
397 | " [7 8 9]]\n",
398 | "[1 2 3]\n",
399 | "[[5 6]\n",
400 | " [8 9]]\n",
401 | "[[ 3 4 5]\n",
402 | " [ 6 7 8]\n",
403 | " [ 9 10 11]]\n",
404 | "[[ 4 6 8]\n",
405 | " [ 7 9 11]\n",
406 | " [10 12 14]]\n",
407 | "[[14 16 18]\n",
408 | " [27 29 31]\n",
409 | " [40 42 44]]\n"
410 | ]
411 | }
412 | ],
413 | "source": [
414 | "a = np.array([[1,2,3], [4,5,6], [7,8,9]])\n",
415 | "print(a)\n",
416 | "print(a[1:,1:])\n",
417 | "a = a + 2\n",
418 | "print(a)\n",
419 | "a = a + np.array([1,2,3])\n",
420 | "print(a)\n",
421 | "a = a + np.array([[10],[20],[30]])\n",
422 | "print(a)"
423 | ]
424 | },
425 | {
426 | "cell_type": "code",
427 | "execution_count": 59,
428 | "metadata": {
429 | "collapsed": false
430 | },
431 | "outputs": [
432 | {
433 | "name": "stdout",
434 | "output_type": "stream",
435 | "text": [
436 | "29.0 [ 27. 29. 31.] [ 16. 29. 42.]\n"
437 | ]
438 | }
439 | ],
440 | "source": [
441 | "print(a.mean(), a.mean(axis=0), a.mean(axis=1))"
442 | ]
443 | },
444 | {
445 | "cell_type": "code",
446 | "execution_count": 65,
447 | "metadata": {
448 | "collapsed": true
449 | },
450 | "outputs": [],
451 | "source": [
452 | "import matplotlib.pyplot as plt\n",
453 | "\n",
454 | "%matplotlib inline"
455 | ]
456 | },
457 | {
458 | "cell_type": "code",
459 | "execution_count": 68,
460 | "metadata": {
461 | "collapsed": false
462 | },
463 | "outputs": [
464 | {
465 | "data": {
466 | "image/png": "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\n",
467 | "text/plain": [
468 | ""
469 | ]
470 | },
471 | "metadata": {},
472 | "output_type": "display_data"
473 | }
474 | ],
475 | "source": [
476 | "x = np.linspace(0, 3*2*np.pi, 500)\n",
477 | "\n",
478 | "plt.plot(x, np.sin(x))\n",
479 | "plt.show()"
480 | ]
481 | },
482 | {
483 | "cell_type": "markdown",
484 | "metadata": {},
485 | "source": [
486 | "#Exercises"
487 | ]
488 | },
489 | {
490 | "cell_type": "code",
491 | "execution_count": 3,
492 | "metadata": {
493 | "collapsed": false
494 | },
495 | "outputs": [
496 | {
497 | "name": "stdout",
498 | "output_type": "stream",
499 | "text": [
500 | "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\n",
501 | "ThE qUiCk BrOwN fOx JuMpS oVeR tHe LaZy DoG\n",
502 | "god yzal eht revo spmuj xof nworb kciuq ehT\n",
503 | "ehT kciuq nworb xof spmuj revo eht yzal god\n",
504 | "1.2346E+09 1.2346E+9\n"
505 | ]
506 | }
507 | ],
508 | "source": [
509 | "a = \"The quick brown fox jumps over the lazy dog\"\n",
510 | "b = 1234567890.0\n",
511 | "\n",
512 | "## Print the variable `a` in all uppercase\n",
513 | "print(a.upper())\n",
514 | "\n",
515 | "## Print the variable `a` with every other letter in uppercase\n",
516 | "def capEveryOtherLetter(str):\n",
517 | " ans = \"\" \n",
518 | " i = True # capitalize\n",
519 | " for char in str:\n",
520 | " if i == True:\n",
521 | " ans += char.upper() \n",
522 | " else:\n",
523 | " ans += char.lower()\n",
524 | " if char != ' ': # if character is not a space\n",
525 | " i = not i # toggle i between False/True\n",
526 | " return ans\n",
527 | "\n",
528 | "print(capEveryOtherLetter(a))\n",
529 | "\n",
530 | "## Print the variable `a` in reverse, i.e. god yzal ...\n",
531 | "def reverse(str):\n",
532 | " rev = \"\"\n",
533 | " for char in str:\n",
534 | " rev = char + rev\n",
535 | " return rev\n",
536 | " \n",
537 | "print(reverse(a))\n",
538 | "\n",
539 | "## Print the variable `a` with the words reversed, i.e. ehT kciuq ...\n",
540 | "def reverseWords(str):\n",
541 | " words = str.split()\n",
542 | " for i in range(len(words)):\n",
543 | " words[i] = reverse(words[i])\n",
544 | " rev = \" \".join(words)\n",
545 | " return rev\n",
546 | "\n",
547 | "print(reverseWords(a))\n",
548 | "\n",
549 | "## Print the variable `b` in scientific notation with 4 decimal places\n",
550 | "## In python, you have floats and decimals that can be rounded. \n",
551 | "## If you care about the accuracy of rounding, use decimal type. \n",
552 | "## If you use floats, you will have issues with accuracy.\n",
553 | "## Why does ans output E+09 and ans2 E+9? \n",
554 | "from decimal import Decimal\n",
555 | "ans = '%.4E' % Decimal(b)\n",
556 | "ans2 = \"{:.4E}\".format(Decimal(b))\n",
557 | "print(ans, ans2)"
558 | ]
559 | },
560 | {
561 | "cell_type": "markdown",
562 | "metadata": {},
563 | "source": [
564 | "* Print the variable `a` in all uppercase\n",
565 | "* Print the variable `a` with every other letter in uppercase\n",
566 | "* Print the variable `a` in reverse, i.e. god yzal ...\n",
567 | "* Print the variable `a` with the words reversed, i.e. ehT kciuq ...\n",
568 | "* Print the variable `b` in scientific notation with 4 decimal places"
569 | ]
570 | },
571 | {
572 | "cell_type": "code",
573 | "execution_count": null,
574 | "metadata": {
575 | "collapsed": true
576 | },
577 | "outputs": [],
578 | "source": []
579 | },
580 | {
581 | "cell_type": "code",
582 | "execution_count": 1,
583 | "metadata": {
584 | "collapsed": false
585 | },
586 | "outputs": [
587 | {
588 | "name": "stdout",
589 | "output_type": "stream",
590 | "text": [
591 | "{'name': 'Bob', 'age': 35},{'name': 'Alice', 'age': 30},{'name': 'Eve', 'age': 20},{'name': 'Gail', 'age': 30},{'name': 'Dennis', 'age': 25},{'name': 'Charlie', 'age': 35},{'name': 'Fred', 'age': 25}\n",
592 | "[{'name': 'Eve', 'age': 20}, {'name': 'Dennis', 'age': 25}, {'name': 'Fred', 'age': 25}, {'name': 'Alice', 'age': 30}, {'name': 'Gail', 'age': 30}, {'name': 'Bob', 'age': 35}, {'name': 'Charlie', 'age': 35}]\n",
593 | "[{'name': 'Eve', 'age': 20}, {'name': 'Dennis', 'age': 25}, {'name': 'Fred', 'age': 25}, {'name': 'Alice', 'age': 30}, {'name': 'Gail', 'age': 30}, {'name': 'Bob', 'age': 35}, {'name': 'Charlie', 'age': 35}]\n"
594 | ]
595 | }
596 | ],
597 | "source": [
598 | "people = [{'name': 'Bob', 'age': 35}, \n",
599 | " {'name': 'Alice', 'age': 30}, \n",
600 | " {'name': 'Eve', 'age': 20},\n",
601 | " {'name': 'Gail', 'age': 30},\n",
602 | " {'name': 'Dennis', 'age': 25},\n",
603 | " {'name': 'Charlie', 'age': 35}, \n",
604 | " {'name': 'Fred', 'age': 25},]\n",
605 | "\n",
606 | "## Print the items in people as comma-separated values.\n",
607 | "## uses map with str conversion function, as join() expects str, not dict\n",
608 | "peopleCommaSeparated = \",\".join(map(str, people))\n",
609 | "print(peopleCommaSeparated)\n",
610 | "\n",
611 | "## Sort people so that they are ordered by age, and print.\n",
612 | "## sort() only works with lists, whereas sorted() accepts any iterable\n",
613 | "peopleSortedByAge = sorted(people, key = lambda person: person['age'])\n",
614 | "print(peopleSortedByAge)\n",
615 | "\n",
616 | "## Sort people so that they are ordered by age first, and then their names, \n",
617 | "## i.e., Bob and Charlie should be next to each other due to their ages \n",
618 | "## with Bob first due to his name.\n",
619 | "peopleSortedByAgeAndName = sorted(people, key = lambda person: (person['age'], person['name']))\n",
620 | "print(peopleSortedByAgeAndName)"
621 | ]
622 | },
623 | {
624 | "cell_type": "markdown",
625 | "metadata": {},
626 | "source": [
627 | "* Print the items in `people` as comma seperated values\n",
628 | "* Sort `people` so that they are ordered by age, and print\n",
629 | "* Sort `people` so that they are ordered by age first, and then their names, i.e. Bob and Charlie should be next to each other due to their ages with Bob first due to his name."
630 | ]
631 | },
632 | {
633 | "cell_type": "code",
634 | "execution_count": null,
635 | "metadata": {
636 | "collapsed": false
637 | },
638 | "outputs": [],
639 | "source": []
640 | },
641 | {
642 | "cell_type": "markdown",
643 | "metadata": {},
644 | "source": [
645 | "* Write a function that returns the first n prime numbers\n",
646 | "* Given a list of coordinates calculate the distance using the (Euclidean distance)[https://en.wikipedia.org/wiki/Euclidean_distance]\n",
647 | "* Given a list of coordinates arrange them in such a way that the distance traveled is minimized (the itertools module may be useful).\n"
648 | ]
649 | },
650 | {
651 | "cell_type": "code",
652 | "execution_count": null,
653 | "metadata": {
654 | "collapsed": true
655 | },
656 | "outputs": [],
657 | "source": [
658 | "coords = [(0,0), (10,5), (10,10), (5,10), (3,3), (3,7), (12,3), (10,11)]\n",
659 | "\n"
660 | ]
661 | },
662 | {
663 | "cell_type": "markdown",
664 | "metadata": {},
665 | "source": [
666 | "* Print the standard deviation of each row in a numpy array\n",
667 | "* Print only the values greater than 90 in a numpy array\n",
668 | "* From a numpy array display the values in each row in a seperate plot (the subplots method may be useful)"
669 | ]
670 | },
671 | {
672 | "cell_type": "code",
673 | "execution_count": 27,
674 | "metadata": {
675 | "collapsed": false
676 | },
677 | "outputs": [
678 | {
679 | "name": "stdout",
680 | "output_type": "stream",
681 | "text": [
682 | "[[44 47 64 67 67 9 83 21 36 87 70 88 88 12 58 65 39 87 46 88]\n",
683 | " [81 37 25 77 72 9 20 80 69 79 47 64 82 99 88 49 29 19 19 14]\n",
684 | " [39 32 65 9 57 32 31 74 23 35 75 55 28 34 0 0 36 53 5 38]\n",
685 | " [17 79 4 42 58 31 1 65 41 57 35 11 46 82 91 0 14 99 53 12]\n",
686 | " [42 84 75 68 6 68 47 3 76 52 78 15 20 99 58 23 79 13 85 48]\n",
687 | " [49 69 41 35 64 95 69 94 0 50 36 34 48 93 3 98 42 77 21 73]\n",
688 | " [ 0 10 43 58 23 59 2 98 62 35 94 67 82 46 99 20 81 50 27 14]\n",
689 | " [41 58 65 36 10 86 43 11 2 51 80 32 54 0 38 19 46 42 56 60]\n",
690 | " [77 30 24 2 3 94 98 13 40 72 19 95 72 26 66 52 67 61 14 96]\n",
691 | " [ 4 67 11 86 77 75 56 16 24 29 21 25 80 60 61 83 33 32 70 85]] \n",
692 | "\n",
693 | "[ 25.08804496 28.47011591 21.7795202 30.07972739 28.97667165\n",
694 | " 28.50697283 31.07008207 23.401923 32.10681392 27.20087315] \n",
695 | "\n",
696 | "[99 91 99 99 95 94 93 98 98 94 99 94 98 95 96] \n",
697 | "\n"
698 | ]
699 | }
700 | ],
701 | "source": [
702 | "import numpy as np\n",
703 | "np.random.seed(0)\n",
704 | "a = np.random.randint(0, 100, size=(10,20))\n",
705 | "print(a, \"\\n\")\n",
706 | "\n",
707 | "## Print the standard deviation (σ) of each row in a numpy array\n",
708 | "## in a 2D array, columns are axis = 0, and rows are axis = 1\n",
709 | "row_std = np.std(a, axis=1)\n",
710 | "print(row_std, \"\\n\")\n",
711 | "\n",
712 | "## Print only the values greater than 90 in a numpy array\n",
713 | "truncated = a[a > 90]\n",
714 | "print(truncated, \"\\n\")\n",
715 | "\n",
716 | "## From a numpy array, display the values in each row in a separate plot \n",
717 | "## (the subplots method) may be useful\n",
718 | "import matplotlib.pyplot as plt\n",
719 | "\n",
720 | "plt.plot(a[0])\n",
721 | "plt.subplot(211)\n",
722 | "plt.show()"
723 | ]
724 | },
725 | {
726 | "cell_type": "code",
727 | "execution_count": null,
728 | "metadata": {
729 | "collapsed": true
730 | },
731 | "outputs": [],
732 | "source": []
733 | }
734 | ],
735 | "metadata": {
736 | "kernelspec": {
737 | "display_name": "Python 3",
738 | "language": "python",
739 | "name": "python3"
740 | },
741 | "language_info": {
742 | "codemirror_mode": {
743 | "name": "ipython",
744 | "version": 3
745 | },
746 | "file_extension": ".py",
747 | "mimetype": "text/x-python",
748 | "name": "python",
749 | "nbconvert_exporter": "python",
750 | "pygments_lexer": "ipython3",
751 | "version": "3.5.1"
752 | }
753 | },
754 | "nbformat": 4,
755 | "nbformat_minor": 0
756 | }
757 |
--------------------------------------------------------------------------------
/Wk01/.ipynb_checkpoints/Wk01-Overview-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Week 1 - Getting Started"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 3,
13 | "metadata": {
14 | "collapsed": false
15 | },
16 | "outputs": [
17 | {
18 | "name": "stdout",
19 | "output_type": "stream",
20 | "text": [
21 | "Numpy: 1.10.4\n"
22 | ]
23 | }
24 | ],
25 | "source": [
26 | "import numpy as np\n",
27 | "\n",
28 | "print(\"Numpy:\", np.__version__)"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "#Python Summary\n",
36 | "\n",
37 | "##Further information\n",
38 | "\n",
39 | "More information is usually available with the `help` function. Using ? brings up the same information in ipython. \n",
40 | "\n",
41 | "Using the `dir` function lists all the options available from a variable."
42 | ]
43 | },
44 | {
45 | "cell_type": "markdown",
46 | "metadata": {},
47 | "source": [
48 | "help(np)\n",
49 | "\n",
50 | "np?\n",
51 | "\n",
52 | "dir(np)"
53 | ]
54 | },
55 | {
56 | "cell_type": "markdown",
57 | "metadata": {},
58 | "source": [
59 | "##Variables\n",
60 | "\n",
61 | "A variable is simply a name for something. One of the simplest tasks is printing the value of a variable.\n",
62 | "\n",
63 | "Printing can be customized using the format method on strings."
64 | ]
65 | },
66 | {
67 | "cell_type": "code",
68 | "execution_count": 13,
69 | "metadata": {
70 | "collapsed": false
71 | },
72 | "outputs": [
73 | {
74 | "name": "stdout",
75 | "output_type": "stream",
76 | "text": [
77 | "We're in Bethesda zip code 20892 , 71.9 m above sea level\n",
78 | "We're in Bethesda zip code 20892, 71.9m above sea level\n",
79 | "We're in Bethesda zip code 20892, 71.9m above sea level\n",
80 | "We're in Bethesda zip code 20892, 7.19e+01m above sea level\n"
81 | ]
82 | }
83 | ],
84 | "source": [
85 | "location = 'Bethesda'\n",
86 | "zip_code = 20892\n",
87 | "elevation = 71.9\n",
88 | "\n",
89 | "print(\"We're in\", location, \"zip code\", zip_code, \", \", elevation, \"m above sea level\")\n",
90 | "print(\"We're in \" + location + \" zip code \" + str(zip_code) + \", \" + str(elevation) + \"m above sea level\")\n",
91 | "print(\"We're in {0} zip code {1}, {2}m above sea level\".format(location, zip_code, elevation))\n",
92 | "print(\"We're in {0} zip code {1}, {2:.2e}m above sea level\".format(location, zip_code, elevation))"
93 | ]
94 | },
95 | {
96 | "cell_type": "markdown",
97 | "metadata": {},
98 | "source": [
99 | "##Types\n",
100 | "\n",
101 | "A number of different types are available as part of the standard library. The following links to the documentation provide a summary.\n",
102 | "\n",
103 | "* https://docs.python.org/3.5/library/stdtypes.html\n",
104 | "* https://docs.python.org/3.5/tutorial/datastructures.html\n",
105 | "\n",
106 | "Other types are available from other packages and can be created to support special situations.\n",
107 | "\n",
108 | "A variety of different methods are available depending on the type."
109 | ]
110 | },
111 | {
112 | "cell_type": "code",
113 | "execution_count": 1,
114 | "metadata": {
115 | "collapsed": false
116 | },
117 | "outputs": [
118 | {
119 | "name": "stdout",
120 | "output_type": "stream",
121 | "text": [
122 | "List: [1, 2, 3, 4, 4] 5 True\n",
123 | "Tuple: (1, 2, 3, 4, 4) 5 True\n",
124 | "Set: {1, 2, 3, 4} 4 True\n",
125 | "Dictionary: {'a': 1, 3: 's', 2.5: 't', 'b': 2} 4 True\n"
126 | ]
127 | }
128 | ],
129 | "source": [
130 | "# Sequences\n",
131 | "\n",
132 | "# Lists\n",
133 | "l = [1,2,3,4,4]\n",
134 | "print(\"List:\", l, len(l), 1 in l)\n",
135 | "\n",
136 | "# Tuples\n",
137 | "t = (1,2,3,4,4)\n",
138 | "print(\"Tuple:\", t, len(t), 1 in t)\n",
139 | "\n",
140 | "# Sets\n",
141 | "s = set([1,2,3,4,4])\n",
142 | "print(\"Set:\", s, len(s), 1 in s)\n",
143 | "\n",
144 | "# Dictionaries\n",
145 | "# Dictionaries map hashable values to arbitrary objects\n",
146 | "d = {'a': 1, 'b': 2, 3: 's', 2.5: 't'}\n",
147 | "print(\"Dictionary:\", d, len(d), 'a' in d)"
148 | ]
149 | },
150 | {
151 | "cell_type": "markdown",
152 | "metadata": {},
153 | "source": [
154 | "##Conditionals\n",
155 | "\n",
156 | "https://docs.python.org/3.5/tutorial/controlflow.html"
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "execution_count": 2,
162 | "metadata": {
163 | "collapsed": false
164 | },
165 | "outputs": [
166 | {
167 | "name": "stdout",
168 | "output_type": "stream",
169 | "text": [
170 | "Should be printed 50% of the time\n"
171 | ]
172 | }
173 | ],
174 | "source": [
175 | "import random\n",
176 | "\n",
177 | "if random.random() < 0.5:\n",
178 | " print(\"Should be printed 50% of the time\")\n",
179 | "elif random.random() < 0.5:\n",
180 | " print(\"Should be primted 25% of the time\")\n",
181 | "else:\n",
182 | " print(\"Should be printed 25% of the time\")\n"
183 | ]
184 | },
185 | {
186 | "cell_type": "markdown",
187 | "metadata": {},
188 | "source": [
189 | "##Loops\n",
190 | "\n",
191 | "https://docs.python.org/3.5/tutorial/controlflow.html"
192 | ]
193 | },
194 | {
195 | "cell_type": "code",
196 | "execution_count": 3,
197 | "metadata": {
198 | "collapsed": false
199 | },
200 | "outputs": [
201 | {
202 | "name": "stdout",
203 | "output_type": "stream",
204 | "text": [
205 | "a\n",
206 | "b\n",
207 | "c\n",
208 | "d\n",
209 | "Else\n",
210 | "a\n",
211 | "c\n"
212 | ]
213 | }
214 | ],
215 | "source": [
216 | "for i in ['a', 'b', 'c', 'd']:\n",
217 | " print(i)\n",
218 | "else:\n",
219 | " print('Else')\n",
220 | " \n",
221 | "for i in ['a', 'b', 'c', 'd']:\n",
222 | " if i == 'b':\n",
223 | " continue\n",
224 | " elif i == 'd':\n",
225 | " break\n",
226 | " print(i)\n",
227 | "else:\n",
228 | " print('Else')"
229 | ]
230 | },
231 | {
232 | "cell_type": "markdown",
233 | "metadata": {},
234 | "source": [
235 | "##Functions\n",
236 | "\n",
237 | "https://docs.python.org/3.5/tutorial/controlflow.html"
238 | ]
239 | },
240 | {
241 | "cell_type": "code",
242 | "execution_count": 4,
243 | "metadata": {
244 | "collapsed": false
245 | },
246 | "outputs": [
247 | {
248 | "name": "stdout",
249 | "output_type": "stream",
250 | "text": [
251 | "False True\n"
252 | ]
253 | }
254 | ],
255 | "source": [
256 | "def is_even(n):\n",
257 | " return not n % 2\n",
258 | "\n",
259 | "print(is_even(1), is_even(2))"
260 | ]
261 | },
262 | {
263 | "cell_type": "code",
264 | "execution_count": 5,
265 | "metadata": {
266 | "collapsed": false
267 | },
268 | "outputs": [
269 | {
270 | "name": "stdout",
271 | "output_type": "stream",
272 | "text": [
273 | "[1, 4, 9, 16, 25]\n"
274 | ]
275 | }
276 | ],
277 | "source": [
278 | "def first_n_squared_numbers(n=5):\n",
279 | " return [i**2 for i in range(1,n+1)]\n",
280 | "\n",
281 | "print(first_n_squared_numbers())"
282 | ]
283 | },
284 | {
285 | "cell_type": "code",
286 | "execution_count": 6,
287 | "metadata": {
288 | "collapsed": false
289 | },
290 | "outputs": [
291 | {
292 | "name": "stdout",
293 | "output_type": "stream",
294 | "text": [
295 | "1 1 2 3 5 8\n"
296 | ]
297 | }
298 | ],
299 | "source": [
300 | "def next_fibonacci(status=[]):\n",
301 | " if len(status) < 2:\n",
302 | " status.append(1)\n",
303 | " return 1\n",
304 | " status.append(status[-2] + status[-1])\n",
305 | " return status[-1]\n",
306 | "\n",
307 | "print(next_fibonacci(), next_fibonacci(), next_fibonacci(), next_fibonacci(), next_fibonacci(), next_fibonacci())"
308 | ]
309 | },
310 | {
311 | "cell_type": "code",
312 | "execution_count": 7,
313 | "metadata": {
314 | "collapsed": false
315 | },
316 | "outputs": [
317 | {
318 | "name": "stdout",
319 | "output_type": "stream",
320 | "text": [
321 | "1\n",
322 | "2\n",
323 | "3\n",
324 | "4\n",
325 | "c 3\n",
326 | "a 1\n",
327 | "b 2\n"
328 | ]
329 | }
330 | ],
331 | "source": [
332 | "def accepts_anything(*args, **kwargs):\n",
333 | " for a in args:\n",
334 | " print(a)\n",
335 | " for k in kwargs:\n",
336 | " print(k, kwargs[k])\n",
337 | " \n",
338 | "accepts_anything(1,2,3,4, a=1, b=2, c=3)"
339 | ]
340 | },
341 | {
342 | "cell_type": "code",
343 | "execution_count": 8,
344 | "metadata": {
345 | "collapsed": false
346 | },
347 | "outputs": [
348 | {
349 | "name": "stdout",
350 | "output_type": "stream",
351 | "text": [
352 | "25\n",
353 | "[{'age': 30, 'name': 'Alice'}, {'age': 35, 'name': 'Bob'}, {'age': 35, 'name': 'Charlie'}, {'age': 25, 'name': 'Dennis'}]\n",
354 | "[{'age': 25, 'name': 'Dennis'}, {'age': 30, 'name': 'Alice'}, {'age': 35, 'name': 'Bob'}, {'age': 35, 'name': 'Charlie'}]\n"
355 | ]
356 | }
357 | ],
358 | "source": [
359 | "# For quick and simple functions a lambda expression can be a useful approach. \n",
360 | "# Standard functions are always a valid alternative and often make code clearer.\n",
361 | "f = lambda x: x**2\n",
362 | "print(f(5))\n",
363 | "\n",
364 | "people = [{'name': 'Alice', 'age': 30}, \n",
365 | " {'name': 'Bob', 'age': 35}, \n",
366 | " {'name': 'Charlie', 'age': 35}, \n",
367 | " {'name': 'Dennis', 'age': 25}]\n",
368 | "print(people)\n",
369 | "people.sort(key=lambda x: x['age'])\n",
370 | "print(people)"
371 | ]
372 | },
373 | {
374 | "cell_type": "markdown",
375 | "metadata": {
376 | "collapsed": true
377 | },
378 | "source": [
379 | "##Numpy\n",
380 | "\n",
381 | "http://docs.scipy.org/doc/numpy/reference/"
382 | ]
383 | },
384 | {
385 | "cell_type": "code",
386 | "execution_count": 21,
387 | "metadata": {
388 | "collapsed": false
389 | },
390 | "outputs": [
391 | {
392 | "name": "stdout",
393 | "output_type": "stream",
394 | "text": [
395 | "[[1 2 3]\n",
396 | " [4 5 6]\n",
397 | " [7 8 9]]\n",
398 | "[1 2 3]\n",
399 | "[[5 6]\n",
400 | " [8 9]]\n",
401 | "[[ 3 4 5]\n",
402 | " [ 6 7 8]\n",
403 | " [ 9 10 11]]\n",
404 | "[[ 4 6 8]\n",
405 | " [ 7 9 11]\n",
406 | " [10 12 14]]\n",
407 | "[[14 16 18]\n",
408 | " [27 29 31]\n",
409 | " [40 42 44]]\n"
410 | ]
411 | }
412 | ],
413 | "source": [
414 | "a = np.array([[1,2,3], [4,5,6], [7,8,9]])\n",
415 | "print(a)\n",
416 | "print(a[1:,1:])\n",
417 | "a = a + 2\n",
418 | "print(a)\n",
419 | "a = a + np.array([1,2,3])\n",
420 | "print(a)\n",
421 | "a = a + np.array([[10],[20],[30]])\n",
422 | "print(a)"
423 | ]
424 | },
425 | {
426 | "cell_type": "code",
427 | "execution_count": 59,
428 | "metadata": {
429 | "collapsed": false
430 | },
431 | "outputs": [
432 | {
433 | "name": "stdout",
434 | "output_type": "stream",
435 | "text": [
436 | "29.0 [ 27. 29. 31.] [ 16. 29. 42.]\n"
437 | ]
438 | }
439 | ],
440 | "source": [
441 | "print(a.mean(), a.mean(axis=0), a.mean(axis=1))"
442 | ]
443 | },
444 | {
445 | "cell_type": "code",
446 | "execution_count": 65,
447 | "metadata": {
448 | "collapsed": true
449 | },
450 | "outputs": [],
451 | "source": [
452 | "import matplotlib.pyplot as plt\n",
453 | "\n",
454 | "%matplotlib inline"
455 | ]
456 | },
457 | {
458 | "cell_type": "code",
459 | "execution_count": 68,
460 | "metadata": {
461 | "collapsed": false
462 | },
463 | "outputs": [
464 | {
465 | "data": {
466 | "image/png": "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\n",
467 | "text/plain": [
468 | ""
469 | ]
470 | },
471 | "metadata": {},
472 | "output_type": "display_data"
473 | }
474 | ],
475 | "source": [
476 | "x = np.linspace(0, 3*2*np.pi, 500)\n",
477 | "\n",
478 | "plt.plot(x, np.sin(x))\n",
479 | "plt.show()"
480 | ]
481 | },
482 | {
483 | "cell_type": "markdown",
484 | "metadata": {},
485 | "source": [
486 | "#Exercises"
487 | ]
488 | },
489 | {
490 | "cell_type": "code",
491 | "execution_count": 3,
492 | "metadata": {
493 | "collapsed": false
494 | },
495 | "outputs": [
496 | {
497 | "name": "stdout",
498 | "output_type": "stream",
499 | "text": [
500 | "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\n",
501 | "ThE qUiCk BrOwN fOx JuMpS oVeR tHe LaZy DoG\n",
502 | "god yzal eht revo spmuj xof nworb kciuq ehT\n",
503 | "ehT kciuq nworb xof spmuj revo eht yzal god\n",
504 | "1.2346E+09 1.2346E+9\n"
505 | ]
506 | }
507 | ],
508 | "source": [
509 | "a = \"The quick brown fox jumps over the lazy dog\"\n",
510 | "b = 1234567890.0\n",
511 | "\n",
512 | "## Print the variable `a` in all uppercase\n",
513 | "print(a.upper())\n",
514 | "\n",
515 | "## Print the variable `a` with every other letter in uppercase\n",
516 | "def capEveryOtherLetter(str):\n",
517 | " ans = \"\" \n",
518 | " i = True # capitalize\n",
519 | " for char in str:\n",
520 | " if i == True:\n",
521 | " ans += char.upper() \n",
522 | " else:\n",
523 | " ans += char.lower()\n",
524 | " if char != ' ': # if character is not a space\n",
525 | " i = not i # toggle i between False/True\n",
526 | " return ans\n",
527 | "\n",
528 | "print(capEveryOtherLetter(a))\n",
529 | "\n",
530 | "## Print the variable `a` in reverse, i.e. god yzal ...\n",
531 | "def reverse(str):\n",
532 | " rev = \"\"\n",
533 | " for char in str:\n",
534 | " rev = char + rev\n",
535 | " return rev\n",
536 | " \n",
537 | "print(reverse(a))\n",
538 | "\n",
539 | "## Print the variable `a` with the words reversed, i.e. ehT kciuq ...\n",
540 | "def reverseWords(str):\n",
541 | " words = str.split()\n",
542 | " for i in range(len(words)):\n",
543 | " words[i] = reverse(words[i])\n",
544 | " rev = \" \".join(words)\n",
545 | " return rev\n",
546 | "\n",
547 | "print(reverseWords(a))\n",
548 | "\n",
549 | "## Print the variable `b` in scientific notation with 4 decimal places\n",
550 | "## In python, you have floats and decimals that can be rounded. \n",
551 | "## If you care about the accuracy of rounding, use decimal type. \n",
552 | "## If you use floats, you will have issues with accuracy.\n",
553 | "## Why does ans output E+09 and ans2 E+9? \n",
554 | "from decimal import Decimal\n",
555 | "ans = '%.4E' % Decimal(b)\n",
556 | "ans2 = \"{:.4E}\".format(Decimal(b))\n",
557 | "print(ans, ans2)"
558 | ]
559 | },
560 | {
561 | "cell_type": "markdown",
562 | "metadata": {},
563 | "source": [
564 | "* Print the variable `a` in all uppercase\n",
565 | "* Print the variable `a` with every other letter in uppercase\n",
566 | "* Print the variable `a` in reverse, i.e. god yzal ...\n",
567 | "* Print the variable `a` with the words reversed, i.e. ehT kciuq ...\n",
568 | "* Print the variable `b` in scientific notation with 4 decimal places"
569 | ]
570 | },
571 | {
572 | "cell_type": "code",
573 | "execution_count": null,
574 | "metadata": {
575 | "collapsed": true
576 | },
577 | "outputs": [],
578 | "source": []
579 | },
580 | {
581 | "cell_type": "code",
582 | "execution_count": 1,
583 | "metadata": {
584 | "collapsed": false
585 | },
586 | "outputs": [
587 | {
588 | "name": "stdout",
589 | "output_type": "stream",
590 | "text": [
591 | "{'name': 'Bob', 'age': 35},{'name': 'Alice', 'age': 30},{'name': 'Eve', 'age': 20},{'name': 'Gail', 'age': 30},{'name': 'Dennis', 'age': 25},{'name': 'Charlie', 'age': 35},{'name': 'Fred', 'age': 25}\n",
592 | "[{'name': 'Eve', 'age': 20}, {'name': 'Dennis', 'age': 25}, {'name': 'Fred', 'age': 25}, {'name': 'Alice', 'age': 30}, {'name': 'Gail', 'age': 30}, {'name': 'Bob', 'age': 35}, {'name': 'Charlie', 'age': 35}]\n",
593 | "[{'name': 'Eve', 'age': 20}, {'name': 'Dennis', 'age': 25}, {'name': 'Fred', 'age': 25}, {'name': 'Alice', 'age': 30}, {'name': 'Gail', 'age': 30}, {'name': 'Bob', 'age': 35}, {'name': 'Charlie', 'age': 35}]\n"
594 | ]
595 | }
596 | ],
597 | "source": [
598 | "people = [{'name': 'Bob', 'age': 35}, \n",
599 | " {'name': 'Alice', 'age': 30}, \n",
600 | " {'name': 'Eve', 'age': 20},\n",
601 | " {'name': 'Gail', 'age': 30},\n",
602 | " {'name': 'Dennis', 'age': 25},\n",
603 | " {'name': 'Charlie', 'age': 35}, \n",
604 | " {'name': 'Fred', 'age': 25},]\n",
605 | "\n",
606 | "## Print the items in people as comma-separated values.\n",
607 | "## uses map with str conversion function, as join() expects str, not dict\n",
608 | "peopleCommaSeparated = \",\".join(map(str, people))\n",
609 | "print(peopleCommaSeparated)\n",
610 | "\n",
611 | "## Sort people so that they are ordered by age, and print.\n",
612 | "## sort() only works with lists, whereas sorted() accepts any iterable\n",
613 | "peopleSortedByAge = sorted(people, key = lambda person: person['age'])\n",
614 | "print(peopleSortedByAge)\n",
615 | "\n",
616 | "## Sort people so that they are ordered by age first, and then their names, \n",
617 | "## i.e., Bob and Charlie should be next to each other due to their ages \n",
618 | "## with Bob first due to his name.\n",
619 | "peopleSortedByAgeAndName = sorted(people, key = lambda person: (person['age'], person['name']))\n",
620 | "print(peopleSortedByAgeAndName)"
621 | ]
622 | },
623 | {
624 | "cell_type": "markdown",
625 | "metadata": {},
626 | "source": [
627 | "* Print the items in `people` as comma seperated values\n",
628 | "* Sort `people` so that they are ordered by age, and print\n",
629 | "* Sort `people` so that they are ordered by age first, and then their names, i.e. Bob and Charlie should be next to each other due to their ages with Bob first due to his name."
630 | ]
631 | },
632 | {
633 | "cell_type": "code",
634 | "execution_count": null,
635 | "metadata": {
636 | "collapsed": false
637 | },
638 | "outputs": [],
639 | "source": []
640 | },
641 | {
642 | "cell_type": "markdown",
643 | "metadata": {},
644 | "source": [
645 | "* Write a function that returns the first n prime numbers\n",
646 | "* Given a list of coordinates calculate the distance using the (Euclidean distance)[https://en.wikipedia.org/wiki/Euclidean_distance]\n",
647 | "* Given a list of coordinates arrange them in such a way that the distance traveled is minimized (the itertools module may be useful).\n"
648 | ]
649 | },
650 | {
651 | "cell_type": "code",
652 | "execution_count": null,
653 | "metadata": {
654 | "collapsed": true
655 | },
656 | "outputs": [],
657 | "source": [
658 | "coords = [(0,0), (10,5), (10,10), (5,10), (3,3), (3,7), (12,3), (10,11)]\n",
659 | "\n"
660 | ]
661 | },
662 | {
663 | "cell_type": "markdown",
664 | "metadata": {},
665 | "source": [
666 | "* Print the standard deviation of each row in a numpy array\n",
667 | "* Print only the values greater than 90 in a numpy array\n",
668 | "* From a numpy array display the values in each row in a seperate plot (the subplots method may be useful)"
669 | ]
670 | },
671 | {
672 | "cell_type": "code",
673 | "execution_count": 27,
674 | "metadata": {
675 | "collapsed": false
676 | },
677 | "outputs": [
678 | {
679 | "name": "stdout",
680 | "output_type": "stream",
681 | "text": [
682 | "[[44 47 64 67 67 9 83 21 36 87 70 88 88 12 58 65 39 87 46 88]\n",
683 | " [81 37 25 77 72 9 20 80 69 79 47 64 82 99 88 49 29 19 19 14]\n",
684 | " [39 32 65 9 57 32 31 74 23 35 75 55 28 34 0 0 36 53 5 38]\n",
685 | " [17 79 4 42 58 31 1 65 41 57 35 11 46 82 91 0 14 99 53 12]\n",
686 | " [42 84 75 68 6 68 47 3 76 52 78 15 20 99 58 23 79 13 85 48]\n",
687 | " [49 69 41 35 64 95 69 94 0 50 36 34 48 93 3 98 42 77 21 73]\n",
688 | " [ 0 10 43 58 23 59 2 98 62 35 94 67 82 46 99 20 81 50 27 14]\n",
689 | " [41 58 65 36 10 86 43 11 2 51 80 32 54 0 38 19 46 42 56 60]\n",
690 | " [77 30 24 2 3 94 98 13 40 72 19 95 72 26 66 52 67 61 14 96]\n",
691 | " [ 4 67 11 86 77 75 56 16 24 29 21 25 80 60 61 83 33 32 70 85]] \n",
692 | "\n",
693 | "[ 25.08804496 28.47011591 21.7795202 30.07972739 28.97667165\n",
694 | " 28.50697283 31.07008207 23.401923 32.10681392 27.20087315] \n",
695 | "\n",
696 | "[99 91 99 99 95 94 93 98 98 94 99 94 98 95 96] \n",
697 | "\n"
698 | ]
699 | }
700 | ],
701 | "source": [
702 | "import numpy as np\n",
703 | "np.random.seed(0)\n",
704 | "a = np.random.randint(0, 100, size=(10,20))\n",
705 | "print(a, \"\\n\")\n",
706 | "\n",
707 | "## Print the standard deviation (σ) of each row in a numpy array\n",
708 | "## in a 2D array, columns are axis = 0, and rows are axis = 1\n",
709 | "row_std = np.std(a, axis=1)\n",
710 | "print(row_std, \"\\n\")\n",
711 | "\n",
712 | "## Print only the values greater than 90 in a numpy array\n",
713 | "truncated = a[a > 90]\n",
714 | "print(truncated, \"\\n\")\n",
715 | "\n",
716 | "## From a numpy array, display the values in each row in a separate plot \n",
717 | "## (the subplots method) may be useful\n",
718 | "import matplotlib.pyplot as plt\n",
719 | "\n",
720 | "plt.plot(a[0])\n",
721 | "plt.subplot(211)\n",
722 | "plt.show()"
723 | ]
724 | },
725 | {
726 | "cell_type": "code",
727 | "execution_count": null,
728 | "metadata": {
729 | "collapsed": true
730 | },
731 | "outputs": [],
732 | "source": []
733 | }
734 | ],
735 | "metadata": {
736 | "kernelspec": {
737 | "display_name": "Python 3",
738 | "language": "python",
739 | "name": "python3"
740 | },
741 | "language_info": {
742 | "codemirror_mode": {
743 | "name": "ipython",
744 | "version": 3
745 | },
746 | "file_extension": ".py",
747 | "mimetype": "text/x-python",
748 | "name": "python",
749 | "nbconvert_exporter": "python",
750 | "pygments_lexer": "ipython3",
751 | "version": "3.5.1"
752 | }
753 | },
754 | "nbformat": 4,
755 | "nbformat_minor": 0
756 | }
757 |
--------------------------------------------------------------------------------