├── test_framework_exercise
├── __init__.py
└── phoenix_test
│ ├── __init__.py
│ ├── manipulators.py
│ ├── test.py
│ └── matchers.py
├── ch4_manipulating_functions
├── problem_0.md
├── problem_2.py
├── problem_1.py
├── problem_4.py
├── problem_3.py
├── 4.2_Context_Managers.ipynb
└── 4.5_List_Comprehensions_and_Generator_Expressions.ipynb
├── data_frame_exercise
├── phoenixcel
│ ├── __init__.py
│ └── dataframe.py
├── birds.csv
├── 3_DataFrame_Usage_Example.ipynb
├── feature_requests.csv
├── 5_Extending_Dataframe.ipynb
└── 1_Series_and_GroupBy.ipynb
├── ch6_how_functions_and_objects_work_together
├── problem_0.md
├── problem_1.md
├── problem_3.py
├── problem_2.py
├── 6.1_Functions_as_First_Class_Objects.ipynb
└── 6.3_Functional_Constructs.ipynb
├── ch5_manipulating_objects
├── problem_1.py
├── problem_0.md
├── problem_2_3_4_5.py
├── 5.4_Static_Methods.ipynb
└── 5.8_Multiple_Inheritance.ipynb
├── uchicago-cnetids.txt
├── ch2_syntactic_basics
├── problem_2.md
├── problem_1.md
├── problem_6.py
├── problem_0.md
├── problem_5.py
├── problem_4.py
├── problem_3.py
├── problem_7.py
├── problem_8.py
├── 2.8_Modules.ipynb
├── 2.3_Lists.ipynb
├── 2.7_Functions.ipynb
├── 2.4_Tuples.ipynb
├── 2.6_Control_Flow.ipynb
└── 2.2_Strings.ipynb
├── images
├── class.png
├── files.png
├── pip.png
├── scope.png
├── module.png
├── mutable.png
├── Operators.png
├── car_drift.png
├── division.png
├── git_states.png
├── literals.png
├── object-def.png
├── open-file.png
├── questions.png
├── thinking.jpg
├── thinkining.jpg
├── broadcasting.png
├── java_stream.png
├── phoenix_test.jpg
├── projections.png
├── runtime_pvm.png
├── shared_ref1.png
├── shared_ref2.png
├── test_output.png
├── array_vs_list.png
├── example_chart.png
├── growth_scatter.png
├── leave_the_nest.png
├── return_to_nest.png
├── run_all_output.png
├── setup_teardown.png
├── test_methods1.png
├── argument_matching.png
├── assignment_forms.png
├── iterator_protocol.png
├── names_references.png
├── reverse_operators.png
├── tuple_operations.png
├── built-in-functions.png
├── comparing_paradigms.png
├── dictionary_literals.png
├── dictionary_methods.png
├── inheritance_as_tree.jpg
├── multiple_inheritance.jpg
├── growth_major_language.png
├── inheritance_as_circles.jpg
├── compiler_mountain_diagram.png
├── scanning_lexing_parsing.png
└── projections_major_languages.png
├── ch3_collections_and_functions
├── problem_1.py
├── problem_2.py
├── problem_3.py
├── problem_6.py
├── problem_4.py
├── problem_5.py
├── that_test_function_from_last_chapter.py
├── townsville.csv
├── problem_0.md
├── 3.2_Sets.ipynb
└── 3.1_Dictionaries.ipynb
├── .gitignore
├── Pipfile
├── uchicago-emails.txt
├── clean_notebooks.sh
├── ch7_intro_to_data_engineering
├── birds.csv
├── 7.0_Installing_Packages.ipynb
└── 7.2_The_Pandas_Series.ipynb
├── README.md
├── ch9_intro_to_debugging
├── bird_watching_session.py
└── Homework_Problems.ipynb
├── course_utils.py
├── move_me
├── Assertion_Examples_from_Minitest.ipynb
└── Interpreter_Explained.ipynb
├── ch1_learning_python
└── 1.2_Running_Python_Programs.ipynb
├── database_efficiency_exercise
├── 2_Exploring_Caching_and_Profiling.ipynb
└── 1_Value_Counts_(Time_Efficiency).ipynb
└── ch8_build_your_own_API
└── Homework_Problems.ipynb
/test_framework_exercise/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ch4_manipulating_functions/problem_0.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data_frame_exercise/phoenixcel/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_framework_exercise/phoenix_test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ch6_how_functions_and_objects_work_together/problem_0.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ch4_manipulating_functions/problem_2.py:
--------------------------------------------------------------------------------
1 | def unique():
2 | pass
--------------------------------------------------------------------------------
/ch6_how_functions_and_objects_work_together/problem_1.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ch4_manipulating_functions/problem_1.py:
--------------------------------------------------------------------------------
1 | def vectorize(func):
2 | pass
--------------------------------------------------------------------------------
/ch4_manipulating_functions/problem_4.py:
--------------------------------------------------------------------------------
1 | def accepts():
2 | pass
3 |
--------------------------------------------------------------------------------
/ch5_manipulating_objects/problem_1.py:
--------------------------------------------------------------------------------
1 | class SwiftArray:
2 | pass
3 |
--------------------------------------------------------------------------------
/uchicago-cnetids.txt:
--------------------------------------------------------------------------------
1 | bob
2 | philb
3 | sally
4 | rebeccaw
5 | joan
6 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/problem_2.md:
--------------------------------------------------------------------------------
1 | **1. You shouldn't...**
2 |
3 | **2. I think...**
--------------------------------------------------------------------------------
/ch6_how_functions_and_objects_work_together/problem_3.py:
--------------------------------------------------------------------------------
1 | class Stream:
2 | pass
--------------------------------------------------------------------------------
/images/class.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/class.png
--------------------------------------------------------------------------------
/images/files.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/files.png
--------------------------------------------------------------------------------
/images/pip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/pip.png
--------------------------------------------------------------------------------
/images/scope.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/scope.png
--------------------------------------------------------------------------------
/images/module.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/module.png
--------------------------------------------------------------------------------
/images/mutable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/mutable.png
--------------------------------------------------------------------------------
/images/Operators.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/Operators.png
--------------------------------------------------------------------------------
/images/car_drift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/car_drift.png
--------------------------------------------------------------------------------
/images/division.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/division.png
--------------------------------------------------------------------------------
/images/git_states.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/git_states.png
--------------------------------------------------------------------------------
/images/literals.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/literals.png
--------------------------------------------------------------------------------
/images/object-def.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/object-def.png
--------------------------------------------------------------------------------
/images/open-file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/open-file.png
--------------------------------------------------------------------------------
/images/questions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/questions.png
--------------------------------------------------------------------------------
/images/thinking.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/thinking.jpg
--------------------------------------------------------------------------------
/images/thinkining.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/thinkining.jpg
--------------------------------------------------------------------------------
/images/broadcasting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/broadcasting.png
--------------------------------------------------------------------------------
/images/java_stream.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/java_stream.png
--------------------------------------------------------------------------------
/images/phoenix_test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/phoenix_test.jpg
--------------------------------------------------------------------------------
/images/projections.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/projections.png
--------------------------------------------------------------------------------
/images/runtime_pvm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/runtime_pvm.png
--------------------------------------------------------------------------------
/images/shared_ref1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/shared_ref1.png
--------------------------------------------------------------------------------
/images/shared_ref2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/shared_ref2.png
--------------------------------------------------------------------------------
/images/test_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/test_output.png
--------------------------------------------------------------------------------
/ch6_how_functions_and_objects_work_together/problem_2.py:
--------------------------------------------------------------------------------
1 | def to_generator(map_or_filter):
2 | pass
3 |
--------------------------------------------------------------------------------
/images/array_vs_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/array_vs_list.png
--------------------------------------------------------------------------------
/images/example_chart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/example_chart.png
--------------------------------------------------------------------------------
/images/growth_scatter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/growth_scatter.png
--------------------------------------------------------------------------------
/images/leave_the_nest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/leave_the_nest.png
--------------------------------------------------------------------------------
/images/return_to_nest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/return_to_nest.png
--------------------------------------------------------------------------------
/images/run_all_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/run_all_output.png
--------------------------------------------------------------------------------
/images/setup_teardown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/setup_teardown.png
--------------------------------------------------------------------------------
/images/test_methods1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/test_methods1.png
--------------------------------------------------------------------------------
/ch3_collections_and_functions/problem_1.py:
--------------------------------------------------------------------------------
1 | import csv
2 |
3 | def calculate_metrics(filename):
4 | pass
5 |
--------------------------------------------------------------------------------
/ch5_manipulating_objects/problem_0.md:
--------------------------------------------------------------------------------
1 | ## How would you describe method resolution order in the diamond pattern?
--------------------------------------------------------------------------------
/images/argument_matching.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/argument_matching.png
--------------------------------------------------------------------------------
/images/assignment_forms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/assignment_forms.png
--------------------------------------------------------------------------------
/images/iterator_protocol.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/iterator_protocol.png
--------------------------------------------------------------------------------
/images/names_references.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/names_references.png
--------------------------------------------------------------------------------
/images/reverse_operators.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/reverse_operators.png
--------------------------------------------------------------------------------
/images/tuple_operations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/tuple_operations.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .tool-versions
3 | .envrc
4 | *.ipynb_checkpoints
5 | __pycache__/
6 |
7 | solutions
8 |
9 |
--------------------------------------------------------------------------------
/images/built-in-functions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/built-in-functions.png
--------------------------------------------------------------------------------
/images/comparing_paradigms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/comparing_paradigms.png
--------------------------------------------------------------------------------
/images/dictionary_literals.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/dictionary_literals.png
--------------------------------------------------------------------------------
/images/dictionary_methods.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/dictionary_methods.png
--------------------------------------------------------------------------------
/images/inheritance_as_tree.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/inheritance_as_tree.jpg
--------------------------------------------------------------------------------
/images/multiple_inheritance.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/multiple_inheritance.jpg
--------------------------------------------------------------------------------
/images/growth_major_language.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/growth_major_language.png
--------------------------------------------------------------------------------
/images/inheritance_as_circles.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/inheritance_as_circles.jpg
--------------------------------------------------------------------------------
/images/compiler_mountain_diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/compiler_mountain_diagram.png
--------------------------------------------------------------------------------
/images/scanning_lexing_parsing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/scanning_lexing_parsing.png
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [dev-packages]
2 | pytest = "*"
3 |
4 | [requires]
5 | python_version = '3.9'
6 |
7 | [packages]
8 | ipykernel = "*"
9 |
--------------------------------------------------------------------------------
/images/projections_major_languages.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPCS-51042/materials/HEAD/images/projections_major_languages.png
--------------------------------------------------------------------------------
/uchicago-emails.txt:
--------------------------------------------------------------------------------
1 | bob@uchicago.edu
2 | philb@uchicago.edu
3 | sally@uchicago.edu
4 | rebeccaw@uchicago.edu
5 | joan@uchicago.edu
--------------------------------------------------------------------------------
/ch2_syntactic_basics/problem_1.md:
--------------------------------------------------------------------------------
1 | **1. A SHA is...**
2 |
3 | **2. A branch is...**
4 |
5 | **3. A remote...**
6 |
7 | **4. The commands would be..**
--------------------------------------------------------------------------------
/ch3_collections_and_functions/problem_2.py:
--------------------------------------------------------------------------------
1 | from collections.abc import Iterable
2 |
3 | def full_paths(path_components, base_path='/'):
4 | pass
5 |
--------------------------------------------------------------------------------
/clean_notebooks.sh:
--------------------------------------------------------------------------------
1 | notebooks=$(find . -type f -name "*.ipynb")
2 |
3 | for notebook in $notebooks
4 | do
5 | jupyter nbconvert --clear-output --inplace $notebook
6 | done
7 |
--------------------------------------------------------------------------------
/ch5_manipulating_objects/problem_2_3_4_5.py:
--------------------------------------------------------------------------------
1 | from numbers import Rational
2 | import math
3 | from math import gcd, lcm
4 |
5 | class Fraction:
6 | pass
7 |
8 | class NotAnIntegerException:
9 | pass
--------------------------------------------------------------------------------
/ch2_syntactic_basics/problem_6.py:
--------------------------------------------------------------------------------
1 | def find_numbers():
2 | '''
3 | This function computes the combinations of the numbers, 1 through 9, for which
4 |
5 | ABC = A*B*C*(A+B+C)
6 | '''
7 |
--------------------------------------------------------------------------------
/ch3_collections_and_functions/problem_3.py:
--------------------------------------------------------------------------------
1 | import string #(You'll find string.punctuation useful for this problem)
2 |
3 | def fill_completions(fd):
4 | pass
5 |
6 |
7 | def find_completions(prefix, c_dict):
8 | pass
9 |
10 |
11 | def main():
12 | pass
13 |
14 | if __name__ == '__main__':
15 | main()
--------------------------------------------------------------------------------
/ch3_collections_and_functions/problem_6.py:
--------------------------------------------------------------------------------
1 | from problem_4 import taxes_owed
2 |
3 | def inflection_point():
4 | '''
5 | This function returns a float representing the income at which
6 | Townsville's graduated income tax would be higher than a flat
7 | 5% income tax.
8 | '''
9 | pass
10 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/problem_0.md:
--------------------------------------------------------------------------------
1 | ## Explaining the `test` method:
2 |
3 | **1. What are the arguments and what types do these arguments need to have for this function to work?**
4 |
5 |
6 | **2. Walk us through the code line by line. What is happening here?**
7 |
8 |
9 | **3. Does this function have a return value? How do you know?**
--------------------------------------------------------------------------------
/ch4_manipulating_functions/problem_3.py:
--------------------------------------------------------------------------------
1 | # As a reminder, do not import Iterable here.
2 | # You don't need that library to check if something is iterable.
3 | # You know which data structures are iterable :)
4 | # (hint: you can use isinstance(expression, type) to identify the type of an expression)
5 |
6 | def maketuple():
7 | pass
8 |
--------------------------------------------------------------------------------
/ch3_collections_and_functions/problem_4.py:
--------------------------------------------------------------------------------
1 | def taxes_owed(income):
2 | '''
3 | This function takes in an income as an integer or float and
4 | returns taxes owed as a float, truncated at two digits.
5 |
6 | Inputs:
7 | income (integer or float)
8 |
9 | Output:
10 | taxes owed (float)
11 | '''
12 | pass
13 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/problem_5.py:
--------------------------------------------------------------------------------
1 |
2 | def mean(string_of_numbers):
3 | '''
4 | This function takes in a space-separated string of integers and floats and
5 | returns a their mean as a float.
6 |
7 | Inputs:
8 | string_of_numbers (string): a space-separated string of integers and floats.
9 |
10 | Output:
11 | a float, the mean of the inputted numbers.
12 | '''
13 | pass
--------------------------------------------------------------------------------
/ch3_collections_and_functions/problem_5.py:
--------------------------------------------------------------------------------
1 | from problem_4 import taxes_owed
2 | import csv
3 |
4 | def total_impact(strategy):
5 | '''
6 | This function takes in a tax strategy as a string and
7 | returns a tuple of tax_revenue and poverty_burden.
8 |
9 | Inputs:
10 | tax strategy (string)
11 |
12 | Output:
13 | tax_revenue and poverty_burden (tuple, float and integer)
14 | '''
15 | pass
--------------------------------------------------------------------------------
/ch3_collections_and_functions/that_test_function_from_last_chapter.py:
--------------------------------------------------------------------------------
1 | def test(function, examples):
2 | passed = 0
3 | run = 0
4 |
5 | for example in examples:
6 | run += 1
7 | expected = example[-1]
8 | actual = function(*example[:-1])
9 |
10 | if expected == actual:
11 | passed += 1
12 | else:
13 | print(f"Whoops. For example {example}, the function returned {actual}.")
14 |
15 | print(f"\n{passed} out of {run} examples worked as expected.")
--------------------------------------------------------------------------------
/ch3_collections_and_functions/townsville.csv:
--------------------------------------------------------------------------------
1 | id,income
2 | 23423423,32000
3 | 23423423,32000
4 | 23423423,32000
5 | 23423423,32000
6 | 23423423,39000
7 | 23423423,39000
8 | 23423423,39000
9 | 23423423,39000
10 | 23423423,41000
11 | 23423423,41000
12 | 23423423,41000
13 | 23423423,41000
14 | 23423423,41000
15 | 23423423,50000
16 | 23423423,50000
17 | 23423423,50000
18 | 23423423,50000
19 | 23423423,90000
20 | 23423423,90000
21 | 23423423,90000
22 | 23423423,120000
23 | 23423423,150000
24 | 23423423,200000
25 | 23423423,1500000
--------------------------------------------------------------------------------
/ch2_syntactic_basics/problem_4.py:
--------------------------------------------------------------------------------
1 |
2 | def expand_letter_ranges(string_of_letters):
3 | '''
4 | This function takes in a comma-separated string of letters and letter ranges and
5 | returns a list of the letters and expanded ranges in alphabetical order.
6 |
7 | Inputs:
8 | string_of_letters (string): a comma-separated string of letters and letter ranges.
9 |
10 | Output:
11 | a list of the letters and expanded ranges in alphabetical order.
12 | '''
13 | pass
--------------------------------------------------------------------------------
/ch2_syntactic_basics/problem_3.py:
--------------------------------------------------------------------------------
1 |
2 | def find_twos(string_1, string_2):
3 | '''
4 | This function takes in two strings that only contains integers, commas and whitespace and
5 | returns a list of integers, where each integer,
6 |
7 | 1. Appears in both strings
8 | 2. Contains a 2 as a digit in the number.
9 |
10 | Inputs:
11 | str1, str2 (string): strings that contains integers, commas, and whitespace. You can assume each integer is separated by a single comma followed by zero or more whitespaces.
12 |
13 | Output:
14 | A list of integers, where the list contents is described by above. The returned list must not contain duplicates.
15 | '''
16 | pass
--------------------------------------------------------------------------------
/data_frame_exercise/birds.csv:
--------------------------------------------------------------------------------
1 | species,specimen_id,weight
2 | oriole,7ss24g6t7f2dr4h32,4.23
3 | oriole,7dr4h32ss24g6t7f2,4.17
4 | oriole,g6t7f2dr4h327ss24,5.21
5 | oriole,t77ss24g6f2dr4h32,3.22
6 | oriole,327ss24g6t7f2dr4h,4.00
7 | oriole,6t7ss24g5f2dr4h32,3.98
8 | oriole,2f2dr4h37ss24g6t7,5.00
9 | blue jay,88Jnnb323es29bs2f,5.23
10 | blue jay,3d329bs2f24g6t7f2,6.32
11 | blue jay,g6t3f2dr4h322ss24,5.21
12 | blue jay,f2dr4t76ss24g6h32,4.85
13 | blue jay,t7f2312ss24g6dr4h,4.91
14 | blue jay,5f26t1ss24gdr4h32,5.69
15 | blue jay,9f237ss24g6t8dr4h,5.22
16 | titmouse,1sn32ufks82d92b39,2.13
17 | titmouse,8sh2bdn4s24g6t7f2,3.10
18 | titmouse,h38snsdr4h327ss24,2.21
19 | titmouse,dr4h3224g6tg5f2dr,2.22
20 | titmouse,32bf72f9m27f2dr4h,3.00
21 | titmouse,2b47f29fn34h47dn3,2.98
22 | titmouse,t77ss24g6f27s41md,3.00
23 |
--------------------------------------------------------------------------------
/ch3_collections_and_functions/problem_0.md:
--------------------------------------------------------------------------------
1 | ## Evaluating the `test` method:
2 |
3 | **1. What differences do you notice between the functions that we do test with this method and the ones that we don't test with this method? Why do you think we chose to use it where we did?**
4 |
5 |
6 | **2. If you were in charge of writing a Python package to help other programmers write automated tests in Python, what would you want it to do that the test method doesn't do? You can talk about functionalities that you wish it had that it doesn't have such as "I wish I could test stuff about a function besides just its return value", or you can talk about stuff that you wish it did differently such as "I wish the way the variables get passed in were more clear. Something like this...(and then explain how you'd like to see it done)."**
--------------------------------------------------------------------------------
/ch7_intro_to_data_engineering/birds.csv:
--------------------------------------------------------------------------------
1 | species,specimen_id,weight
2 | oriole,7ss24g6t7f2dr4h32,4.23
3 | oriole,7dr4h32ss24g6t7f2,4.17
4 | oriole,g6t7f2dr4h327ss24,5.21
5 | oriole,t77ss24g6f2dr4h32,3.22
6 | oriole,327ss24g6t7f2dr4h,4.00
7 | oriole,6t7ss24g5f2dr4h32,3.98
8 | oriole,2f2dr4h37ss24g6t7,5.00
9 | blue jay,88Jnnb323es29bs2f,5.23
10 | blue jay,3d329bs2f24g6t7f2,6.32
11 | blue jay,g6t3f2dr4h322ss24,5.21
12 | blue jay,f2dr4t76ss24g6h32,4.85
13 | blue jay,t7f2312ss24g6dr4h,4.91
14 | blue jay,5f26t1ss24gdr4h32,5.69
15 | blue jay,9f237ss24g6t8dr4h,5.22
16 | titmouse,1sn32ufks82d92b39,2.13
17 | titmouse,8sh2bdn4s24g6t7f2,3.10
18 | titmouse,h38snsdr4h327ss24,2.21
19 | titmouse,dr4h3224g6tg5f2dr,2.22
20 | titmouse,32bf72f9m27f2dr4h,3.00
21 | titmouse,2b47f29fn34h47dn3,2.98
22 | titmouse,t77ss24g6f27s41md,3.00
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # materials
2 | This is an interactive workbook for learning Python programming. It is designed to be:
3 |
4 | 1. Easy to set up. I've included minimal external libraries on purpose.
5 | 2. Self-paced. The chapters are sequential.
6 | 3. Friendly to ALL learning styles: auditory, visual, both, trying things out, breaking stuff...
7 | 4. Free. Forever and ever, amen.
8 |
9 | How to set up:
10 |
11 | 1. Clone this repo.
12 | 1. Install Python 3+. Most computers come with this these days.
13 | 1. Install pip.
14 | 1. Install jupyter with `pip install jupyter`.
15 | 1. Navigate to the repo.
16 | 1. Run `jupyter lab`.
17 |
18 | That's gonna open a browser tab that shows you all the folders on the left. You can navigate into the folders and open any of the .ipynb files. If you're new to all this, start at chapter 1. Each notebook links to videos explaining everything in them.
19 |
20 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/problem_7.py:
--------------------------------------------------------------------------------
1 |
2 | def find_minimum(sequence, comparator=None):
3 | '''
4 | :param sequence: a list of items (like numbers or strings) that decreases, then increases
5 |
6 | :param comparator (optional): a function that takes in TWO items
7 | and returns a boolean indicating whether the first one is smaller than the second
8 |
9 | :return: A tuple containing the smallest item and the index at which it occurs
10 | '''
11 | pass
12 |
13 | class TrainingAttempt():
14 | def __init__(self, id, weights, error):
15 | self.id = id
16 | self.weights = weights
17 | self.error = error
18 |
19 | def __repr__(self):
20 | return f'TrainingAttempt {self.id}'
21 |
22 | def total_error(training_attempt):
23 | '''
24 | :param training_attempt: a TrainingAttempt
25 |
26 | :return: the error of a given TrainingAttempt
27 | '''
28 | pass
29 |
--------------------------------------------------------------------------------
/test_framework_exercise/phoenix_test/manipulators.py:
--------------------------------------------------------------------------------
1 | def mock(call, to_return):
2 | def decorator(func):
3 | def wrapper(testobject):
4 | module = eval('.'.join(call.split('.')[:-1]))
5 | module_function_name = call.split('.')[-1]
6 | module_function_body = getattr(module, module_function_name)
7 | setattr(module, module_function_name, lambda: to_return)
8 |
9 | func(testobject)
10 |
11 | setattr(module, module_function_name, module_function_body)
12 |
13 | return wrapper
14 |
15 | return decorator
16 |
17 | def parametrize(inputs):
18 | def decorator(function):
19 | for example in inputs:
20 | print(f"Running {function.__name__} with args {example}")
21 | try:
22 | function(*example)
23 | except Exception as e:
24 | print(" " + str(e))
25 | return decorator
--------------------------------------------------------------------------------
/ch9_intro_to_debugging/bird_watching_session.py:
--------------------------------------------------------------------------------
1 | from collections import namedtuple
2 |
3 | Observation = namedtuple("Observation", "color location_seen")
4 |
5 | class BirdWatchingSession():
6 | def __init__(self):
7 | self.birds_seen = 0
8 | self.classifications = []
9 |
10 | def record(self, *observations):
11 | self.classifications.append([self.classify(observation.color, observation.location_seen) for observation in observations])
12 | birds_seen = self.birds_seen + len(observations)
13 |
14 | def classify(self, color, location_seen):
15 | # It's a peninsula bird if it was seen on Solidarity Drive
16 | peninsula_bird = location_seen = "Solidarity Drive"
17 | if peninsula_bird:
18 | if color == "black":
19 | return "Red-Shouldered Blackbird"
20 | if color == "red":
21 | return "Serrano (Field Museum's Scarlet Maccaw)"
22 | if color == "green":
23 | return "Pablo (Field Museum's Greenwing Maccaw)"
24 | if color == "grey":
25 | return "Seagull"
26 | else:
27 | if color == "brown":
28 | return "juvenile Bald Eagle"
29 | if color == "grey":
30 | return "Eastern Heron"
31 | if color == "black":
32 | return "Raven"
33 |
34 |
35 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/problem_8.py:
--------------------------------------------------------------------------------
1 |
2 | def power_status(grid, row_bounds, col_bounds):
3 | '''
4 | Determines the status of the homes within a sector. A sector is defined by a row and column
5 | boundary. A row boundary is a tuple of two integers from ([0, nRows), [0, nRows)) and the column
6 | boundary is a tuple of two integers ([0, nColumns), [0, nColumns)), where nRows is equal to the
7 | number of rows in the grid and nColumns is equal to the number of columns in the grid. Make note
8 | the upper-bound is exclusive!
9 |
10 | Based on the boundary specified, the function returns a list indicating the power status of the
11 | homes within the bounds of the sector. Order in the list does matter! Start at the top-left of the
12 | sector and work your way down towards the bottom-right corner. You increase by in the columns. Once
13 | you finish with a row then you move to the next row (i.e., increase by 1).
14 |
15 | You can assume the the first component of the boundary is always less than the second component.
16 |
17 | Inputs:
18 | grid(list of list of bools): the status of the homes
19 | row_bounds(tuple of ints): the row boundary for the sector
20 | col_bounds(tuple of ints): the column boundary for the sector
21 |
22 | Outputs:
23 | Returns a list of booleans indicating the power status of the homes within the bounds of the sector.
24 |
25 | '''
26 | pass
27 |
--------------------------------------------------------------------------------
/test_framework_exercise/phoenix_test/test.py:
--------------------------------------------------------------------------------
1 | from colorama import Fore, Back, Style
2 |
3 | class Test():
4 | types = []
5 |
6 | def __init_subclass__(cls, **kwargs):
7 | super().__init_subclass__(**kwargs)
8 | cls.types.append(cls)
9 |
10 | @classmethod
11 | def run_all(cls, only=""):
12 | pass_count = 0
13 | run_count = 0
14 |
15 | for typ in cls.types:
16 | print(f"Running {typ.__name__}: ")
17 | passed, runned = typ().run(only=only)
18 | pass_count += passed
19 | run_count += runned
20 |
21 | print(f"{pass_count} out of {run_count} tests passed.\n")
22 |
23 | def setup(self):
24 | pass
25 |
26 | def teardown(self):
27 | pass
28 |
29 | def run(self, only=""):
30 | run_count = 0
31 | pass_count = 0
32 | test_methods = [
33 | token for token in dir(self) \
34 | if token.startswith("test") \
35 | and only in token \
36 | and callable(getattr(self.__class__, token))
37 | ]
38 | for method in test_methods:
39 | self.setup()
40 | run_count += 1
41 | try:
42 | getattr(self.__class__, method).__call__(self)
43 | pass_count += 1
44 | print(Fore.GREEN + f" {method} passed!")
45 | except Exception as e:
46 | print(Fore.RED + f" {method}: {e}")
47 | self.teardown()
48 | print(Style.RESET_ALL + f" {pass_count} out of {run_count} tests passed.\n")
49 | return pass_count, run_count
50 |
--------------------------------------------------------------------------------
/test_framework_exercise/phoenix_test/matchers.py:
--------------------------------------------------------------------------------
1 | class FailedAssertion(Exception):
2 | pass
3 |
4 | class Assertion:
5 | def __init__(self, expression):
6 | self.expression = expression
7 |
8 | def is_true(self):
9 | '''
10 | Returns True if expression evaluates to true
11 | And raises a FailedAssertion if it doesn't.
12 | '''
13 | if self.expression:
14 | return True
15 | else:
16 | raise FailedAssertion(f"Expected the asserted expression to be true, but was false.")
17 |
18 | def equals(self, expected_result):
19 | '''
20 | Returns True if expression == expected result
21 | And raises a FailedAssertion if it doesn't.
22 | '''
23 | if self.expression == expected_result:
24 | return True
25 | else:
26 | raise FailedAssertion(f"Expected {expected_result} but got {self.expression}")
27 |
28 | def is_empty(self):
29 | '''
30 | This method returns True if a collection has no items
31 | And it raises a FailedAssertion if it doesn't.
32 | '''
33 | if len(self.expression) == 0:
34 | return True
35 | else:
36 | raise FailedAssertion(f"Expected {self.expression} to be empty")
37 |
38 |
39 | def has_size(self, size):
40 | '''
41 | This method returns True if a collection has the right number of items
42 | And it raises a FailedAssertion if it doesn't.
43 | '''
44 | if len(self.expression) == size:
45 | return True
46 | else:
47 | raise FailedAssertion(f"Expected {self.expression} to have size {size} but it instead had size {len(self.expression)}")
48 |
49 | def has_items(self, *args):
50 | '''
51 | This method returns True if a collection has the right items
52 | And it raises a FailedAssertion if it doesn't.
53 | '''
54 | missing_items = []
55 | for item in args:
56 | if not item in self.expression:
57 | missing_items.append(item)
58 | if missing_items:
59 | raise FailedAssertion(f"Expected {self.expression} to have items {missing_items}")
60 |
61 | def assert_that(expression):
62 | return Assertion(expression)
--------------------------------------------------------------------------------
/course_utils.py:
--------------------------------------------------------------------------------
1 | class Test:
2 | def __init__(self, examples=[], function=None, test_class=None):
3 | self.examples = examples
4 | self.function = function
5 | self.test_class = test_class
6 | self.passed = 0
7 | self.run = 0
8 |
9 | def equivalence(self):
10 | for i, (actual, expected) in enumerate(self.examples):
11 | self.run += 1
12 | if expected == actual:
13 | self.passed += 1
14 | else:
15 | print(
16 | f"Whoops. For example {i}, the function returned {actual} and should've returned {expected}."
17 | )
18 |
19 | print(f"\n{self.passed} out of {self.run} examples worked as expected.")
20 |
21 | def generator_function(self):
22 | for i, example in enumerate(self.examples):
23 | self.run += 1
24 | expected = example[-1]
25 | actual = list(self.function(*example[:-1]))
26 |
27 | if expected == actual:
28 | self.passed += 1
29 | else:
30 | print(
31 | f"Whoops. For example {i}, the function returned {actual} and should've returned {expected}."
32 | )
33 |
34 | print(f"\n{self.passed} out of {self.run} examples worked as expected.")
35 |
36 | def passed_function(self):
37 | for i, example in enumerate(self.examples):
38 | self.run += 1
39 | test_func, inputs, expected = example
40 | actual = self.function(test_func)(*inputs)
41 |
42 | if expected == actual:
43 | self.passed += 1
44 | else:
45 | print(
46 | f"Whoops. For example {i} wrapping {test_func} with inputs {inputs}, the function returned {actual}."
47 | )
48 |
49 | print(f"\n{self.passed} out of {self.run} examples worked as expected.")
50 |
51 | def pitch_errors(self):
52 | for i, (string, error) in enumerate(self.examples):
53 | self.run += 1
54 | found = False
55 | try:
56 | eval(string, {"Pitch": self.test_class})
57 | except ValueError:
58 | if error == ValueError:
59 | self.passed += 1
60 | found = True
61 | except TypeError:
62 | if error == TypeError:
63 | self.passed += 1
64 | found = True
65 | finally:
66 | if not found:
67 | print(
68 | f"Whoops. For example {i}, the expression {string} failed to throw {error}."
69 | )
70 |
71 | print(f"\n{self.passed} out of {self.run} examples worked as expected.")
72 |
73 |
74 | def first_digit(x):
75 | return int(str(x)[0])
76 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/2.8_Modules.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Video Explanation [Available Here](https://www.youtube.com/watch?v=MFCmUT75Ejc)!\n",
8 | "\n",
9 | "\n",
10 | "### Module Basics \n",
11 | "\n",
12 | "Python programs can be defined in ``.py`` files. These files are also known as *modules*. A module is a file containing Python definitions and statements. The file name is the module name minus the ``.py`` suffix. \n",
13 | "\n",
14 | "**What if you want these files to interact with each other (i.e., call functions, use variables from different modules)?**\n",
15 | "\n",
16 | " - Modules *import* other modules by using the ``import`` statement. \n",
17 | " - ``import module_name`` \n",
18 | " - Import statements should be placed at the beginning of a python file. \n",
19 | " - Once imported, you can access the definitions and statements within the module. \n",
20 | " - default way to access variables and statements is to use dot notation, where you specify the name of the module followed by a period, and then the code you want to access. \n",
21 | " - ``module_name.variable`` or ``module_name.func(arg1,arg2,...)`` \n",
22 | "\n",
23 | "Python provides an extensive amount of predefined modules as part of its standard library. We will look at the ``math`` module and see how we can import and use the code within that module. "
24 | ]
25 | },
26 | {
27 | "cell_type": "code",
28 | "execution_count": null,
29 | "metadata": {},
30 | "outputs": [],
31 | "source": [
32 | "# 1st import the math module \n",
33 | "import math \n",
34 | "\n",
35 | "print(math.pi) # Print the constant PI from the math module.\n",
36 | "print(math.fabs(-232)) # Call the floating point abs function from the math module b"
37 | ]
38 | },
39 | {
40 | "cell_type": "markdown",
41 | "metadata": {},
42 | "source": [
43 | "You can also use just the name of the variable or function by importing it like so:"
44 | ]
45 | },
46 | {
47 | "cell_type": "code",
48 | "execution_count": null,
49 | "metadata": {},
50 | "outputs": [],
51 | "source": [
52 | "from math import pi\n",
53 | "\n",
54 | "print(pi)"
55 | ]
56 | },
57 | {
58 | "cell_type": "code",
59 | "execution_count": null,
60 | "metadata": {},
61 | "outputs": [],
62 | "source": []
63 | }
64 | ],
65 | "metadata": {
66 | "kernelspec": {
67 | "display_name": "Python 3",
68 | "language": "python",
69 | "name": "python3"
70 | },
71 | "language_info": {
72 | "codemirror_mode": {
73 | "name": "ipython",
74 | "version": 3
75 | },
76 | "file_extension": ".py",
77 | "mimetype": "text/x-python",
78 | "name": "python",
79 | "nbconvert_exporter": "python",
80 | "pygments_lexer": "ipython3",
81 | "version": "3.9.0"
82 | }
83 | },
84 | "nbformat": 4,
85 | "nbformat_minor": 4
86 | }
87 |
--------------------------------------------------------------------------------
/move_me/Assertion_Examples_from_Minitest.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Video 9.3: Software Testing \n",
8 | "\n",
9 | "There are a few main levels of software testing: \n",
10 | "\n",
11 | " - **Unit testing**: tests that verify functionality of specific\n",
12 | " sections of code (often at the function level)\n",
13 | " - With unit-testing, you are testing a *got* value (i.e., the value returned by a piece of code) versus an *expected* value (i.e., what you as the programmer is expecting piece of code to return). \n",
14 | " - The default testing module provided by Python is ``unittest``, which provides and object-oriented style of writing tests, inspired by the JUnit framework from Java. \n",
15 | " - You can also use third-party tools such as \"pytest\". \n",
16 | " \n",
17 | "- **Integration testing**: combine individual functions/modules and\n",
18 | " test as a group. Not covered in this class. Take the software engineering course. \n",
19 | "- **System testing**: test a complete, integrated system to evaluate compliance with its specified requirements. Not covered in this class. Take the software engineering course.\n",
20 | " "
21 | ]
22 | },
23 | {
24 | "cell_type": "markdown",
25 | "metadata": {},
26 | "source": [
27 | "#### unittest Module \n",
28 | "\n",
29 | "Python provides a unit testing framework in the ``unittest`` standard library module. This module provides a wide range of functions fo rtesting these values: \n",
30 | "\n",
31 | "  -- Learning Python 2013\n",
32 | " \n",
33 | " - From a command line, invoking ``python3 -m unittest`` will search for modules with unit tests starting from the current directory\n",
34 | " - Runs tests from subclasses of ``TestCase`` in any file named ``test*.py `` \n",
35 | " \n",
36 | " See example in: `unittests/test_stringmethods.py` and `unittests/test_file.py` "
37 | ]
38 | },
39 | {
40 | "cell_type": "markdown",
41 | "metadata": {},
42 | "source": [
43 | "#### pytest tool \n",
44 | "\n",
45 | "An alternative testing tool that is common in the Python community is to use *pytest*. It boasts a simple syntax.\n",
46 | "\n",
47 | "Walk through the tutorial here: https://docs.pytest.org/en/latest/getting-started.html \n"
48 | ]
49 | }
50 | ],
51 | "metadata": {
52 | "kernelspec": {
53 | "display_name": "Python 3",
54 | "language": "python",
55 | "name": "python3"
56 | },
57 | "language_info": {
58 | "codemirror_mode": {
59 | "name": "ipython",
60 | "version": 3
61 | },
62 | "file_extension": ".py",
63 | "mimetype": "text/x-python",
64 | "name": "python",
65 | "nbconvert_exporter": "python",
66 | "pygments_lexer": "ipython3",
67 | "version": "3.9.0"
68 | }
69 | },
70 | "nbformat": 4,
71 | "nbformat_minor": 2
72 | }
73 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/2.3_Lists.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Video Explanation [Available Here](https://www.youtube.com/watch?v=LJAimERKQns)!\n",
8 | "\n",
9 | "\n",
10 | "### Lists \n",
11 | "\n",
12 | " - A collection of positionally-ordered values of any type (you can even have multiple types in the same list!).\n",
13 | " - Dynamically Resizable (i.e., they can be shorten or extended as needed) \n",
14 | " - Mutable (i.e., they can be modified in-place) "
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": null,
20 | "metadata": {},
21 | "outputs": [],
22 | "source": [
23 | "listo = [\"A\", \"B\", \"C\"]\n",
24 | "first_id = id(listo)\n",
25 | "first_id"
26 | ]
27 | },
28 | {
29 | "cell_type": "code",
30 | "execution_count": null,
31 | "metadata": {},
32 | "outputs": [],
33 | "source": [
34 | "listo.append(\"D\")\n",
35 | "modified_id = id(listo)\n",
36 | "modified_id"
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "execution_count": null,
42 | "metadata": {},
43 | "outputs": [],
44 | "source": [
45 | "first_id == modified_id\n",
46 | "listo.append(4)\n",
47 | "listo"
48 | ]
49 | },
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {},
53 | "source": [
54 | "### Some ways to create lists: "
55 | ]
56 | },
57 | {
58 | "cell_type": "code",
59 | "execution_count": null,
60 | "metadata": {},
61 | "outputs": [],
62 | "source": [
63 | "# Empty List \n",
64 | "lst = [] \n",
65 | "type(lst)"
66 | ]
67 | },
68 | {
69 | "cell_type": "code",
70 | "execution_count": null,
71 | "metadata": {},
72 | "outputs": [],
73 | "source": [
74 | "# Defining a list with specified items \n",
75 | "# Remember a list can contain values of different types. \n",
76 | "lst = [123, 'abc', 1.23]\n",
77 | "lst"
78 | ]
79 | },
80 | {
81 | "cell_type": "code",
82 | "execution_count": null,
83 | "metadata": {},
84 | "outputs": [],
85 | "source": [
86 | "# Nested lists (lists within lists) \n",
87 | "lst = ['Bob', 40.0, ['dev', 'mgr']]\n",
88 | "lst"
89 | ]
90 | },
91 | {
92 | "cell_type": "code",
93 | "execution_count": null,
94 | "metadata": {},
95 | "outputs": [],
96 | "source": []
97 | }
98 | ],
99 | "metadata": {
100 | "kernelspec": {
101 | "display_name": "Python 3",
102 | "language": "python",
103 | "name": "python3"
104 | },
105 | "language_info": {
106 | "codemirror_mode": {
107 | "name": "ipython",
108 | "version": 3
109 | },
110 | "file_extension": ".py",
111 | "mimetype": "text/x-python",
112 | "name": "python",
113 | "nbconvert_exporter": "python",
114 | "pygments_lexer": "ipython3",
115 | "version": "3.9.0"
116 | }
117 | },
118 | "nbformat": 4,
119 | "nbformat_minor": 4
120 | }
121 |
--------------------------------------------------------------------------------
/ch1_learning_python/1.2_Running_Python_Programs.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## Running Python Programs\n",
8 | "\n",
9 | "When learning new languages, the traditional first program is the one that prints the text \"hello world\" to the terminal. Here's the implemenetation in Python. "
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": null,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "# This will print \"Hello World\" to the console\n",
19 | "print(\"Hello World\")"
20 | ]
21 | },
22 | {
23 | "cell_type": "markdown",
24 | "metadata": {},
25 | "source": [
26 | "Notes: \n",
27 | " - `print` is a built-in function. It takes a value and prints it to the terminal.\n",
28 | " - You can comment a line in Python with ``#``. "
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "## Running this program\n",
36 | "\n",
37 | "In Python, there are two ways of running code:\n",
38 | "\n",
39 | "### Way 1: The REPL\n",
40 | "\n",
41 | "Using an interactive prompt. You write a line of code, you hit enter, and the interpreter executes that line of code and shows the result (if any). \n",
42 | "\n",
43 | " - The interpreter is accessible via the terminal program on your machine.\n",
44 | " \n",
45 | " - The interpreter is also known as a REPL (read-eval-print loop)\n",
46 | "\n",
47 | " - The REPL is great for learning, experimenting, and testing Python code\n",
48 | "\n",
49 | "\n",
50 | " - **Demo**: Go into your terminal and type in `python`. This opens an interactive Python session for you, where your cursor will be placed on a line with some `>>>` to the left of it. Here, type `print(\"Hello World\")`.\n",
51 | " \n",
52 | "### Way 2: A .py file\n",
53 | " \n",
54 | " - **Demo**: Create a blank file called ``hello.py``, write ``print(\"Hello, world!\")`` inside it. Then, in your terminal, `cd` into the same directory where you put the file and run:\n",
55 | " \n",
56 | " python hello.py"
57 | ]
58 | },
59 | {
60 | "cell_type": "markdown",
61 | "metadata": {},
62 | "source": [
63 | "#### A Usage Note \n",
64 | "\n",
65 | "The REPL is a good tool for experimenting with code interactively. Once your code becomes complex then you will want to save it as a Python program. These programs are saved in a ``.py`` file (or a collection of ``.py`` files). \n",
66 | " "
67 | ]
68 | }
69 | ],
70 | "metadata": {
71 | "kernelspec": {
72 | "display_name": "Python 3",
73 | "language": "python",
74 | "name": "python3"
75 | },
76 | "language_info": {
77 | "codemirror_mode": {
78 | "name": "ipython",
79 | "version": 3
80 | },
81 | "file_extension": ".py",
82 | "mimetype": "text/x-python",
83 | "name": "python",
84 | "nbconvert_exporter": "python",
85 | "pygments_lexer": "ipython3",
86 | "version": "3.9.0"
87 | }
88 | },
89 | "nbformat": 4,
90 | "nbformat_minor": 4
91 | }
92 |
--------------------------------------------------------------------------------
/ch7_intro_to_data_engineering/7.0_Installing_Packages.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### [Video Explanation Here!](https://youtu.be/rwI8vwvSsww)\n",
8 | "\n",
9 | "## Option 1: pip\n",
10 | "\n",
11 | "The standard Python packakage manager, or the tool you use to install Python packages not included in the Python standard libary, is [`pip`](https://pip.pypa.io/en/stable/).\n",
12 | "\n",
13 | "The [Python Package Index](https://pypi.org/) (PyPi), is:\n",
14 | "\n",
15 | "- free to use (maintained and funded by the Python Software Foundation!)\n",
16 | "- allows you to also publish your own packages\n",
17 | "- discover new packages\n",
18 | "- handles installation and uninstallation of packages `pip install package_name`\n",
19 | "\n",
20 | "It's worth noting that, if you used Python 2 and _then_ installed Python 3, you might have both `pip` from Python 2 dependencies and `pip3` for installing Python 3 dependencies. These command names are called _soft links_; you can change where they point to. You can _check_ where they point to by using the `which` command like so. As you can see, my `pip` and `pip3` commands point to the same place, so I can use them interchangeably:\n",
21 | "\n",
22 | ""
23 | ]
24 | },
25 | {
26 | "cell_type": "markdown",
27 | "metadata": {},
28 | "source": [
29 | "## Option 2: Conda\n",
30 | "\n",
31 | "Conda is an alternative packaging system popularized by the Python and R scientific programming community.\n",
32 | "\n",
33 | "### Differences between the two package managers\n",
34 | "\n",
35 | "According to the [Anaconda](https://www.anaconda.com/blog/understanding-conda-and-pip) referece:\n",
36 | "\n",
37 | ">Pip installs Python packages whereas conda installs packages which may contain software written in any language. For example, before using pip, a Python interpreter must be installed via a system package manager or by downloading and running an installer. Conda on the other hand can install Python packages as well as the Python interpreter directly.\n",
38 | "\n",
39 | ">Occasionally a package is needed which is not available as a conda package but is available on PyPI and can be installed with pip. In these cases, it makes sense to try to use both conda and pip.\n",
40 | "\n",
41 | "That said,the two are abit tricky to interoperate, so if you installed Python with `conda`, I recommend using `conda` to install your packages for the purposes of this class. Read more [here](https://docs.conda.io/en/latest/) about how to install packages with conda."
42 | ]
43 | }
44 | ],
45 | "metadata": {
46 | "kernelspec": {
47 | "display_name": "Python 3",
48 | "language": "python",
49 | "name": "python3"
50 | },
51 | "language_info": {
52 | "codemirror_mode": {
53 | "name": "ipython",
54 | "version": 3
55 | },
56 | "file_extension": ".py",
57 | "mimetype": "text/x-python",
58 | "name": "python",
59 | "nbconvert_exporter": "python",
60 | "pygments_lexer": "ipython3",
61 | "version": "3.9.0"
62 | }
63 | },
64 | "nbformat": 4,
65 | "nbformat_minor": 4
66 | }
67 |
--------------------------------------------------------------------------------
/ch5_manipulating_objects/5.4_Static_Methods.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### [Video Explanation Here!](https://youtu.be/6XLSDvr1VmI)\n",
8 | "\n",
9 | "### Static Methods\n",
10 | "\n",
11 | "We have covered instance methods and class methods. There is one last type of method to cover, which is **static methods**."
12 | ]
13 | },
14 | {
15 | "cell_type": "code",
16 | "execution_count": null,
17 | "metadata": {},
18 | "outputs": [],
19 | "source": [
20 | "class Car:\n",
21 | " @staticmethod\n",
22 | " def sound():\n",
23 | " return \"vroom vroom\""
24 | ]
25 | },
26 | {
27 | "cell_type": "code",
28 | "execution_count": null,
29 | "metadata": {},
30 | "outputs": [],
31 | "source": [
32 | "Car.sound()"
33 | ]
34 | },
35 | {
36 | "cell_type": "markdown",
37 | "metadata": {},
38 | "source": [
39 | "This type of method can live on a class, but it takes neither a `cls` class argument nor a `self` instance argument. It can take whatever other arbitrary arguments you like, though!"
40 | ]
41 | },
42 | {
43 | "cell_type": "code",
44 | "execution_count": null,
45 | "metadata": {},
46 | "outputs": [],
47 | "source": [
48 | "class Car:\n",
49 | " @staticmethod\n",
50 | " def sound(use):\n",
51 | " if use == \"commuting\":\n",
52 | " return \"beep beep\"\n",
53 | " elif use == \"racing\":\n",
54 | " return \"ZZOOOOOOMMMM\"\n",
55 | " else:\n",
56 | " return \"vroom vroom\""
57 | ]
58 | },
59 | {
60 | "cell_type": "code",
61 | "execution_count": null,
62 | "metadata": {},
63 | "outputs": [],
64 | "source": [
65 | "Car.sound(\"commuting\")"
66 | ]
67 | },
68 | {
69 | "cell_type": "code",
70 | "execution_count": null,
71 | "metadata": {},
72 | "outputs": [],
73 | "source": [
74 | "Car.sound(\"racing\")"
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "execution_count": null,
80 | "metadata": {},
81 | "outputs": [],
82 | "source": [
83 | "Car.sound(\"show\")"
84 | ]
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {},
89 | "source": [
90 | "In these cases, the state of the class itself has little to do with the method. Instead, the class mostly serves as a **namespace** for the static method: a convenient label on the front that:\n",
91 | "\n",
92 | "- Gives some more information about when to use the method\n",
93 | "- Makes it unique from other methods with the same _signature_ (taking the same arguments but doing different things).\n",
94 | "\n",
95 | "Example:"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": null,
101 | "metadata": {},
102 | "outputs": [],
103 | "source": [
104 | "class Noun:\n",
105 | " @staticmethod\n",
106 | " def definition(word):\n",
107 | " if word == \"stick\":\n",
108 | " return \"A thin piece of wood that has fallen or been cut from a tree.\"\n",
109 | "\n",
110 | "class Verb:\n",
111 | " @staticmethod\n",
112 | " def definition(word):\n",
113 | " if word == \"stick\":\n",
114 | " return \"Adhere or cling to something.\""
115 | ]
116 | },
117 | {
118 | "cell_type": "code",
119 | "execution_count": null,
120 | "metadata": {},
121 | "outputs": [],
122 | "source": [
123 | "Noun.definition(\"stick\")"
124 | ]
125 | },
126 | {
127 | "cell_type": "code",
128 | "execution_count": null,
129 | "metadata": {},
130 | "outputs": [],
131 | "source": [
132 | "Verb.definition(\"stick\")"
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "execution_count": null,
138 | "metadata": {},
139 | "outputs": [],
140 | "source": []
141 | }
142 | ],
143 | "metadata": {
144 | "kernelspec": {
145 | "display_name": "Python 3",
146 | "language": "python",
147 | "name": "python3"
148 | },
149 | "language_info": {
150 | "codemirror_mode": {
151 | "name": "ipython",
152 | "version": 3
153 | },
154 | "file_extension": ".py",
155 | "mimetype": "text/x-python",
156 | "name": "python",
157 | "nbconvert_exporter": "python",
158 | "pygments_lexer": "ipython3",
159 | "version": "3.9.0"
160 | }
161 | },
162 | "nbformat": 4,
163 | "nbformat_minor": 4
164 | }
165 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/2.7_Functions.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Video Explanation [Available Here](https://www.youtube.com/watch?v=stCCrAx-z_k)!\n",
8 | "\n",
9 | "\n",
10 | "### Functions \n",
11 | "\n",
12 | "A *function* is a set of statements that can be called more than once. \n",
13 | "\n",
14 | "Benefits of functions:\n",
15 | " - Encapsulation: package logic for use in multiple places\n",
16 | " - Procedural decomposition: split our program into subtasks (i.e., functions) with separate roles.\n",
17 | " - Make life easier for debugging, testing, doing maintenance on code"
18 | ]
19 | },
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {},
23 | "source": [
24 | "### Steps to define a function:\n",
25 | " \n",
26 | " 1. The ``def`` defines a new function called ``name``.\n",
27 | " 2. Define zero or more parameters separated by commas in parentheses\n",
28 | " 3. A colon to indicate the beginning of the function body.\n",
29 | " 4. Functions ca define a **docstring** that provides a description of the function.\n",
30 | " 4. Statements inside function are indented and don’t run until the function is called\n",
31 | " 5. ``return`` can appear anywhere in body of function\n",
32 | " - Can also be omitted. A function that does not return a value will return ``None`` by default. \n",
33 | "\n",
34 | "\n"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": null,
40 | "metadata": {},
41 | "outputs": [],
42 | "source": [
43 | "def identify_bird(weight): \n",
44 | " '''\n",
45 | " Identifies birds (approximately) by their weight \n",
46 | " \n",
47 | " Inputs: \n",
48 | " weight(float): the bird's weight in grams \n",
49 | " \n",
50 | " Output:\n",
51 | " Returns the likely species of the bird as a string\n",
52 | " \n",
53 | " '''\n",
54 | " species = ''\n",
55 | " if weight < 100:\n",
56 | " species = \"Budgie\"\n",
57 | " elif weight < 200:\n",
58 | " species = \"Sun Conure\"\n",
59 | " elif weight < 1000:\n",
60 | " species = \"Toucan\"\n",
61 | " else: \n",
62 | " species = \"Maccaw\" \n",
63 | " \n",
64 | " return species \n",
65 | "\n",
66 | "# Call the function by specifying its name followed by any necessary arguments to the function \n",
67 | "print(identify_bird(17))\n",
68 | "print(identify_bird(240))"
69 | ]
70 | },
71 | {
72 | "cell_type": "markdown",
73 | "metadata": {},
74 | "source": [
75 | "#### Pass statement \n",
76 | "\n",
77 | "The ``pass`` statement useful when you are not ready to write the implementation for a code block. The statement allows the interpreter to perform no operation and to continue processing the next statement. "
78 | ]
79 | },
80 | {
81 | "cell_type": "code",
82 | "execution_count": null,
83 | "metadata": {},
84 | "outputs": [],
85 | "source": [
86 | "def identify_bird(weight): \n",
87 | " '''\n",
88 | " Identifies birds (approximately) by their weight \n",
89 | " \n",
90 | " Inputs: \n",
91 | " weight(float): the bird's weight in grams \n",
92 | " \n",
93 | " Output:\n",
94 | " Returns the likely species of the bird as a string\n",
95 | " \n",
96 | " '''\n",
97 | " pass # IMPLEMENT ME\n",
98 | "\n",
99 | "print(\"----begin processing bird weights---\")\n",
100 | "print(identify_bird(450)) # No error, prints None because we do not have a return statement so None is returned \n",
101 | "print(identify_bird(1500)) # No error, prints None because we do not have a return statement so None is returned \n",
102 | "print(\"Done.\")"
103 | ]
104 | },
105 | {
106 | "cell_type": "code",
107 | "execution_count": null,
108 | "metadata": {},
109 | "outputs": [],
110 | "source": [
111 | "# Pass can be used in any code block statements: loops, classes (later), functions, etc. \n",
112 | "\n",
113 | "print(\"Start\")\n",
114 | "for r in range(10):\n",
115 | " pass \n",
116 | "print(\"Done\")"
117 | ]
118 | },
119 | {
120 | "cell_type": "code",
121 | "execution_count": null,
122 | "metadata": {},
123 | "outputs": [],
124 | "source": []
125 | }
126 | ],
127 | "metadata": {
128 | "kernelspec": {
129 | "display_name": "Python 3",
130 | "language": "python",
131 | "name": "python3"
132 | },
133 | "language_info": {
134 | "codemirror_mode": {
135 | "name": "ipython",
136 | "version": 3
137 | },
138 | "file_extension": ".py",
139 | "mimetype": "text/x-python",
140 | "name": "python",
141 | "nbconvert_exporter": "python",
142 | "pygments_lexer": "ipython3",
143 | "version": "3.9.0"
144 | }
145 | },
146 | "nbformat": 4,
147 | "nbformat_minor": 4
148 | }
149 |
--------------------------------------------------------------------------------
/ch5_manipulating_objects/5.8_Multiple_Inheritance.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### [Video Explanation Here!](https://youtu.be/sHXoMeDSgHQ)\n",
8 | "\n",
9 | "### Multiple Inheritance \n",
10 | "\n",
11 | "We talked about inheritance where one class can inherit the existing code from a prexisitng class by doing the following: \n"
12 | ]
13 | },
14 | {
15 | "cell_type": "code",
16 | "execution_count": null,
17 | "metadata": {},
18 | "outputs": [],
19 | "source": [
20 | "class Subclass(Superclass):\n",
21 | " pass "
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "metadata": {},
27 | "source": [
28 | "However, in Python, a subclass can inherit from more than a single superclass. We call this **multiple inheritance**. You specify the inheritance in the ``()`` seperated by commas "
29 | ]
30 | },
31 | {
32 | "cell_type": "code",
33 | "execution_count": null,
34 | "metadata": {},
35 | "outputs": [],
36 | "source": [
37 | "class Subclass(Superclass1, Superclass2, Superclass3):\n",
38 | " pass "
39 | ]
40 | },
41 | {
42 | "cell_type": "markdown",
43 | "metadata": {},
44 | "source": [
45 | "### Let's talk about Multiple Inheritance and what it means for Python.\n",
46 | "\n",
47 | "Most programming lessons depict inheritance as a tree, with subclasses stemming from the superclasses that they extend.\n",
48 | "\n",
49 | "\n",
50 | "\n",
51 | "So a subclass inherits attributes and behavior from superclasses, the way a child might inherit physical attributes from a parent.\n",
52 | "\n",
53 | "Here’s where that analogy breaks down, though: most languages strictly support single inheritance: that is, a class can only inherit from one other class. That forces us into conceptualizing inheritance not as a tree, but as a set of concentric circles, with each subclass occupying a smaller circle inside that of its superclass.\n",
54 | "\n",
55 | "\n",
56 | "\n",
57 | "In languages with single inheritance, you can't have any circle crossing over the boundary of one of its bigger circles. So each time we make a subclass, we’re making a wager that two things are true:\n",
58 | "\n",
59 | "1. What’s true of the superclass is true of the subclass.\n",
60 | "2. The subclass is only a special case of this superclass; not of anything else.\n",
61 | "\n",
62 | "That’s a pretty bold wager, and we often get it wrong. When we get it wrong and leave the inheritance structure intact, we have to do weird stuff like:\n",
63 | "\n",
64 | "- Override superclass methods with no-ops (when things that are true of the superclass are not true of the subclass)\n",
65 | "- Include modules or inject dependencies (when the subclass is a special case of something besides its superclass. This isn’t weird in and of itself, but you can end up in discussions about which thing should be the superclass and which should be the dependencies that force you to model the problem space in arbitrary, inaccurate ways).\n",
66 | "\n",
67 | "Python is one of the languages that supports the imperative paradigm with multiple inheritance, which allows a class to subclass multiple other classes. \n",
68 | "\n",
69 | "Allowing classes to inherit from multiple other classes frees us up to build structures that resemble generational family trees, with multiple ancestors. \n",
70 | "\n",
71 | "\n",
72 | "\n",
73 | "This de-risks the choice to make a subclass because the subclass does not have to be a special case of only this thing. If a class needs to inherit several behaviors, but different subclasses need those behaviors mixed and matched, then we can divide those behaviors into separate superclasses and have each subclass inherit only the relevant ones.\n",
74 | "\n",
75 | "It fits with the Python philosophy that the language would allow multiple inheritance. A language that allows multiple inheritance also allows single inheritance, and Python often strives for a single implementation that encompasses all use cases, as we have seen with the case statement and with Python's use of abstract base classes instead of an interface construct."
76 | ]
77 | },
78 | {
79 | "cell_type": "code",
80 | "execution_count": null,
81 | "metadata": {},
82 | "outputs": [],
83 | "source": []
84 | }
85 | ],
86 | "metadata": {
87 | "kernelspec": {
88 | "display_name": "Python 3",
89 | "language": "python",
90 | "name": "python3"
91 | },
92 | "language_info": {
93 | "codemirror_mode": {
94 | "name": "ipython",
95 | "version": 3
96 | },
97 | "file_extension": ".py",
98 | "mimetype": "text/x-python",
99 | "name": "python",
100 | "nbconvert_exporter": "python",
101 | "pygments_lexer": "ipython3",
102 | "version": "3.9.0"
103 | }
104 | },
105 | "nbformat": 4,
106 | "nbformat_minor": 4
107 | }
108 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/2.4_Tuples.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Video Explanation [Available Here](https://www.youtube.com/watch?v=v1BzeCuF9_Q)!\n",
8 | "\n",
9 | "\n",
10 | "### Tuples \n",
11 | "\n",
12 | "A ``tuple`` is an immutable sequence of arbitrary objects that are also:\n",
13 | " \n",
14 | " - Fixed-length\n",
15 | " - Heterogeneous\n",
16 | " - Arbitrarily nestable\n",
17 | "\n",
18 | "### Making a Tuple: "
19 | ]
20 | },
21 | {
22 | "cell_type": "code",
23 | "execution_count": null,
24 | "metadata": {},
25 | "outputs": [],
26 | "source": [
27 | "# Empty Tuple\n",
28 | "tup = () \n",
29 | "tup"
30 | ]
31 | },
32 | {
33 | "cell_type": "code",
34 | "execution_count": null,
35 | "metadata": {},
36 | "outputs": [],
37 | "source": [
38 | "# A one-item tuple (not an expression)\n",
39 | "tup = (0,) \n",
40 | "tup "
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {},
46 | "source": [
47 | "**Waaaait a second.**. Why can't we just say `(0)`?\n",
48 | "\n",
49 | "Let's try it!"
50 | ]
51 | },
52 | {
53 | "cell_type": "code",
54 | "execution_count": null,
55 | "metadata": {},
56 | "outputs": [],
57 | "source": [
58 | "(0)"
59 | ]
60 | },
61 | {
62 | "cell_type": "markdown",
63 | "metadata": {},
64 | "source": [
65 | "It's because Python uses parentheses for something _besides_ tuples: grouping expressions together. Suppose I did this:"
66 | ]
67 | },
68 | {
69 | "cell_type": "code",
70 | "execution_count": null,
71 | "metadata": {},
72 | "outputs": [],
73 | "source": [
74 | "number_of_chocolates_in_my_bowl = 7\n",
75 | "number_of_chocolates_I_ate = 7\n",
76 | "\n",
77 | "print(f\"I have {(number_of_chocolates_in_my_bowl - number_of_chocolates_I_ate)} chocolates saved for later.\")"
78 | ]
79 | },
80 | {
81 | "cell_type": "markdown",
82 | "metadata": {},
83 | "source": [
84 | "We use parentheses to tell Python to _evaluate_ that subtraction expression before applying the result anywhere. What we get from 7 - 7 is 0, so Python then interprets:"
85 | ]
86 | },
87 | {
88 | "cell_type": "code",
89 | "execution_count": null,
90 | "metadata": {},
91 | "outputs": [],
92 | "source": [
93 | "print(f\"I have {(0)} chocolates saved for later.\")"
94 | ]
95 | },
96 | {
97 | "cell_type": "markdown",
98 | "metadata": {},
99 | "source": [
100 | "And the zero there isn't a tuple. It's just a value, inside some parentheses that told the interpreter to evaluate it. The comma is used to differentiate a single-item tuple from a single value that just happens to have parentheses around it."
101 | ]
102 | },
103 | {
104 | "cell_type": "code",
105 | "execution_count": null,
106 | "metadata": {},
107 | "outputs": [],
108 | "source": [
109 | "# A four-item tuple \n",
110 | "tup = (0, 'Ni', 1.2, 3)\n",
111 | "\n",
112 | "# Another four-item tuple (same as prior line) without the need for the parenthesis \n",
113 | "tup2 = 0, 'Ni', 1.2, 3 \n",
114 | "\n",
115 | "print(tup)\n",
116 | "print(tup2)"
117 | ]
118 | },
119 | {
120 | "cell_type": "markdown",
121 | "metadata": {},
122 | "source": [
123 | "*Aside*: It seems that lists and tuples are the same. They both hold a collection of values but they have slightly different syntax. **When should you use one over the other**?\n",
124 | "\n",
125 | "- When you need to _change_ the values in the collection"
126 | ]
127 | },
128 | {
129 | "cell_type": "markdown",
130 | "metadata": {},
131 | "source": [
132 | "**By the way**, when you return multiple items from a method, the thing you get back is a tuple."
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "execution_count": null,
138 | "metadata": {},
139 | "outputs": [],
140 | "source": [
141 | "def two_things():\n",
142 | " return \"one\", \"two\" #<--this is a tuple\n",
143 | "\n",
144 | "one, two = two_things()\n",
145 | "type(two_things())"
146 | ]
147 | },
148 | {
149 | "cell_type": "code",
150 | "execution_count": null,
151 | "metadata": {},
152 | "outputs": [],
153 | "source": [
154 | "one"
155 | ]
156 | },
157 | {
158 | "cell_type": "code",
159 | "execution_count": null,
160 | "metadata": {},
161 | "outputs": [],
162 | "source": [
163 | "two"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": null,
169 | "metadata": {},
170 | "outputs": [],
171 | "source": []
172 | }
173 | ],
174 | "metadata": {
175 | "kernelspec": {
176 | "display_name": "Python 3",
177 | "language": "python",
178 | "name": "python3"
179 | },
180 | "language_info": {
181 | "codemirror_mode": {
182 | "name": "ipython",
183 | "version": 3
184 | },
185 | "file_extension": ".py",
186 | "mimetype": "text/x-python",
187 | "name": "python",
188 | "nbconvert_exporter": "python",
189 | "pygments_lexer": "ipython3",
190 | "version": "3.9.0"
191 | }
192 | },
193 | "nbformat": 4,
194 | "nbformat_minor": 4
195 | }
196 |
--------------------------------------------------------------------------------
/ch7_intro_to_data_engineering/7.2_The_Pandas_Series.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### [Video Explanation Here!](https://youtu.be/yF7diKupK0o)\n",
8 | "\n",
9 | "### Pandas: Series Object\n",
10 | "A Series is a one-dimensional array of indexed data. It wraps:\n",
11 | "\n",
12 | "- A sequence of values (accessible via values attribute).\n",
13 | "- A sequence of indices (accessible via index attribute)."
14 | ]
15 | },
16 | {
17 | "cell_type": "code",
18 | "execution_count": null,
19 | "metadata": {},
20 | "outputs": [],
21 | "source": [
22 | "import pandas as pd\n",
23 | "data = pd.Series(range(10,20))\n",
24 | "print(data)"
25 | ]
26 | },
27 | {
28 | "cell_type": "code",
29 | "execution_count": null,
30 | "metadata": {},
31 | "outputs": [],
32 | "source": [
33 | "print(data.values)\n",
34 | "print(data.index)\n",
35 | "print(data.dtype)"
36 | ]
37 | },
38 | {
39 | "cell_type": "markdown",
40 | "metadata": {},
41 | "source": [
42 | "Data is accessible by offset (index) in square brackets."
43 | ]
44 | },
45 | {
46 | "cell_type": "code",
47 | "execution_count": null,
48 | "metadata": {},
49 | "outputs": [],
50 | "source": [
51 | "print(data[0])\n",
52 | "print(data[2:5])"
53 | ]
54 | },
55 | {
56 | "cell_type": "markdown",
57 | "metadata": {},
58 | "source": [
59 | "A Pandas Series has an explicit index that may consist of values of any type."
60 | ]
61 | },
62 | {
63 | "cell_type": "code",
64 | "execution_count": null,
65 | "metadata": {},
66 | "outputs": [],
67 | "source": [
68 | "data = pd.Series(range(10,20), index=['ten', 'eleven', '12', 13, 14, 15, 16, 17, 18, 19])\n",
69 | "print(data['ten'])\n",
70 | "print(data[19])\n",
71 | "print(data.index)"
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {},
77 | "source": [
78 | "There exists no requirement that an index be sequential."
79 | ]
80 | },
81 | {
82 | "cell_type": "code",
83 | "execution_count": null,
84 | "metadata": {},
85 | "outputs": [],
86 | "source": [
87 | "data = pd.Series(range(10,20), index=[20, 19, 18, 15, 14, 'six', 'eight', 'seven', 9, 10])\n",
88 | "print(data['six'])\n",
89 | "print(data['eight'])\n",
90 | "print(data.index)"
91 | ]
92 | },
93 | {
94 | "cell_type": "markdown",
95 | "metadata": {},
96 | "source": [
97 | "We may also consider a Pandas `Series` a specialized dictionary. Whereas a Python `dict` maps a set of arbitrary keys to a set of arbitrary values, a Series maps a set of typed keys to a set of typed values.\n",
98 | "\n",
99 | "This typing is important: the type of information of a Pandas `Series` makes it more efficient than a Python dictionary for certain operations."
100 | ]
101 | },
102 | {
103 | "cell_type": "code",
104 | "execution_count": null,
105 | "metadata": {},
106 | "outputs": [],
107 | "source": [
108 | "star_trek_captains = {\n",
109 | " 'Jean-luc Picard': 'STNG',\n",
110 | " 'James T. Kirk': 'TOG',\n",
111 | " 'Saru': 'Discovery',\n",
112 | " 'Benjamin Sisko': 'DS9',\n",
113 | " 'Kathryn Janeway': 'Voyager'\n",
114 | "}\n",
115 | "star_trek_captains_series = pd.Series(star_trek_captains)\n",
116 | "print(star_trek_captains_series)\n",
117 | "print(star_trek_captains_series['Kathryn Janeway'])"
118 | ]
119 | },
120 | {
121 | "cell_type": "markdown",
122 | "metadata": {},
123 | "source": [
124 | "The Series supports array-style operations, like slicing:"
125 | ]
126 | },
127 | {
128 | "cell_type": "code",
129 | "execution_count": null,
130 | "metadata": {},
131 | "outputs": [],
132 | "source": [
133 | "star_trek_captains_series['Saru': 'Kathryn Janeway']"
134 | ]
135 | },
136 | {
137 | "cell_type": "markdown",
138 | "metadata": {},
139 | "source": [
140 | "Pandas Series can be created from:\n",
141 | "\n",
142 | "- Lists: index defaults to sequence of integers. \n",
143 | "- Dictionaries: index defaults to sorted keys of the dictionary. \n",
144 | "- Scalars: value repeated to fill given index."
145 | ]
146 | },
147 | {
148 | "cell_type": "code",
149 | "execution_count": null,
150 | "metadata": {},
151 | "outputs": [],
152 | "source": [
153 | "pd.Series(42, index=[1, 2, 3])"
154 | ]
155 | },
156 | {
157 | "cell_type": "markdown",
158 | "metadata": {},
159 | "source": [
160 | "#### Data Indexing and Selection: Series"
161 | ]
162 | },
163 | {
164 | "cell_type": "code",
165 | "execution_count": null,
166 | "metadata": {},
167 | "outputs": [],
168 | "source": [
169 | "# Extend series\n",
170 | "print('===== Extend series =====')\n",
171 | "star_trek_captains['John Archer'] = 'Enterprise'\n",
172 | "print(star_trek_captains)"
173 | ]
174 | }
175 | ],
176 | "metadata": {
177 | "kernelspec": {
178 | "display_name": "Python 3",
179 | "language": "python",
180 | "name": "python3"
181 | },
182 | "language_info": {
183 | "codemirror_mode": {
184 | "name": "ipython",
185 | "version": 3
186 | },
187 | "file_extension": ".py",
188 | "mimetype": "text/x-python",
189 | "name": "python",
190 | "nbconvert_exporter": "python",
191 | "pygments_lexer": "ipython3",
192 | "version": "3.9.0"
193 | }
194 | },
195 | "nbformat": 4,
196 | "nbformat_minor": 4
197 | }
198 |
--------------------------------------------------------------------------------
/data_frame_exercise/3_DataFrame_Usage_Example.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "One important part of building an open source tool for others to use is making sure that they know how to use it. Frequetly this is done with annotated **usage examples**, which show how to use the tool and explain what it's doing.\n",
8 | "\n",
9 | "### Challenge:\n",
10 | "\n",
11 | "Here is some code that could be used as a usage example for our DataFrame. Add comments above each piece of code to explain what it is doing. You might recognize this problem: you solved this problem with `csv` in Chapter 3!"
12 | ]
13 | },
14 | {
15 | "cell_type": "code",
16 | "execution_count": null,
17 | "metadata": {},
18 | "outputs": [],
19 | "source": [
20 | "from phoenixcel.dataframe import Series, GroupBy, DataFrame\n",
21 | "\n",
22 | "df = DataFrame.from_csv('metrics.csv')"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": null,
28 | "metadata": {},
29 | "outputs": [],
30 | "source": [
31 | "df.shape"
32 | ]
33 | },
34 | {
35 | "cell_type": "code",
36 | "execution_count": null,
37 | "metadata": {},
38 | "outputs": [],
39 | "source": [
40 | "df.columns"
41 | ]
42 | },
43 | {
44 | "cell_type": "code",
45 | "execution_count": null,
46 | "metadata": {},
47 | "outputs": [],
48 | "source": [
49 | "df.period_start[:10]"
50 | ]
51 | },
52 | {
53 | "cell_type": "code",
54 | "execution_count": null,
55 | "metadata": {},
56 | "outputs": [],
57 | "source": [
58 | "def last_four(string):\n",
59 | " return string[-4:]\n",
60 | "\n",
61 | "df[\"Year\"] = df.period_start.apply(last_four)\n",
62 | "df.year[:5]"
63 | ]
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": null,
68 | "metadata": {},
69 | "outputs": [],
70 | "source": [
71 | "activity = df.activity\n",
72 | "year = df[\"Year\"]\n",
73 | "\n",
74 | "activity_years = []\n",
75 | "for index, item in enumerate(activity):\n",
76 | " activity_year = f\"{item} ({year[index]})\"\n",
77 | " activity_years.append(activity_year)\n",
78 | "\n",
79 | "df[\"Activity Year\"] = activity_years\n",
80 | "df.activity_year[:5]"
81 | ]
82 | },
83 | {
84 | "cell_type": "code",
85 | "execution_count": null,
86 | "metadata": {},
87 | "outputs": [],
88 | "source": [
89 | "print(type(df.average_days_to_complete_activity))"
90 | ]
91 | },
92 | {
93 | "cell_type": "code",
94 | "execution_count": null,
95 | "metadata": {},
96 | "outputs": [],
97 | "source": [
98 | "df[\"Average Days to Complete Activity\"] = df.average_days_to_complete_activity.apply(float)"
99 | ]
100 | },
101 | {
102 | "cell_type": "code",
103 | "execution_count": null,
104 | "metadata": {},
105 | "outputs": [],
106 | "source": [
107 | "alley_grading_only = df.where(lambda row: row['Activity'] == \"Alley Grading-Unimproved\")"
108 | ]
109 | },
110 | {
111 | "cell_type": "code",
112 | "execution_count": null,
113 | "metadata": {},
114 | "outputs": [],
115 | "source": [
116 | "alley_grading_only.shape"
117 | ]
118 | },
119 | {
120 | "cell_type": "code",
121 | "execution_count": null,
122 | "metadata": {},
123 | "outputs": [],
124 | "source": [
125 | "df.activity.count('Alley Grading-Unimproved')"
126 | ]
127 | },
128 | {
129 | "cell_type": "code",
130 | "execution_count": null,
131 | "metadata": {},
132 | "outputs": [],
133 | "source": [
134 | "grouped_by_activities = df.group_by('Activity Year')\n",
135 | "grouped_by_activities"
136 | ]
137 | },
138 | {
139 | "cell_type": "code",
140 | "execution_count": null,
141 | "metadata": {},
142 | "outputs": [],
143 | "source": [
144 | "averages = grouped_by_activities.average(on=\"Average Days to Complete Activity\")\n",
145 | "averages"
146 | ]
147 | },
148 | {
149 | "cell_type": "code",
150 | "execution_count": null,
151 | "metadata": {},
152 | "outputs": [],
153 | "source": [
154 | "targets = grouped_by_activities.aggregate(on=\"Target Response Days\", using_func=max)\n",
155 | "targets"
156 | ]
157 | },
158 | {
159 | "cell_type": "code",
160 | "execution_count": null,
161 | "metadata": {},
162 | "outputs": [],
163 | "source": [
164 | "grouped_by_activities = sorted(grouped_by_activities)\n",
165 | "grouped_by_activities"
166 | ]
167 | },
168 | {
169 | "cell_type": "code",
170 | "execution_count": null,
171 | "metadata": {},
172 | "outputs": [],
173 | "source": [
174 | "[\n",
175 | " f\"{key}: Target = {targets[key]}, Average = {averages[key]}\"\n",
176 | " for key in grouped_by_activities\n",
177 | "]"
178 | ]
179 | },
180 | {
181 | "cell_type": "code",
182 | "execution_count": null,
183 | "metadata": {},
184 | "outputs": [],
185 | "source": []
186 | }
187 | ],
188 | "metadata": {
189 | "kernelspec": {
190 | "display_name": "Python 3",
191 | "language": "python",
192 | "name": "python3"
193 | },
194 | "language_info": {
195 | "codemirror_mode": {
196 | "name": "ipython",
197 | "version": 3
198 | },
199 | "file_extension": ".py",
200 | "mimetype": "text/x-python",
201 | "name": "python",
202 | "nbconvert_exporter": "python",
203 | "pygments_lexer": "ipython3",
204 | "version": "3.8.5"
205 | }
206 | },
207 | "nbformat": 4,
208 | "nbformat_minor": 4
209 | }
210 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/2.6_Control_Flow.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Video Explanation [Available Here](https://www.youtube.com/watch?v=8MCpuP1zWNU)!\n",
8 | "\n",
9 | "\n",
10 | "### Python is a whitespaced language. \n",
11 | "\n",
12 | "- Java, Ruby, C++, Kotlin, and Swift use braces ``{}`` to designate code blocks.\n",
13 | "- Lisp/Scheme/Rackt family languages us parentheses `()`.\n",
14 | "- Python uses indentation to signify code blocks.\n",
15 | "\n",
16 | "Statements indented to the same distance belong to the same block of code.\n",
17 | "\n",
18 | "Blocks end:\n",
19 | " - When the end of file is detected.\n",
20 | " - When a lesser-indented line is detected.\n",
21 | "\n",
22 | "Deeply nested blocks are further indented to the right."
23 | ]
24 | },
25 | {
26 | "cell_type": "markdown",
27 | "metadata": {},
28 | "source": [
29 | "#### If Statments \n",
30 | "\n",
31 | "The ``if`` statement allows for selecting from alternative actions based on conditional expression results. \n",
32 | "\n",
33 | "Notes: \n",
34 | " - There needs to be a colon (``:``) after the end of the condition (or the ``else`` keyword) to signal the beginning of the clause block \n",
35 | " - Both the ``elif`` and ``else`` statements are optional.\n",
36 | " - Parentheses around the conditional expressions are optional. \n",
37 | " - Lines below the ``if``, ``elif``, or ``else`` must be indented over 4 spaces."
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "execution_count": null,
43 | "metadata": {},
44 | "outputs": [],
45 | "source": [
46 | "bird_weight_in_grams = 131\n",
47 | "\n",
48 | "#Determine the likely subspecies of bird based on weight\n",
49 | "if bird_weight_in_grams < 100:\n",
50 | " print(\"Budgie\")\n",
51 | "elif bird_weight_in_grams < 200: #Else if clause, if the first condition fails then we try the next else if\n",
52 | " print(\"Sun Conure\")\n",
53 | "elif bird_weight_in_grams < 1000:\n",
54 | " print(\"Toucan\")\n",
55 | "else: \n",
56 | " print(\"Maccaw\")"
57 | ]
58 | },
59 | {
60 | "cell_type": "markdown",
61 | "metadata": {},
62 | "source": [
63 | "### For statements \n",
64 | "\n",
65 | "The ``for`` statement is a looping statement that steps through items in any sequence or *iterable object* (more on this later...)"
66 | ]
67 | },
68 | {
69 | "cell_type": "code",
70 | "execution_count": null,
71 | "metadata": {},
72 | "outputs": [],
73 | "source": [
74 | "bird_weights = [55, 121, 650, 1400, 340]\n",
75 | "\n",
76 | "for weight in bird_weights: \n",
77 | " species = ''\n",
78 | " if weight < 100:\n",
79 | " species = \"Budgie\"\n",
80 | " elif weight < 200:\n",
81 | " species = \"Sun Conure\"\n",
82 | " elif weight < 1000:\n",
83 | " species = \"Toucan\"\n",
84 | " else: \n",
85 | " species = \"Maccaw\" \n",
86 | " output = f'This bird weighs {weight} grams and might be a {species}'\n",
87 | " print(output)"
88 | ]
89 | },
90 | {
91 | "cell_type": "code",
92 | "execution_count": null,
93 | "metadata": {},
94 | "outputs": [],
95 | "source": [
96 | "# Useful For loop Idioms \n",
97 | "\n",
98 | "# Iterating over a range of numbers using range \n",
99 | "for num in range(10):\n",
100 | " print(num)"
101 | ]
102 | },
103 | {
104 | "cell_type": "code",
105 | "execution_count": null,
106 | "metadata": {},
107 | "outputs": [],
108 | "source": [
109 | "# Iterating over first 20 integers, taking even numbers \n",
110 | "for even_num in range(2,21,2): # 21 because the stop is exclusive \n",
111 | " print(even_num)"
112 | ]
113 | },
114 | {
115 | "cell_type": "code",
116 | "execution_count": null,
117 | "metadata": {},
118 | "outputs": [],
119 | "source": [
120 | "# Iterating over a collection of items and their indices \n",
121 | "# Call the \"enumerate\" function on the sequence \n",
122 | "bird_weights = [55, 121, 650, 1400, 340]\n",
123 | "\n",
124 | "for index, element in enumerate(bird_weights):\n",
125 | " print(f'Index = {index}, Bird Weight = {element}')"
126 | ]
127 | },
128 | {
129 | "cell_type": "markdown",
130 | "metadata": {},
131 | "source": [
132 | "### While Statement \n",
133 | "\n",
134 | "A ``while`` loop repeatedly executes a block of statements as long as its condition expression evaluates to a ``True`` value."
135 | ]
136 | },
137 | {
138 | "cell_type": "code",
139 | "execution_count": null,
140 | "metadata": {},
141 | "outputs": [],
142 | "source": [
143 | "bird_weights = [55, 121, 650, 1400, 340]\n",
144 | "\n",
145 | "large_bird_spotted = False\n",
146 | "index = 0\n",
147 | "while not large_bird_spotted: \n",
148 | " bird_weight = bird_weights[index]\n",
149 | " index = index + 1\n",
150 | " if bird_weight > 1000:\n",
151 | " large_bird_spotted = True \n",
152 | " break\n",
153 | " else:\n",
154 | " continue \n",
155 | " \n",
156 | "print(f\"This bird weighing {bird_weight} grams is a big honkin' bird!\")"
157 | ]
158 | }
159 | ],
160 | "metadata": {
161 | "kernelspec": {
162 | "display_name": "Python 3",
163 | "language": "python",
164 | "name": "python3"
165 | },
166 | "language_info": {
167 | "codemirror_mode": {
168 | "name": "ipython",
169 | "version": 3
170 | },
171 | "file_extension": ".py",
172 | "mimetype": "text/x-python",
173 | "name": "python",
174 | "nbconvert_exporter": "python",
175 | "pygments_lexer": "ipython3",
176 | "version": "3.9.0"
177 | }
178 | },
179 | "nbformat": 4,
180 | "nbformat_minor": 1
181 | }
182 |
--------------------------------------------------------------------------------
/data_frame_exercise/feature_requests.csv:
--------------------------------------------------------------------------------
1 | Timestamp,Name,How do you use phoenixcel tools? ,What is your feature request?
2 | 2/10/2021 4:15:30,Horatio Crisp,Gold prospecting,"My cousin, Amelia Crisp, is a geostatistician, and will give me CSVs with geocoordinates, estimated values of gold deposits at those coordinates, *and* confidence intervals of how reliable those estimates are. The best sites to prospect are the ones with high estimated gold concentrations and small confidence intervals.
3 |
4 | As a gold prospector, I'd like to be able to order my CSV records by *descending* gold concentration estimation, but by *ascending* confidence interval. So the first record after carrying out this procedure should be the highest estimated gold deposit with the smallest confidence interval."
5 | 2/10/2021 4:22:22,Linda Twist,Pranking my friends,"I'd like it so that every now and again, Phoenixcel would change its string columns so they read ""HELP I AM TRAPPED IN A CSV FACTORY"". "
6 | 2/10/2021 5:43:50,DoomGuy,To help me determine the priority of which I rip and tear,I need it to help me prioritize which demons to go after first and to also prioritize which ones to use my chainsaw on. By knowing which ones I can stagger next it will help keep my strength up.
7 | 2/10/2021 6:36:53,Eric Lafontaine ,Organise budgets for customers ,"I would like to group the type of expenses. Groceries, medical, house loans, transportation, etc.
8 |
9 | This could enable me to give customers an idea of where they spend their money and why."
10 | 2/10/2021 9:01:52,Brock,"I have a collection of rocks and small animals that I keep various measurements on (height, weight, strength, etc) for competitive purposes. ","So, early on, when my battle animals were growing up, I wrote the measurements in kind of a silly way -- The battle animals name, then the name of the stat under a ""stat"" column, and then the value of the stat under a ""value"" column. So each battle animal has multiple rows, each of which is one stat.
11 |
12 | My best friend Ash Ketchup told me it would be a lot better to have one row per battle animal and a column for each stat (and that's great!) but I have a lot of data in the old format. Could you write something that lets me give phoenixcel tools a name column, a stat column, and a value column and have it transform it into one row per name, with columns named after the stats? "
13 | 2/10/2021 11:52:52,Charles Xavier,human resources,"I’m hiring new instructors for my school for gifted youngsters, but the candidates are a bit of a mixed bag. I’ve categorized them based on their morality (good, neutral, or evil) and legality (lawful, neutral, or chaotic). For example, Mr Logan is good/chaotic, Ms Frost is evil/lawful, Mr. Eisenhardt is evil/neutral, Mr. Apocalypse is evil/chaotic, and there are many others. I want to hire anyone who fits these criteria:
14 | (1) Is good but not chaotic
15 | (2) Is neutral but not chaotic
16 | (3) Is evil and lawful
17 | So out of the example candidates, only Ms. Frost would make the cut.
18 |
19 | Could you give me a way to organize a table of candidates? Would also be good if it could handle new values for the attributes morality and legality; as well as completley new attributes.
20 | "
21 | 2/10/2021 12:08:21,Orpheus,"I have written a *lot* of songs. I just cannot stop writing. Ever since I lost the love of my life Eurydice to Hadestown, I've been in a monumental sorrow, and song writing is the only thing I seem to be able to do. I am obsessed. I use phoenixcel tools to track and analyze the songs I have written… there are *so* many.","I have all these songs in phoenixcel, kept in alphabetical order. I also keep track of when I have played them to the townspeople. But after 4000 songs, I cannot remember much about many of the ones that exist at this point. I don't know which ones came first even! I'd love to be able to sort my songs in other ways, like by which one I wrote first, which one I sang most recently, and so on.
22 |
23 | Lalalalalalala
24 |
25 | Orpheus"
26 | 2/10/2021 12:09:02,Scheherazade,"As the greatest character in all of literature, I use phoenixcel to keep track of which of my stories gets allocated to which night I tell it.",I would love to be able to sort my rows of data.
27 | 2/10/2021 12:15:19,La Princesse de Clèves,I use phoenixcel to keep track of which of the honorific titles in King Henry II's court corresponds to which noble (a many-to-one relation). Each person is assigned a canonical name as their primary key.,"It's hard to see the patterns in what my queries return; if I could sort the rows into primary key equivalence classes, it would be easier to see what was happening."
28 | 2/10/2021 15:49:00,KRAMPUS,Planning my work,"I am KRAMPUS, a horned, cloven-hooved counterpart to Santa Claus. Where he rewards good children, I punish the naughty ones. For the regular naughty children, I leave them meagre lumps of coal in their Christmas stockings. For the more naughty ones, I will beat them with a switch of sticks. For the especially naughty children, those most foul, nasty little creatures, I stuff them in a sack and steal them away to Hell.
29 |
30 | Recent budgetary cutbacks have meant having to work with smaller and smaller sacks, so the number of children I can stuff away in the sack has been reduced to a paltry figure.
31 |
32 | Thanks to a data-sharing agreement brokered in the 1990s, I have a full list of Santa Claus's Naughty and Nice list. (They say he checks it twice, but I know for a fact he subcontracts it out to Palantir these days.) Since it has a record for every child in the world, it takes forever to load in Excel, so I've taken to using Phoenixcel for combing through the data.
33 |
34 | I wish to request a feature that will allow me to select the `n` most naughty children for each territory (naughtiness/niceness being an interpolated float value between -1 and 1, and territory being a string column).
35 |
36 | Also I would like to pay special thanks for the implementation of `.min()` in Phoenixcel. This has allowed me to identify the most naughty child in the world. It's more of a symbolic gesture than having any real effect on my workflow, but it really does brighten my day to have this personal face to apply to what would otherwise be rather abstract work."
--------------------------------------------------------------------------------
/move_me/Interpreter_Explained.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Interpreter Explained \n",
8 | "\n",
9 | "*What’s happening within the interpreter?* "
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "### Interpreted vs. Compiled Languages\n",
17 | "\n",
18 | "### OK So first of all\n",
19 | "\n",
20 | "Whether a language is interpreted or compiled is not a characteristic of the _language_. It is a characteristic of the _compiler or interpreter being used to interpret the language_. \n",
21 | "\n",
22 | "Bob Nystrom uses this diagram of a mountain to explain the compilation process in his book, [_Crafting Interpreters_](https://craftinginterpreters.com/))\n",
23 | "\n",
24 | "\n",
25 | "\n",
26 | "We start all the way over on the left, with code written in, say, Python. That code gets scanned, lexed, and parsed, like so:\n",
27 | "\n",
28 | ""
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "When we talk about Python as we know it, we're usually referring specifically to the way that Python syntax looks. That part of the programming language is called the **front end** in compiler design parlance. That's not the step where compilation decisions live. That's just the _interface_ that you use to write the programming language. Several different compilers can execute the same front end code in different ways. These are called **compiler implementations**.\n",
36 | "\n",
37 | "A given front-end can have many different compiler/interpreter implementations. For example, the reference implementation of Ruby (called MRI) is written in C. Meanwhile, JRuby is written in Java and runs on the JVM. You write Ruby the same in either one, though. The \"standard distribution\" of Python uses the CPython intepreter, which...you guessed it!...is written in C.\n",
38 | "\n",
39 | "OK, now, compiled vs. intepreted. There's some debate about this."
40 | ]
41 | },
42 | {
43 | "cell_type": "markdown",
44 | "metadata": {},
45 | "source": [
46 | "### Perspective #1: \n",
47 | "\n",
48 | "**Compiled source code is translated into machine code for the specific machine it's running on, while interpreted source code is translated into bytecode for a virtual machine.**\n",
49 | "\n",
50 | "C and C++ source code is translated into machine (native) code before execution.\n",
51 | " - Machine code runs directly on the CPU. \n",
52 | " - Machine code is specific to the architecture (Intel, Arm, etc.) of that machine.\n",
53 | "\n",
54 | "- Python and Java source code is translated to bytecode for a virtual machine. \n",
55 | " - Unlike compiled languages, bytecode is portable to other architectures. \n",
56 | " - This is one of the reasons for the popularity and universality of Python and Java (there is _another_ big reason, which we're going to talk about later)."
57 | ]
58 | },
59 | {
60 | "cell_type": "markdown",
61 | "metadata": {},
62 | "source": [
63 | " \n",
64 | "### Perspective #2: \n",
65 | "\n",
66 | "**Compiled source code is translated into instructions that the machine, virtual or not, can run. Interpreted source code does this _and then runs it_. So an interpreter can (and usually does) _have_ a compiler.**\n",
67 | "\n",
68 | "So, Python compiles the code (makes sure there are no syntax errors, et cetera), and then it executes the code (at which point you might get runtime errors like a `KeyError` or an `IndexOutOfRangeError`). \n",
69 | "\n",
70 | "I'm not going to weigh in on which of these versions is \"right\" because it doesn't matter in practice. What matters in practice is knowing which of these two schools of thought someone subscribes to, so you know what they are talking about when they talk to you about compilers. \n",
71 | "\n",
72 | "**Here is the trend I have noticed:** Perspective #1 is popular among `RickWhomever123` on StackOverflow. Perspective #2 appears in every book I have read that was written by an actual programming language designer.\n",
73 | " \n",
74 | "Henceforth I will say \"the Python interpreter\" because, under either definition, the standard distribution of Python is an interpreted language."
75 | ]
76 | },
77 | {
78 | "cell_type": "markdown",
79 | "metadata": {},
80 | "source": [
81 | "1. The interpreter compiles source code to byte code.\n",
82 | "\n",
83 | " - Source code: the Python code that is placed in the .py files, also called the **frontend code.**\n",
84 | " - Byte code: lower-level, platform-independent representation of the source code\n",
85 | " - Caches already compiled bytecode to speed up execution by saving it inside byte-codefiles(.pyc) that are stored in the *__pycache__* directory.\n",
86 | " \n",
87 | "2. Next, interpreter routes the byte code to the Python Virtual Machine (PVM).\n",
88 | " - The PVM component is a loop that iterates through the byte code instructions, executing each one."
89 | ]
90 | },
91 | {
92 | "cell_type": "markdown",
93 | "metadata": {},
94 | "source": [
95 | " -- Learning Python 2013"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": null,
101 | "metadata": {},
102 | "outputs": [],
103 | "source": []
104 | }
105 | ],
106 | "metadata": {
107 | "kernelspec": {
108 | "display_name": "Python 3",
109 | "language": "python",
110 | "name": "python3"
111 | },
112 | "language_info": {
113 | "codemirror_mode": {
114 | "name": "ipython",
115 | "version": 3
116 | },
117 | "file_extension": ".py",
118 | "mimetype": "text/x-python",
119 | "name": "python",
120 | "nbconvert_exporter": "python",
121 | "pygments_lexer": "ipython3",
122 | "version": "3.9.0"
123 | }
124 | },
125 | "nbformat": 4,
126 | "nbformat_minor": 2
127 | }
128 |
--------------------------------------------------------------------------------
/ch4_manipulating_functions/4.2_Context_Managers.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### [Video Explanation Here!](https://youtu.be/6yUB8cIW408)\n",
8 | "\n",
9 | "\n",
10 | "> \"Context managers allow you to allocate and release resources precisely when you want to. The most widely used example of context managers is the with statement. Suppose you have two related operations which you’d like to execute as a pair, with a block of code in between. Context managers allow you to do specifically that.\" -- book.pythontips.com \n",
11 | "\n",
12 | "For example the common patterns: \n",
13 | "\n",
14 | "``` \n",
15 | "f = open(...) ## File managment \n",
16 | "...\n",
17 | "f.close()\n",
18 | "\n",
19 | "lock.acquire() ## Multhreaded application \n",
20 | "...\n",
21 | "lock.release()\n",
22 | "\n",
23 | "start = time.time() ## Timing code execution \n",
24 | "...\n",
25 | "end = time.time()\n",
26 | "```"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {},
32 | "source": [
33 | "You can read and close a file with a ``try/except`` block: "
34 | ]
35 | },
36 | {
37 | "cell_type": "code",
38 | "execution_count": null,
39 | "metadata": {},
40 | "outputs": [],
41 | "source": [
42 | "try:\n",
43 | " f = open('../uchicago-emails.txt', 'r')\n",
44 | " for email in f: \n",
45 | " email + 1\n",
46 | "finally:\n",
47 | " f.close()"
48 | ]
49 | },
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {},
53 | "source": [
54 | "But we don't. Instead, you'll more often see this, which closes the file for you when your operation works..."
55 | ]
56 | },
57 | {
58 | "cell_type": "code",
59 | "execution_count": null,
60 | "metadata": {},
61 | "outputs": [],
62 | "source": [
63 | "## More compact and readable \n",
64 | "with open('../uchicago-emails.txt', 'r') as f: \n",
65 | " for email in f: \n",
66 | " print(email)"
67 | ]
68 | },
69 | {
70 | "cell_type": "markdown",
71 | "metadata": {},
72 | "source": [
73 | "...and when it doesn't."
74 | ]
75 | },
76 | {
77 | "cell_type": "code",
78 | "execution_count": null,
79 | "metadata": {},
80 | "outputs": [],
81 | "source": [
82 | "with open('not_a_real_file.txt', 'r') as here:\n",
83 | " for nothing in here:\n",
84 | " print(nothing)"
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {},
90 | "source": [
91 | "It's called a **context manager** because it wraps your code in a box (a context). The box is opened, the code is run, and then the box is shut. Regardless of what happens when the code runs, the box is always shut. That way, if the code in the box explodes, you can shut the box to clean up the mess!\n",
92 | "\n",
93 | "The ``File`` class is a context manager because it implements the **context manager protocol**.\n",
94 | "\n",
95 | "Any class can be a context manger. A class must define two methods: \n",
96 | "\n",
97 | "- ``__enter__(self)`` is executed at the start of a with block. It needs to return the context manager. \n",
98 | "- ``__exit__(self, type, value, traceback)`` is executed at the end of a with block and performs any \"cleanup\" actions. If there is an exception that occurs between the ``__enter__`` and the calling of ``__exit__`` then python calls ``__exit__`` with the information about the exception via these three parameters. This step allows the ``__exit__`` method to decide how to hanlde the exception and if any further steps are required to cleanup. "
99 | ]
100 | },
101 | {
102 | "cell_type": "markdown",
103 | "metadata": {},
104 | "source": [
105 | "Lets make our own context manager class that handles testing the amount of time a piece of code takes to complete.\n"
106 | ]
107 | },
108 | {
109 | "cell_type": "code",
110 | "execution_count": null,
111 | "metadata": {},
112 | "outputs": [],
113 | "source": [
114 | "from timeit import default_timer as timer\n",
115 | "\n",
116 | "class Stopwatch:\n",
117 | " \n",
118 | " def __init__(self):\n",
119 | " self.start_time = 0 \n",
120 | " self.end_time = 0 \n",
121 | " \n",
122 | " def __enter__(self): \n",
123 | " self.start_time = timer() \n",
124 | " return self \n",
125 | " \n",
126 | " def __exit__(self, type, value, traceback):\n",
127 | " self.end_time = timer() \n",
128 | " \n",
129 | " @property #allows the method to run when called but not INVOKED\n",
130 | " def elasped_time(self):\n",
131 | " return self.end_time-self.start_time "
132 | ]
133 | },
134 | {
135 | "cell_type": "code",
136 | "execution_count": null,
137 | "metadata": {},
138 | "outputs": [],
139 | "source": [
140 | "def run_a_buncha_cycles(n): \n",
141 | " if n == 0:\n",
142 | " return\n",
143 | " else:\n",
144 | " run_a_buncha_cycles(n-1)"
145 | ]
146 | },
147 | {
148 | "cell_type": "code",
149 | "execution_count": null,
150 | "metadata": {},
151 | "outputs": [],
152 | "source": [
153 | "with Stopwatch() as s: \n",
154 | " run_a_buncha_cycles(5000)\n",
155 | " \n",
156 | "print(s.elasped_time)"
157 | ]
158 | },
159 | {
160 | "cell_type": "markdown",
161 | "metadata": {},
162 | "source": [
163 | "More information about context managers can be found here: https://docs.python.org/3/library/contextlib.html"
164 | ]
165 | }
166 | ],
167 | "metadata": {
168 | "kernelspec": {
169 | "display_name": "Python 3",
170 | "language": "python",
171 | "name": "python3"
172 | },
173 | "language_info": {
174 | "codemirror_mode": {
175 | "name": "ipython",
176 | "version": 3
177 | },
178 | "file_extension": ".py",
179 | "mimetype": "text/x-python",
180 | "name": "python",
181 | "nbconvert_exporter": "python",
182 | "pygments_lexer": "ipython3",
183 | "version": "3.9.0"
184 | }
185 | },
186 | "nbformat": 4,
187 | "nbformat_minor": 4
188 | }
189 |
--------------------------------------------------------------------------------
/ch9_intro_to_debugging/Homework_Problems.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "For this homework, you do not have to submit answers in separate `.py` or `.md` files. Instead, please put your answers in this notebook. You will also make changes to a `.py` file that I provided for you.\n",
8 | "\n",
9 | "### Problem 1:\n",
10 | "\n",
11 | "[Watch this Video](https://chelseatroy.com/2020/05/05/transcript-debugging-techniques-for-uncertain-times/) called \"Debugging: Techniques for Uncertain Times.\" It's a little hokey (conference talks sometimes have to be), but it talks about debugging strategies.\n",
12 | "\n",
13 | "That link goes to a blog post with the video embedded in it, and the blog post is a transcript of the video so you can follow along with the slides and written text if you like.\n",
14 | "\n",
15 | "**Answer the following questions:**\n",
16 | "\n",
17 | "1. There are two modes of software engineering. Which one is the one that most programming tutorials demonstrate?\n",
18 | "2. How do you switch from progress mode to investigation mode?\n",
19 | "3. What strategy might you use to find a bug in a very very large, single-threaded program?"
20 | ]
21 | },
22 | {
23 | "cell_type": "markdown",
24 | "metadata": {},
25 | "source": [
26 | "# YOUR ANSWERS HERE\n",
27 | "\n",
28 | "1. Most programming tutorials demonstrate...\n",
29 | "\n",
30 | "2. You switch from progress to investigation mode by...\n",
31 | "\n",
32 | "3. I might use the..."
33 | ]
34 | },
35 | {
36 | "cell_type": "markdown",
37 | "metadata": {},
38 | "source": [
39 | "### Problem 2\n",
40 | "\n",
41 | "[Watch this Video](https://youtu.be/h_CAQ5218Mw) about using breakpoints to debug your programs.\n",
42 | "\n",
43 | "Then check out `bird_watching_session.py` in this folder. This is a program that Chicago bird watchers want to use to log their bird observations. Besides the initializer, it has two methods: `record`, which the birders use to record what they see, and `classify`, which attempts to classify the birds. \n",
44 | "\n",
45 | "The Chicago Birdwatching Society has come to you with some complaints about this program. They have noticed three problems.\n",
46 | "\n",
47 | "**Here are the problems:**\n",
48 | "1. session.classifications should return a list of strings describing the different kinds of birds seen during a session. That's not what it returns right now.\n",
49 | "2. session.birds_seen should return the number of birds seen during a session. For some reason it doesn't do that.\n",
50 | "3. Some of the classifications in session.classifications are wrong. The birders don't know why (they're not software engineers) but, for example, a black bird in Clark Park is a raven, not a red-shouldered blackbird.\n",
51 | "\n",
52 | "**Track down the bugs, explain why each bug was happening, and then fix it in `bird_watching_session.py`!**"
53 | ]
54 | },
55 | {
56 | "cell_type": "markdown",
57 | "metadata": {},
58 | "source": [
59 | "# YOUR ANSWERS HERE\n",
60 | "\n",
61 | "1. Bug 1 happened because...\n",
62 | "\n",
63 | "2. Bug 2 happened because...\n",
64 | "\n",
65 | "3. Bug 3 happened because..."
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "metadata": {},
71 | "source": [
72 | "These tests might help you out in your search :)"
73 | ]
74 | },
75 | {
76 | "cell_type": "code",
77 | "execution_count": null,
78 | "metadata": {},
79 | "outputs": [],
80 | "source": [
81 | "# Don't worry about understanding these two lines.\n",
82 | "# They are commands we use to get this notebook to autoreload\n",
83 | "# so you don't have to rerun your kernel every time you change your homework files.\n",
84 | "%load_ext autoreload\n",
85 | "%autoreload 2\n",
86 | "\n",
87 | "import sys\n",
88 | "!{sys.executable} -m pip install colorama \n",
89 | "\n",
90 | "sys.path.insert(0, '..')\n",
91 | "from test_framework_exercise.phoenix_test.matchers import FailedAssertion, Assertion, assert_that\n",
92 | "from test_framework_exercise.phoenix_test.test import Test\n",
93 | "sys.path.remove('..')\n",
94 | "\n",
95 | "from bird_watching_session import BirdWatchingSession, Observation"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": null,
101 | "metadata": {},
102 | "outputs": [],
103 | "source": [
104 | "class BirdWatcherSessionTest(Test):\n",
105 | " def setup(self):\n",
106 | " self.session = BirdWatchingSession()\n",
107 | " self.session.record(Observation('black', 'Solidarity Drive'))\n",
108 | " self.session.record(Observation('black', 'Clark Park'))\n",
109 | " self.session.record(Observation('grey', 'Solidarity Drive'))\n",
110 | " self.session.record(Observation('red', 'Solidarity Drive'))\n",
111 | " self.session.record(Observation('brown', 'Starved Rock State Park'))\n",
112 | " self.session.record(Observation('grey', 'Chicago River'))\n",
113 | "\n",
114 | " def test_classifications_data_type(self):\n",
115 | " types = [type(item) for item in self.session.classifications]\n",
116 | " assert_that(set(types)).has_size(1)\n",
117 | " assert_that(types[0]).equals(str)\n",
118 | " \n",
119 | " def test_observation_count(self):\n",
120 | " assert_that(self.session.birds_seen).equals(6)\n",
121 | " \n",
122 | " def test_classification_method(self):\n",
123 | " assert_that(self.session.classify('black', 'Solidarity Drive')).equals(\"Red-Shouldered Blackbird\")\n",
124 | " assert_that(self.session.classify('black', 'Clark Park')).equals(\"Raven\")\n",
125 | " assert_that(self.session.classify('grey', 'Solidarity Drive')).equals(\"Seagull\")\n",
126 | " assert_that(self.session.classify('red', 'Solidarity Drive')).equals(\"Serrano (Field Museum's Scarlet Maccaw)\")\n",
127 | " assert_that(self.session.classify('brown', 'Starved Rock State Park')).equals(\"juvenile Bald Eagle\")\n",
128 | " assert_that(self.session.classify('grey', 'Chicago River')).equals(\"Eastern Heron\")\n",
129 | " \n",
130 | "BirdWatcherSessionTest().run()"
131 | ]
132 | },
133 | {
134 | "cell_type": "code",
135 | "execution_count": null,
136 | "metadata": {},
137 | "outputs": [],
138 | "source": []
139 | }
140 | ],
141 | "metadata": {
142 | "kernelspec": {
143 | "display_name": "Python 3",
144 | "language": "python",
145 | "name": "python3"
146 | },
147 | "language_info": {
148 | "codemirror_mode": {
149 | "name": "ipython",
150 | "version": 3
151 | },
152 | "file_extension": ".py",
153 | "mimetype": "text/x-python",
154 | "name": "python",
155 | "nbconvert_exporter": "python",
156 | "pygments_lexer": "ipython3",
157 | "version": "3.9.0"
158 | }
159 | },
160 | "nbformat": 4,
161 | "nbformat_minor": 4
162 | }
163 |
--------------------------------------------------------------------------------
/data_frame_exercise/5_Extending_Dataframe.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### You are now a published open source developer who has learned lots of things.\n",
8 | "\n",
9 | "- You have learned about the value of having automated tests for code\n",
10 | "- You have studied and contributed to an automated testing framework similar to pytest.\n",
11 | "- You have extended, analyzed, and evaluated the code of a data analysis tool similar to pandas\n",
12 | "\n",
13 | "So your bosses at Phoenix Software, Inc have decided to promote you from phoenixlets to full-fledged phoenixes (phoenices?) \n",
14 | "\n",
15 | "Phoenices are qualified to handle all the steps of the software development process, from planning to testing to execution. "
16 | ]
17 | },
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {},
21 | "source": [
22 | "## Step 1: Feedback Review and Ideation\n",
23 | "\n",
24 | "[Here is a collection](https://docs.google.com/spreadsheets/d/1QE6HOAgfznxp7NE1qEjfQVwz633VuspgNEjKPjq4UAA/edit?usp=sharing) of feature request feedback from the programmers using the curent version of your phoenixcel library. "
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {},
30 | "source": [
31 | "**Based on this feature request feedback,** you decide to implement sorting on a column in a Phoenixcell dataframe. That is, much like an Excel spreadsheet, you can choose a specific column, and then put all the rows in order based on a sorting of that column.\n",
32 | " \n"
33 | ]
34 | },
35 | {
36 | "cell_type": "markdown",
37 | "metadata": {},
38 | "source": [
39 | "## Step 2: The Spec\n",
40 | "\n",
41 | "You have seen from your homework how important and valuable it is to have automated tests. Automated testing is how we make sure that our code in `phoenixcel` does what we expect it to do, and will work for all of our clients! So today, we are going to try out **test-driven development** and write a test for our highest priority feature. \n",
42 | "\n",
43 | "As you write this test provides a good opportunity to talk amogst your group:\n",
44 | "\n",
45 | "- How should clients use the feature?\n",
46 | "- What should it be called?\n",
47 | "- What data does it need to take in?\n",
48 | "- Should it return anything?\n",
49 | "- Should it modify anything?\n",
50 | "- Should it be _fluent_ (fit into the existing fluent interface of the DataFrame)? \n",
51 | "\n",
52 | "Luckily, you have already written a lovely testing framework, which we can import right here to help us write the test:"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "execution_count": null,
58 | "metadata": {},
59 | "outputs": [],
60 | "source": [
61 | "import csv \n",
62 | "from phoenixcel.dataframe import Series, GroupBy, DataFrame"
63 | ]
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": null,
68 | "metadata": {},
69 | "outputs": [],
70 | "source": [
71 | "import sys\n",
72 | "!{sys.executable} -m pip install colorama \n",
73 | "\n",
74 | "sys.path.insert(0, '..')\n",
75 | "from test_framework_exercise.phoenix_test.matchers import FailedAssertion, Assertion, assert_that\n",
76 | "from test_framework_exercise.phoenix_test.test import Test\n",
77 | "sys.path.remove('..')"
78 | ]
79 | },
80 | {
81 | "cell_type": "code",
82 | "execution_count": null,
83 | "metadata": {},
84 | "outputs": [],
85 | "source": [
86 | "## Write your test(s) here. You don't have to use this EXACT test.\n",
87 | "## It's just here to provide you with syntax examples.\n",
88 | "\n",
89 | "class PhoenixCellFeatureTest(Test): #you might wanna change this name\n",
90 | " def test_something(self):\n",
91 | " df = DataFrame.from_dictionary({\n",
92 | " 'number_column' : [1, 5, 2, 4, 3],\n",
93 | " 'letter_column' : ['A', 'B', 'B', 'C', 'C']\n",
94 | " })\n",
95 | " \n",
96 | " # SOMETHING HAPPENS HERE\n",
97 | " \n",
98 | " assert_that(df['number_column']).equals([1, 2, 3, 4, 5])\n",
99 | " assert_that(df['letter_column'][1]).equals('B')\n",
100 | "\n",
101 | "PhoenixCellFeatureTest().run()"
102 | ]
103 | },
104 | {
105 | "cell_type": "markdown",
106 | "metadata": {},
107 | "source": [
108 | "## Step 3: Implementation\n",
109 | "\n",
110 | "Okay, so, your test fails because your implementation doesn't do anything yet. It's time to make it pass! Implement your feature by extending the characteristics of `DataFrame`. You can do that right here in the notebook if you want to by importing those classes and then inheriting from them, like this:"
111 | ]
112 | },
113 | {
114 | "cell_type": "code",
115 | "execution_count": null,
116 | "metadata": {},
117 | "outputs": [],
118 | "source": [
119 | "class DataFrame(DataFrame):\n",
120 | " pass\n"
121 | ]
122 | },
123 | {
124 | "cell_type": "markdown",
125 | "metadata": {},
126 | "source": [
127 | "## Step 4: Documentation\n",
128 | "\n",
129 | "Make sure your clients know how to use your feature! You can do this with two especially valuable kinds of documentation:\n",
130 | "\n",
131 | "1. A docstring: the comment inside the function that describes what the function does and lists its inputs, outputs, and what it modifies\n",
132 | "2. A usage example: Write some example code that uses your new feature, with comments explaining what's going on."
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "execution_count": null,
138 | "metadata": {},
139 | "outputs": [],
140 | "source": []
141 | },
142 | {
143 | "cell_type": "markdown",
144 | "metadata": {},
145 | "source": [
146 | "## Step 5: BONUS FEATURES!\n",
147 | "\n",
148 | "If you get all of the above implemented, try out these additional challenges!\n",
149 | "\n",
150 | "1. Add an option to your sorting function to sort the chosen column in ascending or descending order.\n",
151 | "2. Add an option to your sorting function to either sort the dataframe in place, or return a new one.\n",
152 | "3. Allow your sorting function to take in TWO columns. i.e., if the values of the FIRST sort column are equal, then sort by the SECOND sort column. Remember to write a test together first to get clarity on how this should work!\n",
153 | "4. Generalize your solution for #3 to work for an _arbitrary number of columns_!"
154 | ]
155 | },
156 | {
157 | "cell_type": "code",
158 | "execution_count": null,
159 | "metadata": {},
160 | "outputs": [],
161 | "source": []
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.9.0"
181 | }
182 | },
183 | "nbformat": 4,
184 | "nbformat_minor": 4
185 | }
186 |
--------------------------------------------------------------------------------
/ch6_how_functions_and_objects_work_together/6.1_Functions_as_First_Class_Objects.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### [Video Explanation Here!](https://youtu.be/vWi8luPDkFg)\n",
8 | "\n",
9 | "In Python, functions are objects, which means we can: \n",
10 | " - Store functions in variables \n",
11 | " - Pass functions as parameter to another function \n",
12 | " - Return functions within other functions \n",
13 | " - Store functions within other data structures (i.e, lists, dictionaries, sets, etc.) \n",
14 | " \n",
15 | "The ``def`` statement is an executable statement that binds a name to the function object: "
16 | ]
17 | },
18 | {
19 | "cell_type": "code",
20 | "execution_count": null,
21 | "metadata": {},
22 | "outputs": [],
23 | "source": [
24 | "def echo(message):\n",
25 | " print(message)\n",
26 | "\n",
27 | "def echo(message):\n",
28 | " print(f'{message} ... {message}')\n",
29 | " \n",
30 | "print(f'echo = {echo}')\n",
31 | "print(f'type of echo = {type(echo)}')"
32 | ]
33 | },
34 | {
35 | "cell_type": "code",
36 | "execution_count": null,
37 | "metadata": {},
38 | "outputs": [],
39 | "source": [
40 | "class Smingity:\n",
41 | " def what():\n",
42 | " pass\n",
43 | "\n",
44 | "Smingity.__dict__ #THIS IS NAUGTY DO NOT DO THIS, I'M JUST SHOWING YOU "
45 | ]
46 | },
47 | {
48 | "cell_type": "code",
49 | "execution_count": null,
50 | "metadata": {},
51 | "outputs": [],
52 | "source": [
53 | "# Since \"echo\" is just a variable. we can have multiple variables\n",
54 | "# reference the same object it points to. \n",
55 | "\n",
56 | "import sys\n",
57 | "print(sys.getrefcount(echo))\n",
58 | "\n",
59 | "x = echo \n",
60 | "y = echo \n",
61 | "\n",
62 | "print(sys.getrefcount(echo))"
63 | ]
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": null,
68 | "metadata": {},
69 | "outputs": [],
70 | "source": [
71 | "# Since \"y\", \"x\" and \"echo\" reference a function object, we can call \n",
72 | "# the function objects normally by using the variable names followed\n",
73 | "# by any required position arguments. \n",
74 | "x(\"Hello\")\n",
75 | "y(\"World\")"
76 | ]
77 | },
78 | {
79 | "cell_type": "code",
80 | "execution_count": null,
81 | "metadata": {},
82 | "outputs": [],
83 | "source": [
84 | "del x\n",
85 | "del y\n",
86 | "\n",
87 | "print(sys.getrefcount(echo))\n",
88 | "\n",
89 | "echo(\"Goodbye\")"
90 | ]
91 | },
92 | {
93 | "cell_type": "code",
94 | "execution_count": null,
95 | "metadata": {},
96 | "outputs": [],
97 | "source": [
98 | "#We can pass functions to other functions \n",
99 | "def echo(message):\n",
100 | " print(message)\n",
101 | " \n",
102 | "def indirect(func, arg):\n",
103 | " func(arg)\n",
104 | " \n",
105 | "indirect(echo, 'Argument call!')"
106 | ]
107 | },
108 | {
109 | "cell_type": "code",
110 | "execution_count": null,
111 | "metadata": {},
112 | "outputs": [],
113 | "source": [
114 | "# We can return functions within other functions \n",
115 | "def add(a, b):\n",
116 | " return a + b\n",
117 | "\n",
118 | "def get_add_func():\n",
119 | " return add \n",
120 | "\n",
121 | "adder = get_add_func()\n",
122 | "print(adder(\"hello \",\"world\"))"
123 | ]
124 | },
125 | {
126 | "cell_type": "markdown",
127 | "metadata": {},
128 | "source": [
129 | "### Anonymous (lambda) Functions \n",
130 | "\n",
131 | "Python also provides another way to generate function objects, via *anonymous functions* (aka lambda functions), which: \n",
132 | "\n",
133 | "- Are expressions (not statements) that return a function object that can be called later without providing a name (hence \"anonymous\") \n",
134 | "- Can be used in places where ``def`` statement is not syntactically legal (inside a literal list, inlined as a function argument, etc.) \n",
135 | "\n",
136 | "The body of a lambda function is a single expression, not a block of statements. \n",
137 | " - The body is similar to a return statement in a def statement \n",
138 | "Syntax: ``lambda arg1,arg2,arg3,...,argN: expression``\n",
139 | " "
140 | ]
141 | },
142 | {
143 | "cell_type": "code",
144 | "execution_count": null,
145 | "metadata": {},
146 | "outputs": [],
147 | "source": [
148 | "(lambda arg1, arg2: arg1 + arg2)(2,3)"
149 | ]
150 | },
151 | {
152 | "cell_type": "code",
153 | "execution_count": null,
154 | "metadata": {},
155 | "outputs": [],
156 | "source": [
157 | "lam = lambda x, y: x * y\n",
158 | "print(lam)"
159 | ]
160 | },
161 | {
162 | "cell_type": "code",
163 | "execution_count": null,
164 | "metadata": {},
165 | "outputs": [],
166 | "source": [
167 | "print(lam(2,3)) "
168 | ]
169 | },
170 | {
171 | "cell_type": "code",
172 | "execution_count": null,
173 | "metadata": {},
174 | "outputs": [],
175 | "source": [
176 | "# Notice this just returns the function object. It does not execute\n",
177 | "# the object. \n",
178 | "lambda a,b,c: a + b + c"
179 | ]
180 | },
181 | {
182 | "cell_type": "markdown",
183 | "metadata": {},
184 | "source": [
185 | "#### Why use lambda functions? \n",
186 | "\n",
187 | ">\"Lambda comes in handy as a sort of function shorthand that allows you to embed a function’s definition within the code that uses it\" Learning Python, 2013 \n",
188 | "\n",
189 | "- One use (of many) for lambdas is for *jump tables*, which are lists or dictionaries of actions to be performed on demand"
190 | ]
191 | },
192 | {
193 | "cell_type": "code",
194 | "execution_count": null,
195 | "metadata": {},
196 | "outputs": [],
197 | "source": [
198 | "powers = [\n",
199 | " lambda x: x ** 0, \n",
200 | " lambda x: x ** 1, \n",
201 | " lambda x: x ** 2, \n",
202 | " lambda x: x ** 3, \n",
203 | " lambda x: x ** 4\n",
204 | "] "
205 | ]
206 | },
207 | {
208 | "cell_type": "code",
209 | "execution_count": null,
210 | "metadata": {},
211 | "outputs": [],
212 | "source": [
213 | "for power in powers: print(power(2)) "
214 | ]
215 | },
216 | {
217 | "cell_type": "code",
218 | "execution_count": null,
219 | "metadata": {},
220 | "outputs": [],
221 | "source": [
222 | "print(powers[0](3)) "
223 | ]
224 | },
225 | {
226 | "cell_type": "code",
227 | "execution_count": null,
228 | "metadata": {},
229 | "outputs": [],
230 | "source": []
231 | }
232 | ],
233 | "metadata": {
234 | "kernelspec": {
235 | "display_name": "Python 3",
236 | "language": "python",
237 | "name": "python3"
238 | },
239 | "language_info": {
240 | "codemirror_mode": {
241 | "name": "ipython",
242 | "version": 3
243 | },
244 | "file_extension": ".py",
245 | "mimetype": "text/x-python",
246 | "name": "python",
247 | "nbconvert_exporter": "python",
248 | "pygments_lexer": "ipython3",
249 | "version": "3.8.5"
250 | }
251 | },
252 | "nbformat": 4,
253 | "nbformat_minor": 4
254 | }
255 |
--------------------------------------------------------------------------------
/ch2_syntactic_basics/2.2_Strings.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Video Explanation [Available Here](https://www.youtube.com/watch?v=4XpKfehAHrw)!\n",
8 | "\n",
9 | "#### Strings \n",
10 | "\n",
11 | "Strings (i.e., ``str`` type in Python) are used to record both textual information and arbitrary collections of bytes."
12 | ]
13 | },
14 | {
15 | "cell_type": "code",
16 | "execution_count": null,
17 | "metadata": {},
18 | "outputs": [],
19 | "source": [
20 | "birdie_says = \"Polly wanna cracker!\"\n",
21 | "birdie_says"
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "metadata": {},
27 | "source": [
28 | " - Strings are *immutable sequences*: positionally ordered collections of other objects that cannot be modified.\n",
29 | "\n",
30 | " - String transformation operations/functions always produce new ``str`` values."
31 | ]
32 | },
33 | {
34 | "cell_type": "code",
35 | "execution_count": null,
36 | "metadata": {},
37 | "outputs": [],
38 | "source": [
39 | "hi = \"Hi\"\n",
40 | "first_id = id(hi)\n",
41 | "first_id"
42 | ]
43 | },
44 | {
45 | "cell_type": "code",
46 | "execution_count": null,
47 | "metadata": {},
48 | "outputs": [],
49 | "source": [
50 | "hi = hi.capitalize()\n",
51 | "modified_id = id(hi)\n",
52 | "modified_id"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "execution_count": null,
58 | "metadata": {},
59 | "outputs": [],
60 | "source": [
61 | "first_id == modified_id"
62 | ]
63 | },
64 | {
65 | "cell_type": "markdown",
66 | "metadata": {},
67 | "source": [
68 | " ### Ways to define a ``str`` in Python:"
69 | ]
70 | },
71 | {
72 | "cell_type": "code",
73 | "execution_count": null,
74 | "metadata": {},
75 | "outputs": [],
76 | "source": [
77 | "# Single quote literal\n",
78 | "# Allows you to embed double quotes (\") inside the string \n",
79 | "str1 = 'spa\"m'\n",
80 | "print(str1)\n",
81 | "type(str1)"
82 | ]
83 | },
84 | {
85 | "cell_type": "code",
86 | "execution_count": null,
87 | "metadata": {},
88 | "outputs": [],
89 | "source": [
90 | "# Double quote literal\n",
91 | "# Allows you to embed double quotes (') inside the string \n",
92 | "str2 = \"sp\\\"a'm\"\n",
93 | "print(str2)"
94 | ]
95 | },
96 | {
97 | "cell_type": "code",
98 | "execution_count": null,
99 | "metadata": {},
100 | "outputs": [],
101 | "source": [
102 | "# Triple quote literal (multi-line strings)\n",
103 | "# Multi-line strings include the newlines \n",
104 | "str3 = '''Here is a list of names all on different lines \n",
105 | "\"\"Bob\"\n",
106 | "\"Sally\" \n",
107 | "\"Joe\" \n",
108 | "\"Karen\"'''\n",
109 | "print(str3) # Notice the newlines are preserved"
110 | ]
111 | },
112 | {
113 | "cell_type": "code",
114 | "execution_count": null,
115 | "metadata": {},
116 | "outputs": [],
117 | "source": [
118 | "# Double quote version (multi-line strings) \n",
119 | "# Allows for escaping single quotes ''\n",
120 | "str3 = \"\"\"Here is a list of names all on different lines \n",
121 | "'Bob'\n",
122 | "'Sally' \n",
123 | "'Joe'\n",
124 | "'Karen'\"\"\"\n",
125 | "print(str3)"
126 | ]
127 | },
128 | {
129 | "cell_type": "code",
130 | "execution_count": null,
131 | "metadata": {},
132 | "outputs": [],
133 | "source": [
134 | "# As with other languages, you can have escape characters in strings \n",
135 | "# \\t - tab character \n",
136 | "# \\n - newline character\n",
137 | "# Many others: https://www.w3schools.com/python/gloss_python_escape_characters.asp\n",
138 | "str5 = \"Bob\\tSally\\nJoe\"\n",
139 | "print(str5)\n",
140 | "str6 = 'Bob\\tSally\\nJoe'"
141 | ]
142 | },
143 | {
144 | "cell_type": "code",
145 | "execution_count": null,
146 | "metadata": {},
147 | "outputs": [],
148 | "source": [
149 | "#Below is an example of \"raw strings\", which include escape characters \n",
150 | "# a raw string always begins with a \"r\" before the string syntax \n",
151 | "str7 = r'C:\\new\\test.py' \n",
152 | "non_raw_str7 = 'C:\\new\\test.py'\n",
153 | "\n",
154 | "#Notice the strings actually contain the \\n and \\t in the ouput versus \n",
155 | "# the non-raw versions \n",
156 | "print(str7) \n",
157 | "print(\"----\")\n",
158 | "print(non_raw_str7)"
159 | ]
160 | },
161 | {
162 | "cell_type": "markdown",
163 | "metadata": {},
164 | "source": [
165 | "### String Formatting \n",
166 | "\n",
167 | "Formattting allows you to incorporate values from other types to produce a new string. "
168 | ]
169 | },
170 | {
171 | "cell_type": "code",
172 | "execution_count": null,
173 | "metadata": {},
174 | "outputs": [],
175 | "source": [
176 | "# By relative position '{}' using the \"format\" method. \n",
177 | "# Auto-conversion for non-strings. \n",
178 | "f_str = 'Address = {} {} {}'.format(4543, 'Bird Sanctuary', 'Road')\n",
179 | "print(f_str)"
180 | ]
181 | },
182 | {
183 | "cell_type": "code",
184 | "execution_count": null,
185 | "metadata": {},
186 | "outputs": [],
187 | "source": [
188 | "# By absolute position '{index}', where index is an integer \n",
189 | "f_str2 = 'Hello {2} {0} and Bye {1}'.format('birdies','Felicia','gorgeous')\n",
190 | "print(f_str2)"
191 | ]
192 | },
193 | {
194 | "cell_type": "code",
195 | "execution_count": null,
196 | "metadata": {},
197 | "outputs": [],
198 | "source": [
199 | "# By keyword. Specify keyword first followed by the value.\n",
200 | "\n",
201 | "#Here, I used a slash to split this expression into two lines in a notebook cell\n",
202 | "f_str3 = '{number} {action} for a bird, one giant leap for {beneficiaries}!'\\\n",
203 | " .format(number = 1, action = 'small flap', beneficiaries = 'bird kind')\n",
204 | "print(f_str3)"
205 | ]
206 | },
207 | {
208 | "cell_type": "code",
209 | "execution_count": null,
210 | "metadata": {},
211 | "outputs": [],
212 | "source": [
213 | "# New in Python 3.6+: formatted string literals. \n",
214 | "# IMPORTANT - Note the 'f'. This 'f' is required!\n",
215 | "\n",
216 | "#Define a few variables \n",
217 | "num = 4543 \n",
218 | "name = 'Bird Sanctuary'\n",
219 | "suffix = 'Road' \n",
220 | "\n",
221 | "# Directly place your expressions inside the curly braces\n",
222 | "f_str4 = f'Address = {num} {name} {suffix}'\n",
223 | "print(f_str4)"
224 | ]
225 | },
226 | {
227 | "cell_type": "markdown",
228 | "metadata": {},
229 | "source": [
230 | "The string formatting method includes additional options for formatting:\n",
231 | " \n",
232 | " - Precision: number of decimals for float objects \n",
233 | " - Hex, binary, or octal representation for ints\n",
234 | " - Justification options and whitespace padding\n",
235 | " \n",
236 | "Documentation:\n",
237 | " - Zetcode \"Python f-string Tutorial: http://zetcode.com/python/fstring/"
238 | ]
239 | },
240 | {
241 | "cell_type": "code",
242 | "execution_count": null,
243 | "metadata": {},
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.9.0"
265 | }
266 | },
267 | "nbformat": 4,
268 | "nbformat_minor": 4
269 | }
270 |
--------------------------------------------------------------------------------
/ch4_manipulating_functions/4.5_List_Comprehensions_and_Generator_Expressions.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### [Video Explanation Here!](https://youtu.be/7D35-K8pPxI)\n",
8 | "\n",
9 | "## List Comprehensions\n",
10 | "\n",
11 | "**List comprehension** is a way to build a new list by running an expression on each item in an iterable object. \n",
12 | " - Comprehensions can also create dictionaries and sets\n",
13 | "\n",
14 | "**Syntax**:``[expression for target in iterable]``"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": null,
20 | "metadata": {},
21 | "outputs": [],
22 | "source": [
23 | "listo = []\n",
24 | "for x in [1, 2, 3]:\n",
25 | " listo.append(x * 2)\n",
26 | "\n",
27 | "listo"
28 | ]
29 | },
30 | {
31 | "cell_type": "code",
32 | "execution_count": null,
33 | "metadata": {},
34 | "outputs": [],
35 | "source": [
36 | "# x is assigned to each element in the iterable object\n",
37 | "new_list = [x * 2 for x in [1,2,3]]\n",
38 | "new_list"
39 | ]
40 | },
41 | {
42 | "cell_type": "code",
43 | "execution_count": null,
44 | "metadata": {},
45 | "outputs": [],
46 | "source": [
47 | "new_list = [pow(x,2) for x in range(3)]\n",
48 | "new_list"
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {},
54 | "source": [
55 | "#### For-loop vs. Map vs. Comprehension \n",
56 | "\n",
57 | "The following examples produce the same collection of values: ``[1,2,4]`` \n",
58 | " - Each example uses the same iterable object \n",
59 | " - ``map`` applies a ``function`` to each item and returns an ``iterator``.\n",
60 | " - Comprehension applies an expression and generates a new list. "
61 | ]
62 | },
63 | {
64 | "cell_type": "code",
65 | "execution_count": null,
66 | "metadata": {},
67 | "outputs": [],
68 | "source": [
69 | "# 1. Using for loop and list append \n",
70 | "listo = []\n",
71 | "for x in range(3):\n",
72 | " listo.append(2 ** x)\n",
73 | " \n",
74 | "listo"
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "execution_count": null,
80 | "metadata": {},
81 | "outputs": [],
82 | "source": [
83 | "# 2. Map produces an iterator not a list \n",
84 | "iterator = map(lambda x: 2**x, range(3))\n",
85 | "list(iterator)"
86 | ]
87 | },
88 | {
89 | "cell_type": "code",
90 | "execution_count": null,
91 | "metadata": {},
92 | "outputs": [],
93 | "source": [
94 | "# 3. Comprehension produces a new list not an iterator \n",
95 | "listo = [2 ** x for x in range(3)] \n",
96 | "listo"
97 | ]
98 | },
99 | {
100 | "cell_type": "markdown",
101 | "metadata": {},
102 | "source": [
103 | "#### Nested & Conditional Comprehensions \n",
104 | "Comprehensions can be deeply nested\n",
105 | " - The first for-loop is the outermost. \n",
106 | " - Subsequent for-loops are nested inwards. "
107 | ]
108 | },
109 | {
110 | "cell_type": "code",
111 | "execution_count": null,
112 | "metadata": {},
113 | "outputs": [],
114 | "source": [
115 | "listo = [ (x, y) for x in ('a','b') for y in (5,17)]\n",
116 | "listo"
117 | ]
118 | },
119 | {
120 | "cell_type": "code",
121 | "execution_count": null,
122 | "metadata": {},
123 | "outputs": [],
124 | "source": [
125 | "#Comprehensions can use conditionals to filter out \n",
126 | "# items within an iterable: \n",
127 | "listo = [ x for x in (3,4,20,50) if x > 10]\n",
128 | "listo"
129 | ]
130 | },
131 | {
132 | "cell_type": "markdown",
133 | "metadata": {},
134 | "source": [
135 | "#### Set & Dictionary Comprehension \n",
136 | "- Set comprehension uses the following syntax to generate the set: \n",
137 | " **Syntax**:``{f(x) for x in iterable if cond}`` \n",
138 | " "
139 | ]
140 | },
141 | {
142 | "cell_type": "code",
143 | "execution_count": null,
144 | "metadata": {},
145 | "outputs": [],
146 | "source": [
147 | "{x for x in [2,3,3,5] if x < 4}"
148 | ]
149 | },
150 | {
151 | "cell_type": "markdown",
152 | "metadata": {},
153 | "source": [
154 | "Dictionary comprehensions uses same literal dictionary syntax but requires the iterable object to be an iterable containing key-value pairs ``(key,value)``\n",
155 | " - **Syntax**: ``{f(k): g(v) for (k,v) in iterbl if cond}``\n",
156 | " "
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "execution_count": null,
162 | "metadata": {},
163 | "outputs": [],
164 | "source": [
165 | "#zip creates a iterable object of key-value pairs as tuples \n",
166 | "iterable = zip(['A','B','B'],[1,2,3])\n",
167 | "iterable"
168 | ]
169 | },
170 | {
171 | "cell_type": "code",
172 | "execution_count": null,
173 | "metadata": {},
174 | "outputs": [],
175 | "source": [
176 | "{key:value for (key,value) in iterable if key.isupper()}"
177 | ]
178 | },
179 | {
180 | "cell_type": "markdown",
181 | "metadata": {},
182 | "source": [
183 | "#### Generator Expressions \n",
184 | "\n",
185 | "A *generator expressions* are similar to list comprehensions but instead return a generator object that produces results one at time instead of building a list in its entirety. \n",
186 | "\n",
187 | "**Syntax**: ``(expression for x in iterable)`` -> Note the ``(...)``"
188 | ]
189 | },
190 | {
191 | "cell_type": "code",
192 | "execution_count": null,
193 | "metadata": {},
194 | "outputs": [],
195 | "source": [
196 | "incr_gen = (i + 1 for i in [1,2,3,4])"
197 | ]
198 | },
199 | {
200 | "cell_type": "code",
201 | "execution_count": null,
202 | "metadata": {},
203 | "outputs": [],
204 | "source": [
205 | "for num in incr_gen:\n",
206 | " print(num) # prints 2 3 4 5"
207 | ]
208 | },
209 | {
210 | "cell_type": "markdown",
211 | "metadata": {},
212 | "source": [
213 | "You can also provide conditionals to the generators: "
214 | ]
215 | },
216 | {
217 | "cell_type": "code",
218 | "execution_count": null,
219 | "metadata": {},
220 | "outputs": [],
221 | "source": [
222 | "incr_gen = (i + 1 for i in [1,2,3,4] if i >= 2)"
223 | ]
224 | },
225 | {
226 | "cell_type": "code",
227 | "execution_count": null,
228 | "metadata": {},
229 | "outputs": [],
230 | "source": [
231 | "for num in incr_gen:\n",
232 | " print(num) # prints 3 4 5"
233 | ]
234 | },
235 | {
236 | "cell_type": "markdown",
237 | "metadata": {},
238 | "source": [
239 | "#### Generator Expressions vs Comprehensions\n",
240 | "\n",
241 | "**What's the difference between generator expressions and comprehensions?** \n",
242 | " - The main difference is that generator expression produce results on demand, whereas comprehensions produce the results all at once.\n",
243 | " - Take into consideration the program performance in regards to time/memory space when consuming an entire iterable: \n",
244 | " - Generator expressions typically require less memory than the equivalent comprehension \n",
245 | " - Comprehensions may run faster over the entire iteration of the iterable \n",
246 | " - If the entire iterable will not fully be consumed then using a generator may be a better option."
247 | ]
248 | }
249 | ],
250 | "metadata": {
251 | "kernelspec": {
252 | "display_name": "Python 3",
253 | "language": "python",
254 | "name": "python3"
255 | },
256 | "language_info": {
257 | "codemirror_mode": {
258 | "name": "ipython",
259 | "version": 3
260 | },
261 | "file_extension": ".py",
262 | "mimetype": "text/x-python",
263 | "name": "python",
264 | "nbconvert_exporter": "python",
265 | "pygments_lexer": "ipython3",
266 | "version": "3.9.0"
267 | }
268 | },
269 | "nbformat": 4,
270 | "nbformat_minor": 4
271 | }
272 |
--------------------------------------------------------------------------------
/database_efficiency_exercise/2_Exploring_Caching_and_Profiling.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Let's explore caching and profiling.\n",
8 | "\n",
9 | "Important words: \n",
10 | "\n",
11 | "**caching** - Saving a piece of information, usually one that is computationally expensive to fetch, in fast-access memory to hand out to clients who ask for that piece of information. Usually done after the first time the piece of info is fetched. When the result of a function is cached for a specific set of arguments to the function, it's called **memoization**.\n",
12 | "\n",
13 | "**profiling** - Running our code with a tool that tells us how much time and/or memory each portion of our code is using. It is (or should be) the first step in any serious code optimization effort. "
14 | ]
15 | },
16 | {
17 | "cell_type": "code",
18 | "execution_count": null,
19 | "metadata": {},
20 | "outputs": [],
21 | "source": [
22 | "# In REAL LIFE the module you'll import this from is called functools.\n",
23 | "# In this version, I deliberately patched lru_cache to give you access to the cache,\n",
24 | "# Which you don't get in the \"real\" version for thread safety reasons.\n",
25 | "from chelseas_functools import lru_cache \n",
26 | "import cProfile"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {},
32 | "source": [
33 | "Here, I have written a recursive function that calculates the _factorial_ of a number.\n",
34 | "\n",
35 | "Example: 5 factorial, or 5!, is 5 * 4 * 3 * 2 * 1, or 120.\n",
36 | "\n",
37 | "I have decorated it with the `@lru_cache` decorator with a `maxsize` argument of `None`.\n",
38 | "\n",
39 | "[Theis documentation](https://docs.python.org/3/library/functools.html) covers how `@lru_cache` works."
40 | ]
41 | },
42 | {
43 | "cell_type": "code",
44 | "execution_count": null,
45 | "metadata": {},
46 | "outputs": [],
47 | "source": [
48 | "@lru_cache(maxsize=None)\n",
49 | "def factorial(num):\n",
50 | " if num == 1:\n",
51 | " return 1\n",
52 | " else:\n",
53 | " return num * factorial(num-1)"
54 | ]
55 | },
56 | {
57 | "cell_type": "markdown",
58 | "metadata": {},
59 | "source": [
60 | "Now, I run my factorial function on the number 50 with Python's profiler. [Here is the documentation](https://docs.python.org/3/library/profile.html) on how to read profiler output.\n",
61 | "\n",
62 | "Run the cell below a couple of times and notice how the profiler output changes."
63 | ]
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": null,
68 | "metadata": {},
69 | "outputs": [],
70 | "source": [
71 | "cProfile.run('factorial(51)')"
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {},
77 | "source": [
78 | "The `@lru_cache` decorator adds two methods to the `factorial` function:\n",
79 | " \n",
80 | "1. `cache_info`, which gives you four pieces of information about the cache (what are they?)\n",
81 | "1. `cache_clear`, which clears the cache so you can run the function \"from scratch\" again."
82 | ]
83 | },
84 | {
85 | "cell_type": "code",
86 | "execution_count": null,
87 | "metadata": {},
88 | "outputs": [],
89 | "source": [
90 | "factorial.cache_info()"
91 | ]
92 | },
93 | {
94 | "cell_type": "markdown",
95 | "metadata": {},
96 | "source": [
97 | "### OK, so here's where I did something naughty.\n",
98 | "\n",
99 | "I augmented the `@lru_cache` wrapper to give you access to the cache. DO NOT USE the `chelseas_functools` version of `@lru_cache` in any production application. But for our _educational_ purposes, you can here peek inside the cache that the function is keeping:"
100 | ]
101 | },
102 | {
103 | "cell_type": "code",
104 | "execution_count": null,
105 | "metadata": {},
106 | "outputs": [],
107 | "source": [
108 | "factorial.cache"
109 | ]
110 | },
111 | {
112 | "cell_type": "markdown",
113 | "metadata": {},
114 | "source": [
115 | "How many items are in this cache? Is that how many items you expected this cache to have in there?\n",
116 | "\n",
117 | "Does this cache **remind** you of any in-class exercises we have done?"
118 | ]
119 | },
120 | {
121 | "cell_type": "markdown",
122 | "metadata": {},
123 | "source": [
124 | "## Let's try out @lru_cache with a maxsize.\n",
125 | "\n",
126 | "So far in this exercise, we have had the `@lru_cache`'s `maxsize` argument set to `None`. This means that the cache increases in size _indefinitely_. Python has another decorator called `@cache` that has the same behavior as `@lru_cache` with a `maxsize` set to `None`.\n",
127 | "\n",
128 | "#### Questions for you:\n",
129 | "\n",
130 | "1. Based on the documentation you read, what is the default value for `maxsize` in `@lru_cache`?\n",
131 | "2. What are the units of `maxsize`? What is it saving that many of?\n",
132 | "\n",
133 | "Let's set the `@lru_cache`'s `maxsize` to something else: ten, for example. "
134 | ]
135 | },
136 | {
137 | "cell_type": "code",
138 | "execution_count": null,
139 | "metadata": {},
140 | "outputs": [],
141 | "source": [
142 | "@lru_cache(maxsize=10)\n",
143 | "def factorial(num):\n",
144 | " if num == 1:\n",
145 | " return 1\n",
146 | " else:\n",
147 | " return num * factorial(num-1)"
148 | ]
149 | },
150 | {
151 | "cell_type": "markdown",
152 | "metadata": {},
153 | "source": [
154 | "Now, let's run our wrapped function on a number (I have deliberately chosen a small number to make the following examples easier to visually inspect)."
155 | ]
156 | },
157 | {
158 | "cell_type": "code",
159 | "execution_count": null,
160 | "metadata": {},
161 | "outputs": [],
162 | "source": [
163 | "factorial(3)"
164 | ]
165 | },
166 | {
167 | "cell_type": "markdown",
168 | "metadata": {},
169 | "source": [
170 | "**Here's where things get wild**: observe below how the data structure used for the cache _changes_ when the cache has a `maxsize`. \n",
171 | "\n",
172 | "What data structure is that?\n",
173 | "Why do you think it's getting used here? \n",
174 | "\n",
175 | "**Hint #1:** When `@lru_cache` has a limited size, how does it decide which items to keep and which items to get rid of? Does the data structure we saw above support that use case?\n",
176 | "\n",
177 | "**Hint #2:** you can go _look_ at the actual, _real_ implementation of `lru_cache` [right here](https://github.com/python/cpython/blob/main/Lib/functools.py)—or even my copied version in the `chelseas_functools` module in this directory, which is _almost exactly_ the same as the real implementation. Search in the file for `def _lru_cache_wrapper`, which (shocking!) defines the `lru_cache` wrapper. See how that function _switches_ how it implements the cache based on the `maxsize` argument?\n",
178 | "\n",
179 | "Here's what the cache looks like when it has a `maxsize`: "
180 | ]
181 | },
182 | {
183 | "cell_type": "code",
184 | "execution_count": null,
185 | "metadata": {},
186 | "outputs": [],
187 | "source": [
188 | "factorial.cache"
189 | ]
190 | },
191 | {
192 | "cell_type": "code",
193 | "execution_count": null,
194 | "metadata": {},
195 | "outputs": [],
196 | "source": [
197 | "id(factorial.cache[1][1]) == id(factorial.cache[3][0])"
198 | ]
199 | },
200 | {
201 | "cell_type": "code",
202 | "execution_count": null,
203 | "metadata": {},
204 | "outputs": [],
205 | "source": []
206 | }
207 | ],
208 | "metadata": {
209 | "kernelspec": {
210 | "display_name": "Python 3",
211 | "language": "python",
212 | "name": "python3"
213 | },
214 | "language_info": {
215 | "codemirror_mode": {
216 | "name": "ipython",
217 | "version": 3
218 | },
219 | "file_extension": ".py",
220 | "mimetype": "text/x-python",
221 | "name": "python",
222 | "nbconvert_exporter": "python",
223 | "pygments_lexer": "ipython3",
224 | "version": "3.9.0"
225 | }
226 | },
227 | "nbformat": 4,
228 | "nbformat_minor": 4
229 | }
230 |
--------------------------------------------------------------------------------
/data_frame_exercise/phoenixcel/dataframe.py:
--------------------------------------------------------------------------------
1 | import csv
2 |
3 |
4 | class Series(list):
5 | def sum(self):
6 | return sum(self)
7 |
8 | def average(self):
9 | return sum(self) / len(self)
10 |
11 | avg = average
12 |
13 | def apply(self, func):
14 | self = Series([func(x) for x in self])
15 | return self
16 |
17 |
18 | class GroupBy(dict):
19 | def sum(self, on=None):
20 | return self.aggregate(on=on, using_func=sum)
21 |
22 | def average(self, on=None):
23 | def func(listo):
24 | return sum(listo) / len(listo)
25 |
26 | return self.aggregate(on=on, using_func=func)
27 |
28 | avg = average
29 |
30 | def count(self, on=None):
31 | return self.aggregate(on=on, using_func=len)
32 |
33 | def min(self, on=None):
34 | return self.aggregate(on=on, using_func=min)
35 |
36 | def max(self, on=None):
37 | return self.aggregate(on=on, using_func=max)
38 |
39 | def spread(self, on=None):
40 | def func(listo):
41 | return max(listo) - min(listo)
42 |
43 | return self.aggregate(on=on, using_func=func)
44 |
45 | def aggregate(self, on=None, using_func=None):
46 | aggregator = {}
47 | if on == None:
48 | raise Exception("What column do you want aggregated?")
49 | if using_func == None:
50 | raise Exception(f"How do you want '{on}' aggregated?")
51 | else:
52 | for key in self.keys():
53 | addends = [item[on] for item in self[key]]
54 | aggregator[key] = using_func(addends)
55 | return aggregator
56 |
57 | def describe_with(self, *args):
58 | descriptions = {}
59 | for aggregation in args:
60 | if aggregation['agg'] == 'aggregate':
61 | result = self.aggregate(on=aggregation['column'], using_func=aggregation['using_func'])
62 | function_name = aggregation['using_func'].__name__
63 | else:
64 | aggregation_function = getattr(self, aggregation['agg'])
65 | result = aggregation_function(on=aggregation['column'])
66 | function_name = aggregation['agg']
67 |
68 | for result_key in result.keys():
69 | if not descriptions.get(result_key):
70 | descriptions[result_key] = {}
71 | aggregation_label = f"{aggregation['column']} {function_name}"
72 | descriptions[result_key][aggregation_label] = result[result_key]
73 | return GroupBy(descriptions)
74 |
75 | def print_cute(self):
76 | '''
77 | Prints out a GroupBy or a GroupBy Description in a nice format.
78 |
79 | Input:
80 | None - this method operates on the existing GroupBy object.
81 |
82 | Output:
83 | None - no return value
84 |
85 | Modifies:
86 | Prints to standard out with a list of the groups. For each group,
87 | prints an indented list of the items in it (for a GroupBy),
88 | or an indented list of summary statistics (for a Groupby Description).
89 | '''
90 | for key, value in self.items():
91 | print(key)
92 |
93 | if isinstance(value, dict):
94 | for key, component in value.items():
95 | print(f" {key} : {component}")
96 | else:
97 | for component in value:
98 | print(f" {component}")
99 |
100 |
101 | class DataFrame():
102 | def __init__(self):
103 | self._dictionary = {}
104 | self._list = []
105 |
106 | # Ways to crate an instance
107 | @classmethod
108 | def from_csv(cls, file_path):
109 | df = cls()
110 | header_unread = True
111 |
112 | with open(file_path) as f:
113 | reader = csv.DictReader(f)
114 |
115 | for row in reader:
116 | if header_unread:
117 | for key in row.keys():
118 | df._dictionary[key] = Series()
119 | header_unread = False
120 |
121 | df._list.append(row)
122 |
123 | for key in row.keys():
124 | df._dictionary[key].append(row[key])
125 |
126 | for key in list(df._dictionary.keys()):
127 | setattr(df, key.lower().replace(" ", "_"), df._dictionary[key])
128 | return df
129 |
130 | @classmethod
131 | def from_rows(cls, rows):
132 | df = cls()
133 | for key in rows[0].keys():
134 | df._dictionary[key] = Series()
135 | for row in rows:
136 | for key in rows[0].keys():
137 | df._dictionary[key].append(row[key])
138 |
139 | df._list.append(row)
140 |
141 | for key in list(df._dictionary.keys()):
142 | setattr(df, key.lower().replace(" ", "_"), df._dictionary[key])
143 |
144 | return df
145 |
146 | @classmethod
147 | def from_dictionary(cls, dictionary):
148 | df = cls()
149 | df._dictionary = dictionary
150 | for i in range(len(dictionary[list(dictionary.keys())[0]])):
151 | item = {}
152 | for key in dictionary.keys():
153 | item[key] = dictionary[key][i]
154 | df._list.append(item)
155 |
156 | for key in list(df._dictionary.keys()):
157 | setattr(df, key.lower().replace(" ", "_"), df._dictionary[key])
158 |
159 | return df
160 |
161 | # Properties
162 | @property
163 | def shape(self):
164 | return \
165 | len(self._dictionary.keys()), \
166 | len(self._dictionary[list(self._dictionary.keys())[0]])
167 |
168 | @property
169 | def columns(self):
170 | return list(self._dictionary.keys())
171 |
172 | # Methods for getting a column in the dictionary
173 | def __getitem__(self, item):
174 | '''
175 | Get a reference to a column in the dataframe.
176 |
177 | Input:
178 | item - the column header
179 |
180 | Output:
181 | the column, which is a series
182 |
183 | Modifies:
184 | Nothing
185 | '''
186 | return self._dictionary[item]
187 |
188 | # Method for setting a column in the dictionary
189 | def __setitem__(self, key, value):
190 | '''
191 | Set a new column in the dataframe.
192 |
193 | Inputs:
194 | key - the column header
195 | value - the column (as a Series for consistency, please)
196 |
197 | Outputs:
198 | None
199 |
200 | Modifies:
201 | Modifies the dataframe object in place.
202 | '''
203 | self._dictionary[key] = value
204 | for index, item in enumerate(self._list):
205 | item[key] = value[index]
206 |
207 | setattr(self, key.lower().replace(" ", "_"), self._dictionary[key])
208 |
209 | def where(self, condition):
210 | rows = [row for row in self._list if condition(row)]
211 | return DataFrame.from_rows(rows)
212 |
213 | def assign(self, **kwargs):
214 | for key, value in kwargs.items():
215 | new_column = Series()
216 | for row in self._list:
217 | new_column.append(value(row))
218 | self.__setitem__(key, new_column)
219 | return self
220 |
221 | def group_by(self, column):
222 | '''
223 | Returns an object that aggregates the items in the dataframe
224 | based on one value that they have in common,
225 | similar to a pivot table in the software to which
226 | phoenixcell's name pays tribute (Please don't sue me, Microsoft)
227 |
228 | Inputs:
229 | column - the column on whose value the items should be grouped
230 |
231 | Outputs:
232 | A new GroupBy() object
233 |
234 | Modifies:
235 | Nothing
236 | '''
237 | groups = GroupBy()
238 | for item in self._list:
239 | maybe_unique_column_value = item[column]
240 | if maybe_unique_column_value in groups.keys():
241 | groups[maybe_unique_column_value].append(item)
242 | else:
243 | groups[maybe_unique_column_value] = Series()
244 | groups[maybe_unique_column_value].append(item)
245 | return groups
--------------------------------------------------------------------------------
/ch6_how_functions_and_objects_work_together/6.3_Functional_Constructs.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### [Video Explanation Here!](https://youtu.be/FivUQTtcDhI)\n",
8 | "\n",
9 | "### Functional Programming \n",
10 | "\n",
11 | "Python is a multiparadigm language that also provides a set of built-ins used for *functional programming*: in Python's case, tools that apply functions to sequences and other iterables.\n",
12 | "\n",
13 | "What are some of the built-in functional programming functions? ``map``, ``filter``. We look at each now."
14 | ]
15 | },
16 | {
17 | "cell_type": "markdown",
18 | "metadata": {},
19 | "source": [
20 | "#### Map \n",
21 | "- ``map(function, iterable, ...)``: Applies the given ``function`` argument to each item in the ``iterable`` argument. It returns a new iterable object with all those new values.\n",
22 | "\n",
23 | "- The return iterable object is a map object. \n",
24 | "- Can use both ``def`` and ``lambda`` statements to generate the function objects. "
25 | ]
26 | },
27 | {
28 | "cell_type": "code",
29 | "execution_count": null,
30 | "metadata": {},
31 | "outputs": [],
32 | "source": [
33 | "map_obj = map(lambda x: x + 2, [1,2,3])\n",
34 | "\n",
35 | "# This object contains the new collection of values, which are \n",
36 | "# 3,4,5. We cannot see them if we were to print them out \n",
37 | "map_obj"
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "execution_count": null,
43 | "metadata": {},
44 | "outputs": [],
45 | "source": [
46 | "#Since a map object is an iterable object. We can use a iteration\n",
47 | "# context to go through it. \n",
48 | "for item in map_obj:\n",
49 | " print(item)"
50 | ]
51 | },
52 | {
53 | "cell_type": "code",
54 | "execution_count": null,
55 | "metadata": {},
56 | "outputs": [],
57 | "source": [
58 | "list_added_two = list(map_obj)\n",
59 | "list_added_two"
60 | ]
61 | },
62 | {
63 | "cell_type": "code",
64 | "execution_count": null,
65 | "metadata": {},
66 | "outputs": [],
67 | "source": [
68 | "# What happens when we try to use map_obj again?\n",
69 | "for item in map_obj:\n",
70 | " print(item)"
71 | ]
72 | },
73 | {
74 | "cell_type": "code",
75 | "execution_count": null,
76 | "metadata": {},
77 | "outputs": [],
78 | "source": [
79 | "# Or we could convert the map iterable object into another iterable\n",
80 | "# object \n",
81 | "map_obj = map(lambda x: x + 2, [1,2,3])\n",
82 | "lst = set(map_obj)\n",
83 | "print(lst)"
84 | ]
85 | },
86 | {
87 | "cell_type": "code",
88 | "execution_count": null,
89 | "metadata": {},
90 | "outputs": [],
91 | "source": [
92 | "# The previous example used a lambda but we can also use function objects\n",
93 | "# defined with def \n",
94 | "list(map(len, [[1,2,3],[4],[5,6]]))"
95 | ]
96 | },
97 | {
98 | "cell_type": "markdown",
99 | "metadata": {},
100 | "source": [
101 | "The ``operator`` modules provides the standard operators in Python as expressions, which you can use in these tools. "
102 | ]
103 | },
104 | {
105 | "cell_type": "code",
106 | "execution_count": null,
107 | "metadata": {},
108 | "outputs": [],
109 | "source": [
110 | "import operator \n",
111 | "list(map(operator.abs,[-2,53,-43]))"
112 | ]
113 | },
114 | {
115 | "cell_type": "markdown",
116 | "metadata": {},
117 | "source": [
118 | "The ``map`` function can also take in a N-argument functions to work with N-iterable objects"
119 | ]
120 | },
121 | {
122 | "cell_type": "code",
123 | "execution_count": null,
124 | "metadata": {},
125 | "outputs": [],
126 | "source": [
127 | "# \"pow\" is a binary function (takes 2 operands);\n",
128 | "# therefore we canprovide map with two iterables\n",
129 | "list(map(pow,[1,2,3],[4,5,3]))"
130 | ]
131 | },
132 | {
133 | "cell_type": "markdown",
134 | "metadata": {},
135 | "source": [
136 | "Binary functions from the ``operator`` modules can also be used: "
137 | ]
138 | },
139 | {
140 | "cell_type": "code",
141 | "execution_count": null,
142 | "metadata": {},
143 | "outputs": [],
144 | "source": [
145 | "list(map(operator.sub,[20,19],range(2)))"
146 | ]
147 | },
148 | {
149 | "cell_type": "markdown",
150 | "metadata": {},
151 | "source": [
152 | "#### Filter \n",
153 | "\n",
154 | "- ``filter(function, iterable)``: Returns an iterable that contains all items from the ``iterable`` argument for which the ``function`` argument is returns ``True``. Each element from the iterable object is passed as an argument to ``function``. "
155 | ]
156 | },
157 | {
158 | "cell_type": "code",
159 | "execution_count": null,
160 | "metadata": {},
161 | "outputs": [],
162 | "source": [
163 | "list(filter(str.isupper,['a',\"ABC\", 'def']))"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": null,
169 | "metadata": {},
170 | "outputs": [],
171 | "source": [
172 | "list(filter(lambda x: x%2 != 0, [1,2,3,4,5]))"
173 | ]
174 | },
175 | {
176 | "cell_type": "markdown",
177 | "metadata": {},
178 | "source": [
179 | "#### Functools \n",
180 | "\n",
181 | "In Python, the ``functools`` module provides more functional programming functions in Python. For example,\n",
182 | "\n",
183 | " - ``functools.reduce(function, iterable[, initializer])``: Apply ``function`` to pairs of items successively and return a single value as the result. You can optionally specify the initial value.\n"
184 | ]
185 | },
186 | {
187 | "cell_type": "code",
188 | "execution_count": null,
189 | "metadata": {},
190 | "outputs": [],
191 | "source": [
192 | "import functools \n",
193 | "import operator \n",
194 | "\n",
195 | "# 1st iteration: Call operator.add(1,2) -> 3 \n",
196 | "# 2nd iteration: Call operator.add(3,3) -> 6 \n",
197 | "# 3rd iteration: Call operator.add(6,4) -> 10 \n",
198 | "# final result = 10 \n",
199 | "functools.reduce(operator.add, [1,2,3,4])"
200 | ]
201 | },
202 | {
203 | "cell_type": "code",
204 | "execution_count": null,
205 | "metadata": {},
206 | "outputs": [],
207 | "source": [
208 | "# What happens if you pass in an initial value \n",
209 | "# 1st iteration: Call operator.mul(2,1) -> 2 \n",
210 | "# 2nd iteration: Call operator.mul(2,2) -> 4 \n",
211 | "# 3rd iteration: Call operator.mul(4,3) -> 12 \n",
212 | "# 4th iteration: Call operator.mul(12,4) -> 48 \n",
213 | "# Final result = 48 \n",
214 | "functools.reduce(operator.mul, [1,2,3,4], 2)"
215 | ]
216 | },
217 | {
218 | "cell_type": "code",
219 | "execution_count": null,
220 | "metadata": {},
221 | "outputs": [],
222 | "source": [
223 | "# User-defined functions must take in 2 arguments:\n",
224 | "# 1st iteration: lambda(2,1): pow(2,1) -> 2 \n",
225 | "# 2nd iteration: lambda(2,3): pow(2,3) -> 8\n",
226 | "# Final result = 8 \n",
227 | "functools.reduce(lambda x, y: pow(x,y), [2,3])"
228 | ]
229 | },
230 | {
231 | "cell_type": "markdown",
232 | "metadata": {},
233 | "source": [
234 | "The functional methods in Python pretty clearly communicate the maintainer's disdain for them by being crappy to use. It's GVR's position that modern Python constructs like list comprehensions obviate the need for map and filter, and wanted to remove them in Python 3 but didn't due to community backlash.\n",
235 | "\n",
236 | "He thought reduce, in particular, sucked because \"it was only ever used to add things together or write illegible code.\" But rather than remove it completely and incite a firestorm, they demoted it from a builtin function to the functools module, which is, by his own admission, where Guido stuffs things he doesn't care about :-). "
237 | ]
238 | }
239 | ],
240 | "metadata": {
241 | "kernelspec": {
242 | "display_name": "Python 3",
243 | "language": "python",
244 | "name": "python3"
245 | },
246 | "language_info": {
247 | "codemirror_mode": {
248 | "name": "ipython",
249 | "version": 3
250 | },
251 | "file_extension": ".py",
252 | "mimetype": "text/x-python",
253 | "name": "python",
254 | "nbconvert_exporter": "python",
255 | "pygments_lexer": "ipython3",
256 | "version": "3.9.0"
257 | }
258 | },
259 | "nbformat": 4,
260 | "nbformat_minor": 4
261 | }
262 |
--------------------------------------------------------------------------------
/ch8_build_your_own_API/Homework_Problems.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### It is time.\n",
8 | "\n",
9 | "You know some Python. You have some practice with reading code that others have written. You have started writing code to satisfy automated tests. You have even begun evaluating some code design decisions.\n",
10 | "\n",
11 | "### Now, you are ready to write your own tests, plus the implementation code to make them pass.\n",
12 | "\n",
13 | "For this homework, you'll be writing a fully-tested API that fetches data from a fully-tested in-memory database.\n",
14 | "\n",
15 | "Sound daunting? Don't worry :) You'll have video tutorials to help you! \n",
16 | "\n",
17 | "The first thing you want to do is **choose a data model**. Your data model can be whatever you like: I like birds, so in my video tutorials I chose to make a data model to represent birds. In a FastAPI tutorial linked below, Anthony Herbert creates an API and database that provides information about cities.\n",
18 | "\n",
19 | "### The tutorials will not show you _all_ of the steps, but they will help you get started.\n",
20 | "\n",
21 | "This is akin to what you will need to do as a professional software engineer: you won't always have a teacher there to explain how to solve the problems you need to solve, and you'll have to do your own research, sometimes piecing together information from several sources. [Here's a video I recorded for you](https://youtu.be/6zlKxjfD1zA) about some of the sources you can use to help you approach novel programming challenges. You have options besides Stack Overflow!\n",
22 | "\n",
23 | "### OK, now let's get started on the API.\n",
24 | "\n",
25 | "For this API, you will set up a **virtual environment**: you can think of this as a container that your app can run in, that holds all the appropriate versions of all the libraries you need and keeps them separate from all the other projects on your machine. \n",
26 | "\n",
27 | "1. [Follow this video tutotial](https://youtu.be/p4x-HiRncSw) to set up a virtual environment.\n",
28 | "\n",
29 | "Next, it's time to start your API!\n",
30 | "\n",
31 | "2. [Follow this video tutotial](https://youtu.be/FWXZ5CpM4LA) to write your first API endpoint.\n",
32 | "\n",
33 | "Then, you'll begin following _another_ useful (and expected, for software engineers) practice: automated testing. \n",
34 | "\n",
35 | "3. [Follow this video tutotial](https://youtu.be/60pTjaP-1ts) to write a unit test for your first endpoint.\n",
36 | "\n",
37 | "If you follow these tutorials, you should automatically succeed on your first set of requirements.\n",
38 | "\n",
39 | "### Requirements here:\n",
40 | "\n",
41 | "1. Your app exists.\n",
42 | "2. Your app is in a virtual environment with a Pipfile delineating the dependencies."
43 | ]
44 | },
45 | {
46 | "cell_type": "markdown",
47 | "metadata": {},
48 | "source": [
49 | "### Once you have done all that, it's time to try some things on your own.\n",
50 | "\n",
51 | "\n",
52 | "\n",
53 | "Using what you've learned so far, you'll make an API that serves up data from a dict in your `main.py` file. This API should be able to create items (put them in the dictionary), list all the items out of the dictionary, get a specific item from the dictionary, or delete an item from the dictionary.\n",
54 | "\n",
55 | "[This video](https://youtu.be/kCggyi_7pHg) is a fantastic introduction to writing these four endpoints in FastAPI. Note that that video stores cities in a **list**, and you'll want to store your objects in a **dictionary**. This will make for an easier transition when we start putting them in an actual _database_ later. \n",
56 | "\n",
57 | "Also note that at the end of that video, Anthony writes an integration to get local times for the cities in his database. You don't have to do something like that: your data model can have just keys and static values.\n",
58 | "\n",
59 | "### Requirements here:\n",
60 | "\n",
61 | "1. A GET endpoint named for your resource (in my case birds, in Anthony's case cities) that gets all the items in the dictionary.\n",
62 | "2. This endpoint should have a unit test that passes when the endpoint works and fails when it doesn't.\n",
63 | "\n",
64 | "3. A GET endpoint named for your resource that gets a specific item in the dictionary based on its key (you can make the keys whatever you like: [GUIDS](https://www.guidgenerator.com) are a common choice. I chose to just use the birds' names.)\n",
65 | "4. This endpoint should have a unit test that passes when the endpoint works and fails when it doesn't.\n",
66 | "\n",
67 | "5. A POST endpoint named for your resource that adds an instance to your dictionary.\n",
68 | "6. This endpoint should have a unit test that passes when the endpoint works and fails when it doesn't.\n",
69 | "\n",
70 | "7. A DELETE endpoint named for your resource that deletes a specific item in the dictionary.\n",
71 | "8. This endpoint should have a unit test that passes when the endpoint works and fails when it doesn't.\n",
72 | "\n",
73 | "Four endpoints, four unit tests. We're practicing the skill here of patching together information from different sources to learn how to implement your own application. You will rarely be able to find an _exact_ tutorial, and you'll need to be able to consult different use cases and documentation to find your way to your end goal.\n",
74 | "\n",
75 | "What challenges do you run into as you write these unit tests? You may run into a challenge where, to make sure your requests to _get_ stuff from the database are working, you have to dirst _put_ stuff in the database."
76 | ]
77 | },
78 | {
79 | "cell_type": "markdown",
80 | "metadata": {},
81 | "source": [
82 | "### Addressing the challenge: dependency injection\n",
83 | "\n",
84 | "[Follow this video tutotial](https://youtu.be/-NsfdPajLYs) to test-drive a database object. We'll use this instead of a plain old dictionary going forward.\n",
85 | "\n",
86 | "Then, [follow this video tutotial](https://youtu.be/Vqt4Efo-To8) to **inject the database dependency** into the app so that we can rely on test data for the database in our unit tests. This video also shows you a useful tool for tracking down problems while you're testing by using the python debugger, called pdb for short.\n",
87 | "\n",
88 | "Once you have the database injected into your app, you'll need to change each of your routes (listing items, getting an item, creating an item, an deleting an item) to use your new database. (In fact, the create function in the video would not work without changes for it to use the database properly by calling the \"put\" method rather than trying to assign items directly).\n",
89 | "\n",
90 | "### Requirements here:\n",
91 | "\n",
92 | "1. You have created the database object, as per the tutorial. You have tested it, as per the tutorial. You have injected it into your app, as per the tutorial.\n",
93 | "2. All of the endpoints (except for delete) now reference an instance of your database rather than a dictionary (we only cover this for the _first_ endpoint in that tutorial).\n",
94 | "3. All of the unit tests (except for delete) are adjusted to work with the changed endpoints, so they pass when the endpoints work and fail when they don't."
95 | ]
96 | },
97 | {
98 | "cell_type": "markdown",
99 | "metadata": {},
100 | "source": [
101 | "### But wait. What about delete??\n",
102 | "\n",
103 | "Yes. The new database object doesn't have a method to help you delete things! Add this function (and a unit test for it!) and call that function from your route that deletes things.\n",
104 | "\n",
105 | "### Requirements here:\n",
106 | "\n",
107 | "1. Your database has a \"delete\" function.\n",
108 | "2. This \"delete\" function has a unit test.\n",
109 | "3. Your \"delete\" route deletes an item from your database and your test is adjusted to work with the changed endpoint, so that it passes when the endpoint works and fails when it doesn't.\n",
110 | "\n",
111 | "### Things that you specifically _do not_ have to do:\n",
112 | "\n",
113 | "1. You do not have to deploy this anywhere. Running locally is fine. \n",
114 | "2. You do not have to open a pull request. Instead, accept [this repo assignment](https://classroom.github.com/a/Fg8fa_Uz) and stick your app in there. You can push straight to the `main` branch for this assignment."
115 | ]
116 | }
117 | ],
118 | "metadata": {
119 | "kernelspec": {
120 | "display_name": "Python 3",
121 | "language": "python",
122 | "name": "python3"
123 | },
124 | "language_info": {
125 | "codemirror_mode": {
126 | "name": "ipython",
127 | "version": 3
128 | },
129 | "file_extension": ".py",
130 | "mimetype": "text/x-python",
131 | "name": "python",
132 | "nbconvert_exporter": "python",
133 | "pygments_lexer": "ipython3",
134 | "version": "3.9.0"
135 | }
136 | },
137 | "nbformat": 4,
138 | "nbformat_minor": 4
139 | }
140 |
--------------------------------------------------------------------------------
/database_efficiency_exercise/1_Value_Counts_(Time_Efficiency).ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## In Chapter 8, you worked on an in-memory data store.\n",
8 | "\n",
9 | "So far it wraps a dictionary with keys that point to each of the items. Now we'll start building out some of the functionality that more sophisticated data stores have. Let's make a new key-value data store. It has a function to `get` values and `set` values. It also has a `count` function, which currently always returns zero."
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": null,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "import random\n",
19 | "from datetime import datetime\n",
20 | "\n",
21 | "class Datastore():\n",
22 | " def __init__(self):\n",
23 | " self._data = {}\n",
24 | " \n",
25 | " def insert_at_random(self, values, num_records):\n",
26 | " for x in range(num_records):\n",
27 | " random_key = hash(x) # This is how we're getting a pseudo-random and probably unique ID\n",
28 | " value_from_choices = random.choices(values)[0]\n",
29 | " self.set(random_key, value_from_choices)\n",
30 | " \n",
31 | " def get(self, key):\n",
32 | " return self._data[key]\n",
33 | " \n",
34 | " def set(self, key, value):\n",
35 | " self._data[key] = value\n",
36 | " \n",
37 | " def count(self, value):\n",
38 | " return 0\n",
39 | " "
40 | ]
41 | },
42 | {
43 | "cell_type": "markdown",
44 | "metadata": {},
45 | "source": [
46 | "Take a look at `insert_at_random` for this data store; we fill it up with lots of instances of a few different fruit and vegetable values."
47 | ]
48 | },
49 | {
50 | "cell_type": "code",
51 | "execution_count": null,
52 | "metadata": {},
53 | "outputs": [],
54 | "source": [
55 | "db = Datastore()\n",
56 | "db.insert_at_random(values=[\"apple\", \"banana\", \"carrot\", \"celery\", \"mirepoix\", \"clementine\"], num_records=1000000)\n",
57 | "db.count(\"clementine\")"
58 | ]
59 | },
60 | {
61 | "cell_type": "markdown",
62 | "metadata": {},
63 | "source": [
64 | "Now, when we have a table full of data, it's _pretty common_ for clients to want to be able to find out _how many_ of each value are in a given column. For example, if we have a table of different foods, maybe we want to know how many times each food appears in the datastore. \n",
65 | "\n",
66 | "Today we are going to implement the `count` function. See the automated test below, which illustrate exactly how this function should work. Two things to note:\n",
67 | "\n",
68 | "1. Right now, the test _fails_ because you'll have to implement `count` to get it to pass.\n",
69 | "2. The test is looking for a _range_ rather than an exact answer because we're randomly assigning values into the datas tore, so the test represents a 99.8% **confidence interval** around the number of clementine values your data store instance will randomly have (see how confidence intervals are useful? :)"
70 | ]
71 | },
72 | {
73 | "cell_type": "code",
74 | "execution_count": null,
75 | "metadata": {},
76 | "outputs": [],
77 | "source": [
78 | "# You need these imports to run the tests\n",
79 | "import sys\n",
80 | "!{sys.executable} -m pip install colorama \n",
81 | "\n",
82 | "sys.path.insert(0, '..')\n",
83 | "from test_framework_exercise.phoenix_test.matchers import FailedAssertion, Assertion, assert_that\n",
84 | "from test_framework_exercise.phoenix_test.test import Test\n",
85 | "sys.path.remove('..')"
86 | ]
87 | },
88 | {
89 | "cell_type": "code",
90 | "execution_count": null,
91 | "metadata": {},
92 | "outputs": [],
93 | "source": [
94 | "class DatastoreCountTest(Test):\n",
95 | " def test_count(self):\n",
96 | " test_db = Datastore()\n",
97 | " test_db.insert_at_random(values=[\"apple\", \"banana\", \"carrot\", \"celery\", \"mirepoix\", \"clementine\"], num_records=1000000) \n",
98 | "\n",
99 | " result = test_db.count(\"clementine\")\n",
100 | " assert_that(160000 < result < 170000).is_true()\n",
101 | " \n",
102 | "DatastoreCountTest().run()"
103 | ]
104 | },
105 | {
106 | "cell_type": "markdown",
107 | "metadata": {},
108 | "source": [
109 | "### Challenge: Implement the `count` function. \n",
110 | "\n",
111 | "The `count` function will allow you to get the number of a certain value stored in your key value store so that the above test passes."
112 | ]
113 | },
114 | {
115 | "cell_type": "markdown",
116 | "metadata": {},
117 | "source": [
118 | "## Done? OK. \n",
119 | "\n",
120 | "Now it's time to tell you about my secret motive for this problem: this exercise is a helpful introduction to the concepts of time and space efficiency in software engineering and how to evaluate those tradeoffs.\n",
121 | "\n",
122 | "To make it easier to do that, let's introduce everyone's favorite thing: a decorator! This decorator, called `stopwatch`, prints out how long a method took to run."
123 | ]
124 | },
125 | {
126 | "cell_type": "code",
127 | "execution_count": null,
128 | "metadata": {},
129 | "outputs": [],
130 | "source": [
131 | "def stopwatch(func):\n",
132 | " def wrapper(*args, **kwargs):\n",
133 | " start = datetime.now()\n",
134 | " result = func(*args, **kwargs)\n",
135 | " end = datetime.now()\n",
136 | " print(f\"Operation took {end - start} seconds\")\n",
137 | " return result\n",
138 | " \n",
139 | " return wrapper"
140 | ]
141 | },
142 | {
143 | "cell_type": "markdown",
144 | "metadata": {},
145 | "source": [
146 | "### Challenge: Annotate the `count` function with the `@stopwatch` decorator. \n",
147 | "\n",
148 | "Then, duplicate the line ` result = self.db.count(\"clementine\")` a few times in your test so it runs several times.\n",
149 | "\n",
150 | "Run the test again. You should get several printouts of how long the test is taking.\n",
151 | "\n",
152 | "Why do you think the test is taking so long?\n",
153 | "\n",
154 | ".\n",
155 | "..\n",
156 | "...\n",
157 | "....\n",
158 | "...\n",
159 | "..\n",
160 | "."
161 | ]
162 | },
163 | {
164 | "cell_type": "markdown",
165 | "metadata": {},
166 | "source": [
167 | "## Introducing performance testing!\n",
168 | "\n",
169 | "In software engineering, **performance** usually refers to a program's _speed_. And especially when it comes to fetching data, speed can be really, _really_ important. So, in addition to tests that make sure our code does the right thing, we might have tests to make sure our code does the right thing _fast enough_.\n",
170 | "\n",
171 | "Run the below test on your implementation of the data store. Does it pass?"
172 | ]
173 | },
174 | {
175 | "cell_type": "code",
176 | "execution_count": null,
177 | "metadata": {},
178 | "outputs": [],
179 | "source": [
180 | "class DatastorePerformanceTest(Test):\n",
181 | "\n",
182 | " def test_count_performance(self):\n",
183 | " test_db = Datastore()\n",
184 | " test_db.insert_at_random(values=[\"apple\", \"banana\", \"carrot\", \"celery\", \"mirepoix\", \"clementine\"], num_records=1000000)\n",
185 | " \n",
186 | " start = datetime.now()\n",
187 | " test_db.count(\"clementine\")\n",
188 | " end = datetime.now()\n",
189 | " assert_that((end - start).total_seconds() < 0.01).is_true() \n",
190 | " \n",
191 | "DatastorePerformanceTest().run()"
192 | ]
193 | },
194 | {
195 | "cell_type": "markdown",
196 | "metadata": {},
197 | "source": [
198 | "### Challenge: Implement your `count` function so that _both_ test suites pass.\n",
199 | "\n",
200 | "What do you have to do to make that work? \n",
201 | "\n",
202 | "What are the implications of that strategy for your data store?"
203 | ]
204 | },
205 | {
206 | "cell_type": "code",
207 | "execution_count": null,
208 | "metadata": {},
209 | "outputs": [],
210 | "source": [
211 | "db = Datastore()\n",
212 | "db.insert_at_random(values=[\"apple\", \"banana\", \"carrot\", \"celery\", \"mirepoix\", \"clementine\"], num_records=1000000)\n",
213 | "db.count(\"clementine\")"
214 | ]
215 | },
216 | {
217 | "cell_type": "code",
218 | "execution_count": null,
219 | "metadata": {},
220 | "outputs": [],
221 | "source": [
222 | "import sys\n",
223 | "\n",
224 | "sys.getsizeof(str(db._data))"
225 | ]
226 | },
227 | {
228 | "cell_type": "code",
229 | "execution_count": null,
230 | "metadata": {},
231 | "outputs": [],
232 | "source": [
233 | "sys.getsizeof(str(db._counts))"
234 | ]
235 | }
236 | ],
237 | "metadata": {
238 | "kernelspec": {
239 | "display_name": "Python 3",
240 | "language": "python",
241 | "name": "python3"
242 | },
243 | "language_info": {
244 | "codemirror_mode": {
245 | "name": "ipython",
246 | "version": 3
247 | },
248 | "file_extension": ".py",
249 | "mimetype": "text/x-python",
250 | "name": "python",
251 | "nbconvert_exporter": "python",
252 | "pygments_lexer": "ipython3",
253 | "version": "3.9.0"
254 | }
255 | },
256 | "nbformat": 4,
257 | "nbformat_minor": 4
258 | }
259 |
--------------------------------------------------------------------------------
/data_frame_exercise/1_Series_and_GroupBy.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## Our Testing Framework is a Runaway Success.\n",
8 | "\n",
9 | "We have lots of open source clients,a booming Patreon, and packed weeks of conversations with potential sponsors.\n",
10 | "\n",
11 | "Now our clients are asking us for more tools. This time, they're hoping that we'll make something to improve their workflow for data analysis. In particular, one client does lots of number crunching on Chicago open data, and they'd like something better than the csv library for exploring and analyzing the datasets.\n",
12 | "\n",
13 | "So we start working on a library called `phoenixcell`.\n",
14 | "\n",
15 | "We start with a `Series` object that extends a `list` and has an `apply` function."
16 | ]
17 | },
18 | {
19 | "cell_type": "code",
20 | "execution_count": null,
21 | "metadata": {},
22 | "outputs": [],
23 | "source": [
24 | "import csv\n",
25 | "\n",
26 | "class Series(list):\n",
27 | " def apply(self, func):\n",
28 | " self = [func(x) for x in self]\n",
29 | " return Series(self)"
30 | ]
31 | },
32 | {
33 | "cell_type": "markdown",
34 | "metadata": {},
35 | "source": [
36 | "### Challenge: What does the apply function do?\n",
37 | "\n",
38 | "1. What argument(s) does it take in?\n",
39 | "2. What does it do with the argument(s)?\n",
40 | "3. What does it modify?\n",
41 | "4. What does it return?"
42 | ]
43 | },
44 | {
45 | "cell_type": "markdown",
46 | "metadata": {},
47 | "source": [
48 | "See it in action here:"
49 | ]
50 | },
51 | {
52 | "cell_type": "code",
53 | "execution_count": null,
54 | "metadata": {},
55 | "outputs": [],
56 | "source": [
57 | "s = Series()\n",
58 | "s.append(1)\n",
59 | "s.append(2)\n",
60 | "s.append(3)\n",
61 | "\n",
62 | "result = s.apply(float)"
63 | ]
64 | },
65 | {
66 | "cell_type": "markdown",
67 | "metadata": {},
68 | "source": [
69 | "We also make an object called `GroupBy` that extends a `dict` and has a fuction called `aggregate()`."
70 | ]
71 | },
72 | {
73 | "cell_type": "code",
74 | "execution_count": null,
75 | "metadata": {},
76 | "outputs": [],
77 | "source": [
78 | " class GroupBy(dict):\n",
79 | " def sum(self, column=None):\n",
80 | " return self.aggregate(column=column, using_func=sum)\n",
81 | "\n",
82 | " def average(self, column=None):\n",
83 | " def func(listo):\n",
84 | " return sum(listo) / len(listo)\n",
85 | " return self.aggregate(column=column, using_func=func)\n",
86 | " avg = average\n",
87 | "\n",
88 | " def count(self, column=None):\n",
89 | " return self.aggregate(column=column, using_func=len)\n",
90 | "\n",
91 | " def aggregate(self, column=None, using_func=None): \n",
92 | " aggregator = {}\n",
93 | " if column == None:\n",
94 | " raise Exception(\"What column do you want aggregated?\")\n",
95 | " if using_func == None:\n",
96 | " raise Exception(f\"How do you want '{column}' aggregated?\")\n",
97 | " else:\n",
98 | " for key in self.keys():\n",
99 | " addends = [item[column] for item in self[key]]\n",
100 | " aggregator[key] = using_func(addends)\n",
101 | " return aggregator"
102 | ]
103 | },
104 | {
105 | "cell_type": "markdown",
106 | "metadata": {},
107 | "source": [
108 | "### Challenge: \n",
109 | "\n",
110 | "What does the aggregate function do?\n",
111 | "\n",
112 | "1. What argument(s) does it take in?\n",
113 | "2. What does it do with the argument(s)?\n",
114 | "3. What does it modify?\n",
115 | "4. What does it return?\n",
116 | "\n",
117 | "Here's an example of it running: "
118 | ]
119 | },
120 | {
121 | "cell_type": "code",
122 | "execution_count": null,
123 | "metadata": {},
124 | "outputs": [],
125 | "source": [
126 | "birds = GroupBy( \\\n",
127 | " oriole = [ \n",
128 | " {'species': 'oriole', 'specimen_id': '7dr4h32ss24g6t7f2', 'weight': 4.23},\n",
129 | " {'species': 'oriole', 'specimen_id': 'g6t7f2dr4h327ss24', 'weight': 4.17},\n",
130 | " {'species': 'oriole', 'specimen_id': 't77ss24g6f2dr4h32', 'weight': 5.21},\n",
131 | " ],\n",
132 | " bluejay = [\n",
133 | " {'species': 'bluejay', 'specimen_id': '88Jnnb323es29bs2f', 'weight': 5.0},\n",
134 | " {'species': 'bluejay', 'specimen_id': 'g6t3f2dr4h322ss24', 'weight': 6.32},\n",
135 | " {'species': 'bluejay', 'specimen_id': 'f2dr4t76ss24g6h32', 'weight': 5.21},\n",
136 | " {'species': 'bluejay', 'specimen_id': 't7f2312ss24g6dr4h', 'weight': 4.85},\n",
137 | " {'species': 'bluejay', 'specimen_id': '9f237ss24g6t8dr4h', 'weight': 5.69}\n",
138 | " ],\n",
139 | " titmouse = [\n",
140 | " {'species': 'titmouse', 'specimen_id': '1sn32ufks82d92b39', 'weight': 5.22},\n",
141 | " {'species': 'titmouse', 'specimen_id': '8sh2bdn4s24g6t7f2', 'weight': 2.13},\n",
142 | " {'species': 'titmouse', 'specimen_id': 'h38snsdr4h327ss24', 'weight': 3.1},\n",
143 | " {'species': 'titmouse', 'specimen_id': '32bf72f9m27f2dr4h', 'weight': 2.22},\n",
144 | " {'species': 'titmouse', 'specimen_id': '2b47f29fn34h47dn3', 'weight': 3.0},\n",
145 | " {'species': 'titmouse', 'specimen_id': 't77ss24g6f27s41md', 'weight': 2.98}\n",
146 | " ]\n",
147 | ")"
148 | ]
149 | },
150 | {
151 | "cell_type": "code",
152 | "execution_count": null,
153 | "metadata": {},
154 | "outputs": [],
155 | "source": [
156 | "# This is kinda counterintuitive. What does this do?\n",
157 | "# Run it and see if you can figure out what it's telling you.\n",
158 | "\n",
159 | "birds.aggregate(column=\"specimen_id\", using_func=len)"
160 | ]
161 | },
162 | {
163 | "cell_type": "code",
164 | "execution_count": null,
165 | "metadata": {},
166 | "outputs": [],
167 | "source": [
168 | "from statistics import median\n",
169 | "\n",
170 | "birds.aggregate(column=\"weight\", using_func=median)"
171 | ]
172 | },
173 | {
174 | "cell_type": "markdown",
175 | "metadata": {},
176 | "source": [
177 | "### Challenge: \n",
178 | "\n",
179 | "`GroupBy` also has several **convenience functions** that _call_ the aggregate function with methods that are commonly used for aggregating.\n",
180 | "\n",
181 | "Observe:"
182 | ]
183 | },
184 | {
185 | "cell_type": "code",
186 | "execution_count": null,
187 | "metadata": {},
188 | "outputs": [],
189 | "source": [
190 | "birds.average(column=\"weight\")"
191 | ]
192 | },
193 | {
194 | "cell_type": "code",
195 | "execution_count": null,
196 | "metadata": {},
197 | "outputs": [],
198 | "source": [
199 | "birds.count(column=\"specimen_id\")"
200 | ]
201 | },
202 | {
203 | "cell_type": "code",
204 | "execution_count": null,
205 | "metadata": {},
206 | "outputs": [],
207 | "source": [
208 | "# How many total ounces of bird we have in each species category\n",
209 | "# Not sure how this would be useful but there it is\n",
210 | "birds.sum(column=\"weight\")"
211 | ]
212 | },
213 | {
214 | "cell_type": "markdown",
215 | "metadata": {},
216 | "source": [
217 | "### Challenge\n",
218 | "\n",
219 | "Write some new convenience functions for for `GroupBy`: \n",
220 | "\n",
221 | "- `min`: aggregate by finding the smallest value\n",
222 | "- `max`: aggregate by finding the largest value\n",
223 | "- `spread`: aggregate by finding the difference between the largest and the smallest value "
224 | ]
225 | },
226 | {
227 | "cell_type": "code",
228 | "execution_count": null,
229 | "metadata": {},
230 | "outputs": [],
231 | "source": [
232 | "import sys\n",
233 | "!{sys.executable} -m pip install colorama \n",
234 | "\n",
235 | "sys.path.insert(0, '..')\n",
236 | "from test_framework_exercise.phoenix_test.matchers import FailedAssertion, Assertion, assert_that\n",
237 | "from test_framework_exercise.phoenix_test.test import Test\n",
238 | "sys.path.remove('..')\n",
239 | "\n",
240 | "class GroupByTest(Test):\n",
241 | " \n",
242 | " def test_min_function(self):\n",
243 | " assert_that(birds.min(column=\"weight\")).equals({'oriole': 4.17, 'bluejay': 4.85, 'titmouse': 2.13})\n",
244 | " \n",
245 | " def test_max_function(self):\n",
246 | " assert_that(birds.max(column=\"weight\")).equals({'oriole': 5.21, 'bluejay': 6.32, 'titmouse': 5.22})\n",
247 | " \n",
248 | " def test_spread_function(self):\n",
249 | " assert_that(birds.spread(column=\"weight\")).equals({'oriole': 1.04, 'bluejay': 1.4700000000000006, 'titmouse': 3.09})\n",
250 | " \n",
251 | "GroupByTest().run()"
252 | ]
253 | }
254 | ],
255 | "metadata": {
256 | "kernelspec": {
257 | "display_name": "Python 3",
258 | "language": "python",
259 | "name": "python3"
260 | },
261 | "language_info": {
262 | "codemirror_mode": {
263 | "name": "ipython",
264 | "version": 3
265 | },
266 | "file_extension": ".py",
267 | "mimetype": "text/x-python",
268 | "name": "python",
269 | "nbconvert_exporter": "python",
270 | "pygments_lexer": "ipython3",
271 | "version": "3.8.5"
272 | }
273 | },
274 | "nbformat": 4,
275 | "nbformat_minor": 4
276 | }
277 |
--------------------------------------------------------------------------------
/ch3_collections_and_functions/3.2_Sets.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Video Explanation [Available Here](https://www.youtube.com/watch?v=-M2Np1QDX_A)!\n",
8 | "\n",
9 | "\n",
10 | "### Sets \n",
11 | "\n",
12 | "A set is a collection of unordered, unique, immutable values."
13 | ]
14 | },
15 | {
16 | "cell_type": "code",
17 | "execution_count": null,
18 | "metadata": {},
19 | "outputs": [],
20 | "source": [
21 | "# Defining a set using '{...}' syntax \n",
22 | "colors={'red','black','white','blue'}\n",
23 | "colors "
24 | ]
25 | },
26 | {
27 | "cell_type": "code",
28 | "execution_count": null,
29 | "metadata": {},
30 | "outputs": [],
31 | "source": [
32 | "# Defining a set using the 'set(iterable)' syntax \n",
33 | "colors2=set([\"red\",\"blue\",\"black\",\"blue\",\"blue\"])\n",
34 | "\n",
35 | "# Notice there are no duplicates{'black','blue','red'}\n",
36 | "colors2"
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "execution_count": null,
42 | "metadata": {},
43 | "outputs": [],
44 | "source": [
45 | "#Note: You can't use a literal to create an empty set because Python thinks it's a dictionary\n",
46 | "\n",
47 | "new_variable = {}\n",
48 | "type(new_variable)"
49 | ]
50 | },
51 | {
52 | "cell_type": "code",
53 | "execution_count": null,
54 | "metadata": {},
55 | "outputs": [],
56 | "source": [
57 | "#Here is a hack to get around that\n",
58 | "\n",
59 | "new_variable = {1}\n",
60 | "new_variable.remove(1)\n",
61 | "type(new_variable)"
62 | ]
63 | },
64 | {
65 | "cell_type": "markdown",
66 | "metadata": {},
67 | "source": [
68 | "You can even convert a set from a string, though I confess I'm not clear why you would do this."
69 | ]
70 | },
71 | {
72 | "cell_type": "code",
73 | "execution_count": null,
74 | "metadata": {},
75 | "outputs": [],
76 | "source": [
77 | "#The following creates a set of single strings 'a','b','c','d','e'\n",
78 | "# and another set of single strings 'b','d','x','y','z'\n",
79 | "A = set('abcde')\n",
80 | "B = set('bdxyz')\n",
81 | "\n",
82 | "print(A)\n",
83 | "print(\"--\")\n",
84 | "print(B)"
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {},
90 | "source": [
91 | "### Set Theory Operations \n",
92 | "\n",
93 | "Sets are fundamentally mathematical in nature and contain operations based on set theory. They allow the following operations: \n",
94 | " \n",
95 | "### Union (``union()`` or ``|``}: A set containing all elements that are in both sets\n",
96 | " "
97 | ]
98 | },
99 | {
100 | "cell_type": "code",
101 | "execution_count": null,
102 | "metadata": {},
103 | "outputs": [],
104 | "source": [
105 | "# Union Operation \n",
106 | "new_set = A | B \n",
107 | "print(new_set)\n",
108 | "print('---')\n",
109 | "new_set = A.union(B) # Same operation as above but using method \n",
110 | "print(new_set)"
111 | ]
112 | },
113 | {
114 | "cell_type": "markdown",
115 | "metadata": {},
116 | "source": [
117 | "### Difference (``difference()`` or ``-``): A set that consists of elements that are in one set but not the other.\n",
118 | " \n",
119 | " **Fun language fact:** In Ruby, you can subtract Arrays: `arr = [1, 2, 3] - [1, 3]` will give you a, `arr` of `[2]` in Ruby. \n",
120 | " \n",
121 | " Python _does not_ support this: you have to convert the lists to sets in order to do this, so the same operation in Python would have to be `arr = list(set([1, 2, 3]) - set([1, 3]))`.\n",
122 | " \n",
123 | " Why do you think this is?"
124 | ]
125 | },
126 | {
127 | "cell_type": "code",
128 | "execution_count": null,
129 | "metadata": {},
130 | "outputs": [],
131 | "source": [
132 | "# Difference Operation \n",
133 | "new_set = A - B \n",
134 | "print(new_set)\n",
135 | "new_set = B.difference(A)\n",
136 | "print(new_set)"
137 | ]
138 | },
139 | {
140 | "cell_type": "markdown",
141 | "metadata": {},
142 | "source": [
143 | "### Intersection (``intersection`` or ``&``): A set that consists of all elements that are in both sets. "
144 | ]
145 | },
146 | {
147 | "cell_type": "code",
148 | "execution_count": null,
149 | "metadata": {},
150 | "outputs": [],
151 | "source": [
152 | "# Intersection Operation \n",
153 | "new_set = A & B \n",
154 | "print(new_set)\n",
155 | "print('---')\n",
156 | "new_set = A.intersection(B) # same operation as above but using method \n",
157 | "print(new_set)"
158 | ]
159 | },
160 | {
161 | "cell_type": "markdown",
162 | "metadata": {},
163 | "source": [
164 | "### Set Methods \n",
165 | "\n",
166 | "The set object provides methods that support set changes, in-place unions, and deletions of items from the set\n",
167 | "\n",
168 | "Documentation:https://docs.python.org/3/library/stdtypes.html#set13/30\n"
169 | ]
170 | },
171 | {
172 | "cell_type": "code",
173 | "execution_count": null,
174 | "metadata": {},
175 | "outputs": [],
176 | "source": [
177 | "letters={'a','b','c'} "
178 | ]
179 | },
180 | {
181 | "cell_type": "code",
182 | "execution_count": null,
183 | "metadata": {},
184 | "outputs": [],
185 | "source": [
186 | "# Add a new item to the set \n",
187 | "letters.add('d') \n",
188 | "letters"
189 | ]
190 | },
191 | {
192 | "cell_type": "code",
193 | "execution_count": null,
194 | "metadata": {},
195 | "outputs": [],
196 | "source": [
197 | "# Merge: This is a in-place union \n",
198 | "letters.update(set(['x','y','a','b']))\n",
199 | "letters "
200 | ]
201 | },
202 | {
203 | "cell_type": "code",
204 | "execution_count": null,
205 | "metadata": {},
206 | "outputs": [],
207 | "source": [
208 | "# Delete on item \n",
209 | "letters.remove('a') \n",
210 | "letters "
211 | ]
212 | },
213 | {
214 | "cell_type": "code",
215 | "execution_count": null,
216 | "metadata": {},
217 | "outputs": [],
218 | "source": [
219 | "# Simple iteration through a set using a for-loop \n",
220 | "letters = {'a','b','c'} \n",
221 | "for item in letters: \n",
222 | " print(item)"
223 | ]
224 | },
225 | {
226 | "cell_type": "markdown",
227 | "metadata": {},
228 | "source": [
229 | "### Immutable Constraints on Sets \n",
230 | "\n",
231 | "- Sets can only contain immutable (a.k.a. “hashable”) object types. \n",
232 | "- Lists and dictionaries cannot be embedded in sets, but tuples can if you need to store compound values"
233 | ]
234 | },
235 | {
236 | "cell_type": "code",
237 | "execution_count": null,
238 | "metadata": {},
239 | "outputs": [],
240 | "source": [
241 | "S = {1.23}"
242 | ]
243 | },
244 | {
245 | "cell_type": "code",
246 | "execution_count": null,
247 | "metadata": {},
248 | "outputs": [],
249 | "source": [
250 | "# Running this code section will through an error because lists are\n",
251 | "# not hashable types \n",
252 | "S.add([1,2,3])"
253 | ]
254 | },
255 | {
256 | "cell_type": "code",
257 | "execution_count": null,
258 | "metadata": {},
259 | "outputs": [],
260 | "source": [
261 | "# Running this code section will through an error because dictionaries are\n",
262 | "# not hashable types \n",
263 | "S.add({'a':1})"
264 | ]
265 | },
266 | {
267 | "cell_type": "code",
268 | "execution_count": null,
269 | "metadata": {},
270 | "outputs": [],
271 | "source": [
272 | "# This is the same for dictionary types. The keys must be immutable \n",
273 | "# therefore a key cannot be a list or another dictionary. \n",
274 | "d = {'a': 1, 'b':2}\n",
275 | "d[['a']] = 3"
276 | ]
277 | },
278 | {
279 | "cell_type": "code",
280 | "execution_count": null,
281 | "metadata": {},
282 | "outputs": [],
283 | "source": [
284 | "# However, tuples work because they immutable. \n",
285 | "S.add((1,2,3))\n",
286 | "S"
287 | ]
288 | },
289 | {
290 | "cell_type": "code",
291 | "execution_count": null,
292 | "metadata": {},
293 | "outputs": [],
294 | "source": [
295 | "# Sets themselves are mutable too, and so cannot be nested \n",
296 | "# in other sets directly.\n",
297 | "S.add(set((1,2,3)))\n",
298 | "S"
299 | ]
300 | },
301 | {
302 | "cell_type": "code",
303 | "execution_count": null,
304 | "metadata": {},
305 | "outputs": [],
306 | "source": [
307 | "# Use the built-in 'frozenset' function (creates an immutable set) \n",
308 | "# that can embedded other sets. Works just like sets\n",
309 | "f_set = frozenset([1,2,3])\n",
310 | "print(f_set) \n",
311 | "\n",
312 | "print(\"---\")\n",
313 | "S.add(f_set)\n",
314 | "print(S)"
315 | ]
316 | },
317 | {
318 | "cell_type": "code",
319 | "execution_count": null,
320 | "metadata": {},
321 | "outputs": [],
322 | "source": [
323 | "f_set.append(8)"
324 | ]
325 | },
326 | {
327 | "cell_type": "code",
328 | "execution_count": null,
329 | "metadata": {},
330 | "outputs": [],
331 | "source": []
332 | }
333 | ],
334 | "metadata": {
335 | "kernelspec": {
336 | "display_name": "Python 3",
337 | "language": "python",
338 | "name": "python3"
339 | },
340 | "language_info": {
341 | "codemirror_mode": {
342 | "name": "ipython",
343 | "version": 3
344 | },
345 | "file_extension": ".py",
346 | "mimetype": "text/x-python",
347 | "name": "python",
348 | "nbconvert_exporter": "python",
349 | "pygments_lexer": "ipython3",
350 | "version": "3.9.0"
351 | }
352 | },
353 | "nbformat": 4,
354 | "nbformat_minor": 4
355 | }
356 |
--------------------------------------------------------------------------------
/ch3_collections_and_functions/3.1_Dictionaries.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Video Explanation [Available Here](https://www.youtube.com/watch?v=bODBNuuJHlc)!\n",
8 | "\n",
9 | "\n",
10 | "### Dictionaries \n",
11 | "\n",
12 | "We already learned about lists, which allow you to store a collection of Python objects, indexed with an integer.\n",
13 | "\n",
14 | "A dictionary allows you to store a collection of Python objects indexed with _any_ hashable type (most of the time in practice, people use a string)."
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "#### Dictionary Literals \n",
22 | "\n",
23 | "  -- Learning Python 2013\n"
24 | ]
25 | },
26 | {
27 | "cell_type": "markdown",
28 | "metadata": {},
29 | "source": [
30 | "#### Dictionary Operations \n",
31 | "\n",
32 | "Basic dictionary operations include: \n",
33 | " - Accessing a value ``D[key]`` and modifying key-value pairs ``D[key]=new_value``.\n",
34 | " \n",
35 | " - Retrieving the length (``len``), key membership checking (``in``), and creating lists (``list``)\n",
36 | " "
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "execution_count": null,
42 | "metadata": {},
43 | "outputs": [],
44 | "source": [
45 | "# Creating a dictionary literal \n",
46 | "test_averages={'test1':84, 'test2':76, 'test3':94}"
47 | ]
48 | },
49 | {
50 | "cell_type": "code",
51 | "execution_count": null,
52 | "metadata": {},
53 | "outputs": [],
54 | "source": [
55 | "# Accessing a value \n",
56 | "test_averages['test1']"
57 | ]
58 | },
59 | {
60 | "cell_type": "markdown",
61 | "metadata": {},
62 | "source": [
63 | "If you try to access a key that isn't in the dictionary, you'll get a `KeyError`"
64 | ]
65 | },
66 | {
67 | "cell_type": "code",
68 | "execution_count": null,
69 | "metadata": {},
70 | "outputs": [],
71 | "source": [
72 | "test_averages['test4']"
73 | ]
74 | },
75 | {
76 | "cell_type": "markdown",
77 | "metadata": {},
78 | "source": [
79 | "You can use the `get` method instead, which returns None if the key isn't in the dictionary."
80 | ]
81 | },
82 | {
83 | "cell_type": "code",
84 | "execution_count": null,
85 | "metadata": {},
86 | "outputs": [],
87 | "source": [
88 | "print(test_averages.get('test4'))"
89 | ]
90 | },
91 | {
92 | "cell_type": "markdown",
93 | "metadata": {},
94 | "source": [
95 | "You can even give it a default value to return instead in that case:"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": null,
101 | "metadata": {},
102 | "outputs": [],
103 | "source": [
104 | "print(test_averages.get('test5', 'DEFAULT!'))"
105 | ]
106 | },
107 | {
108 | "cell_type": "code",
109 | "execution_count": null,
110 | "metadata": {},
111 | "outputs": [],
112 | "source": [
113 | "# Changing a key's value\n",
114 | "test_averages['test3'] = 96"
115 | ]
116 | },
117 | {
118 | "cell_type": "code",
119 | "execution_count": null,
120 | "metadata": {},
121 | "outputs": [],
122 | "source": [
123 | "# Now we see the update to the dictionary \n",
124 | "test_averages"
125 | ]
126 | },
127 | {
128 | "cell_type": "code",
129 | "execution_count": null,
130 | "metadata": {},
131 | "outputs": [],
132 | "source": [
133 | "# Using 'in' checks to see if a key inside the dictionary \n",
134 | "print('test2' in test_averages)\n",
135 | "\n",
136 | "# 'Bob' is not a key in the test_averages dictionary\n",
137 | "print('Bob' in test_averages)\n",
138 | "\n",
139 | "# This is false because 96 is a value in the dictionary and not a key!\n",
140 | "print(96 in test_averages)"
141 | ]
142 | },
143 | {
144 | "cell_type": "code",
145 | "execution_count": null,
146 | "metadata": {},
147 | "outputs": [],
148 | "source": [
149 | "# Number of (key,value) entries in the dictionary \n",
150 | "len(test_averages)"
151 | ]
152 | },
153 | {
154 | "cell_type": "code",
155 | "execution_count": null,
156 | "metadata": {},
157 | "outputs": [],
158 | "source": [
159 | "# Create a list of keys. Use the .keys method to retrieve all the keys \n",
160 | "# in the dictionary \n",
161 | "keys = list(test_averages.keys())\n",
162 | "print(keys)\n",
163 | "print('---')\n",
164 | "\n",
165 | "# Create a list of values. Use the .values method to retrieve all the keys \n",
166 | "# in the dictionary \n",
167 | "values = list(test_averages.values())\n",
168 | "print(values)\n"
169 | ]
170 | },
171 | {
172 | "cell_type": "markdown",
173 | "metadata": {},
174 | "source": [
175 | "#### Mutability of Dictionaries\n",
176 | "\n",
177 | "Dictionaries are mutable, so you can change, expand, and shrink them in place without making new dictionaries."
178 | ]
179 | },
180 | {
181 | "cell_type": "code",
182 | "execution_count": null,
183 | "metadata": {},
184 | "outputs": [],
185 | "source": [
186 | "# Lets a define a new dictionary \n",
187 | "D = {'eggs': 3, 'spam':2, 'ham': 1}"
188 | ]
189 | },
190 | {
191 | "cell_type": "code",
192 | "execution_count": null,
193 | "metadata": {},
194 | "outputs": [],
195 | "source": [
196 | "# Change an entry, we already saw this above\n",
197 | "D['ham'] = ['grill','bake','fry']\n",
198 | "D"
199 | ]
200 | },
201 | {
202 | "cell_type": "code",
203 | "execution_count": null,
204 | "metadata": {},
205 | "outputs": [],
206 | "source": [
207 | "# Delete an entry in the dictionary \n",
208 | "# Syntax: del dictionary_name[key]\n",
209 | "del D['eggs']\n",
210 | "D"
211 | ]
212 | },
213 | {
214 | "cell_type": "code",
215 | "execution_count": null,
216 | "metadata": {},
217 | "outputs": [],
218 | "source": [
219 | "# Add a new entry is just the same syntax as updating an entry \n",
220 | "# We are going to add 'brunch' as a key and the value of 'Bacon'\n",
221 | "D['brunch'] = 'Bacon'\n",
222 | "D"
223 | ]
224 | },
225 | {
226 | "cell_type": "code",
227 | "execution_count": null,
228 | "metadata": {},
229 | "outputs": [],
230 | "source": [
231 | "### For loop idioms with dictionaries \n",
232 | "test_averages={'test1':84,'test2':76,'test3':94}\n",
233 | "\n",
234 | "# For loop 'in' idiom returns all the keys in the dictionary \n",
235 | "for key in test_averages:\n",
236 | " print(key)"
237 | ]
238 | },
239 | {
240 | "cell_type": "code",
241 | "execution_count": null,
242 | "metadata": {},
243 | "outputs": [],
244 | "source": [
245 | "# Use the .items() method to return the key-value pair entries \n",
246 | "for key, value in test_averages.items():\n",
247 | " fmt_str = f'Key = {key}, value = {value}'\n",
248 | " print(fmt_str)"
249 | ]
250 | },
251 | {
252 | "cell_type": "markdown",
253 | "metadata": {},
254 | "source": [
255 | "#### Dictionary methods \n",
256 | "\n",
257 | "  -- Learning Python 2013\n",
258 | " \n",
259 | "Documentation:https://docs.python.org/3/library/stdtypes.html#typesmapping2Source: \n"
260 | ]
261 | },
262 | {
263 | "cell_type": "markdown",
264 | "metadata": {},
265 | "source": [
266 | "#### Dictionary View Objects \n",
267 | "\n",
268 | "The objects returned by ``dict.keys()``, ``dict.values()`` and ``dict.items()`` are *view objects*:\n",
269 | "\n",
270 | " - Provide a dynamic view on the dictionary’s entries, which means that when the dictionary changes the view reflects these changes.\n",
271 | " \n",
272 | " - Advantage to these views is that they require a small and fixed amount of memory and processor time."
273 | ]
274 | },
275 | {
276 | "cell_type": "code",
277 | "execution_count": null,
278 | "metadata": {},
279 | "outputs": [],
280 | "source": [
281 | "dishes = {'eggs':2,'sausage':1,'bacon':1,'spam':500}"
282 | ]
283 | },
284 | {
285 | "cell_type": "code",
286 | "execution_count": null,
287 | "metadata": {},
288 | "outputs": [],
289 | "source": [
290 | "# Keys is a view object of the keys from the dishes dictionary\n",
291 | "keys = dishes.keys() \n",
292 | "values = dishes.values() \n",
293 | "items = dishes.items() \n",
294 | "\n",
295 | "print(keys)\n",
296 | "print(values)\n",
297 | "print(items)"
298 | ]
299 | },
300 | {
301 | "cell_type": "code",
302 | "execution_count": null,
303 | "metadata": {},
304 | "outputs": [],
305 | "source": [
306 | "# View objects are dynamic and reflect dictionary changes \n",
307 | "\n",
308 | "# Lets delete the 'eggs' entry \n",
309 | "del dishes['eggs']\n",
310 | "\n",
311 | "# Notice the both the views have removed key and its value \n",
312 | "print(keys)\n",
313 | "print(values)\n",
314 | "print(items)"
315 | ]
316 | },
317 | {
318 | "cell_type": "code",
319 | "execution_count": null,
320 | "metadata": {},
321 | "outputs": [],
322 | "source": []
323 | }
324 | ],
325 | "metadata": {
326 | "kernelspec": {
327 | "display_name": "Python 3",
328 | "language": "python",
329 | "name": "python3"
330 | },
331 | "language_info": {
332 | "codemirror_mode": {
333 | "name": "ipython",
334 | "version": 3
335 | },
336 | "file_extension": ".py",
337 | "mimetype": "text/x-python",
338 | "name": "python",
339 | "nbconvert_exporter": "python",
340 | "pygments_lexer": "ipython3",
341 | "version": "3.9.0"
342 | }
343 | },
344 | "nbformat": 4,
345 | "nbformat_minor": 1
346 | }
347 |
--------------------------------------------------------------------------------