├── 2nd-Loop ├── CHPT-01-Numeric-Types │ ├── Exer-01-Number-guessing-game │ │ ├── Number-guessing-game.py │ │ ├── Number-guessing-game_BTE_1.py │ │ ├── Number-guessing-game_BTE_3.py │ │ └── README.md │ ├── Exer-02-Summing-numbers │ │ ├── README.md │ │ ├── summing-numbers.py │ │ ├── summing-numbers_BTE_1.py │ │ ├── summing-numbers_BTE_2.py │ │ ├── summing-numbers_BTE_3.py │ │ └── summing-numbers_BTE_4.py │ ├── Exer-03-Run-timing │ │ ├── README.md │ │ ├── run-timing-BTE-1.py │ │ ├── run-timing-BTE-2.py │ │ └── run-timing.py │ ├── Exer-04-Hexadecimal-output │ │ ├── README.md │ │ ├── hexadecimal-output.py │ │ └── hexadecimal-output_BTE_1.py │ └── README.md ├── CHPT-02-Strings │ ├── Exer-05-Pig-Latin │ │ ├── C5-Handle-capitalized-words.py │ │ ├── C5-oig-latin-alternative_vers.py │ │ ├── README.md │ │ └── pig_latin.py │ ├── Exer-06-Pig-Latin-sentence │ │ ├── README.md │ │ ├── pig-latin-sentence-BTE-1.py │ │ ├── pig-latin-sentence-BTE-2-alternative-solution-2.py │ │ ├── pig-latin-sentence-BTE-2-alternative-solution.py │ │ ├── pig-latin-sentence-BTE-2.py │ │ └── pig-latin-sentence.py │ ├── Exer-07-Ubbi-Dubbi │ │ ├── README.md │ │ ├── ubbi-dubbi-BTE-1.py │ │ ├── ubbi-dubbi-BTE-2.py │ │ ├── ubbi-dubbi-BTE-3.py │ │ ├── ubbi-dubbi-BTE-3_alternative_method.py │ │ └── ubbi-dubbi.py │ ├── Exer-08-Sorting-a-string │ │ ├── README.md │ │ ├── sorting-a-string-BTE-1.py │ │ ├── sorting-a-string-BTE-2.py │ │ ├── sorting-a-string-BTE-3.py │ │ └── sorting-a-string.py │ └── README.md ├── CHPT-03-Lists-and-tuples │ ├── Exer-09-First-last │ │ ├── README.md │ │ ├── firstlast-BTE-1.py │ │ ├── firstlast-BTE-2.py │ │ ├── firstlast-BTE-3.py │ │ ├── firstlast-BTE-4.py │ │ ├── firstlast-BTE-5.py │ │ ├── firstlast-BTE-6.py │ │ └── firstlast.py │ ├── Exer-10-Summing-anything │ │ ├── README.md │ │ ├── mysum.py │ │ ├── mysum_BTE_1.py │ │ ├── mysum_BTE_2.py │ │ ├── mysum_BTE_2_alternative_solution.py │ │ ├── mysum_BTE_3.py │ │ └── mysum_BTE_3_alternative_solution.py │ ├── Exer-11-Alphabetizing-names │ │ ├── README.md │ │ ├── alphabetize_names.py │ │ ├── alphabetize_names_BTE_1.py │ │ ├── alphabetize_names_BTE_2.py │ │ ├── alphabetize_names_BTE_2_alternative_solution.py │ │ ├── alphabetize_names_BTE_2_alternative_solution_2.py │ │ └── alphabetize_names_BTE_3.py │ ├── Exer-12-Word-with-most-repeated-letters │ │ ├── README.md │ │ ├── most_repeating_word.py │ │ ├── most_repeating_word_BTE_1.py │ │ ├── most_repeating_word_BTE_1_alternative_solution.py │ │ ├── most_repeating_word_BTE_1_alternative_solution_2.py │ │ └── most_repeating_word_BTE_2.py │ ├── Exer-13-Printing-tuple-records │ │ ├── BTE_1.py │ │ ├── BTE_1_alternative_version.py │ │ ├── BTE_2.py │ │ ├── README.md │ │ └── format_sort_records.py │ └── README.md ├── CHPT-04-Dictionaries-and-sets │ ├── Exer-14-Restaurant │ │ ├── README.md │ │ ├── restaurant.py │ │ ├── restaurant_BTE_1.py │ │ ├── restaurant_BTE_1_alternative_solution.py │ │ ├── restaurant_BTE_2.py │ │ └── restaurant_BTE_3.py │ ├── Exer-15-Rainfall │ │ ├── README.md │ │ ├── rainfall.py │ │ ├── rainfall_BTE_1.py │ │ ├── rainfall_BTE_2.py │ │ ├── rainfall_BTE_3.py │ │ └── rainfall_alternative_solution.py │ ├── Exer-16-Dictdiff │ │ ├── README.md │ │ ├── dictdiff.py │ │ ├── dictdiff_BTE_1.py │ │ ├── dictdiff_BTE_1_alternative_solution.py │ │ ├── dictdiff_BTE_2.py │ │ └── dictdiff_BTE_3.py │ ├── Exer-17-How-many-different-numbers │ │ ├── README.md │ │ ├── how_many_different_numbers.py │ │ ├── how_many_different_numbers_BTE_1.py │ │ ├── how_many_different_numbers_BTE_2.py │ │ └── how_many_different_numbers_BTE_3.py │ └── README.md ├── CHPT-05-Files │ ├── Exer-18-Final-line │ │ ├── README.md │ │ ├── get_final_line.py │ │ ├── get_final_line_BTE_1.py │ │ ├── get_final_line_BTE_1_alternative_solution.py │ │ ├── get_final_line_BTE_2.py │ │ ├── get_final_line_BTE_3.py │ │ ├── get_final_line_BTE_3_alternative_solution.py │ │ ├── get_final_line_alternative_solution.py │ │ └── get_final_line_alternative_solution_2.py │ ├── Exer-19-etc-passwd-to-dict │ │ ├── README.md │ │ ├── passwd_to_dict.py │ │ ├── passwd_to_dict_BTE_1.py │ │ ├── passwd_to_dict_BTE_2.py │ │ ├── passwd_to_dict_BTE_3.py │ │ └── passwd_to_dict_alternative_solution.py │ ├── Exer-20-Word-count │ │ ├── README.md │ │ ├── wcount.py │ │ ├── wcount_BTE_1.py │ │ ├── wcount_BTE_2_alternative_solution.py │ │ └── wcount_BTE_2_alternative_solution_2.py │ ├── Exer-21-Longest-word-per-file │ │ ├── README.md │ │ ├── longest_word.py │ │ ├── longest_word_BTE_2.py │ │ └── longest_word_BTE_3.py │ ├── Exer-22-Reading-and-writing-CSV │ │ ├── README.md │ │ ├── passwd_to_csv.py │ │ ├── passwd_to_csv_BTE_1.py │ │ ├── passwd_to_csv_BTE_2.py │ │ └── passwd_to_csv_BTE_3.py │ ├── Exer-23-JSON │ │ ├── README.md │ │ ├── print_scores.py │ │ ├── print_scores_BTE_1.py │ │ ├── print_scores_BTE_2.py │ │ └── print_scores_BTE_3.py │ ├── Exer-24-Reverse-lines │ │ ├── README.md │ │ ├── reverse_lines.py │ │ ├── reverse_lines_BTE_1.py │ │ ├── reverse_lines_BTE_2.py │ │ └── reverse_lines_BTE_3.py │ └── README.md ├── CHPT-06-Functions │ ├── Exer-25-XML-generator │ │ ├── README.md │ │ ├── myxml.py │ │ ├── myxml_BTE_1.py │ │ ├── myxml_BTE_1_alternative_solution.py │ │ ├── myxml_BTE_2.py │ │ ├── myxml_BTE_3.py │ │ └── myxml_alternative_solution.py │ ├── Exer-26-Prefix-notation-calculator │ │ ├── README.md │ │ ├── calc.py │ │ ├── calc_BTE_1.py │ │ ├── calc_BTE_2.py │ │ ├── calc_BTE_2_alternative_solution.py │ │ ├── calc_BTE_3.py │ │ └── calc_BTE_3_alternative_solution.py │ ├── Exer-27-Password-generator │ │ ├── README.md │ │ ├── create_password_generator.py │ │ ├── create_password_generator_BTE_1.py │ │ ├── create_password_generator_BTE_2.py │ │ └── create_password_generator_BTE_3.py │ └── README.md ├── CHPT-07-Functional-programming-with-comprehensions │ ├── Exer-28-Join-numbers │ │ ├── README.md │ │ ├── join_numbers.py │ │ ├── join_numbers_BTE_1.py │ │ ├── join_numbers_BTE_2.py │ │ └── join_numbers_BTE_3.py │ ├── Exer-29-Add-numbers │ │ ├── README.md │ │ ├── add_numbers.py │ │ ├── add_numbers_BTE_1.py │ │ └── add_numbers_BTE_3.py │ ├── Exer-30-Flatten-a-list │ │ ├── README.md │ │ ├── flatten.py │ │ ├── flatten_BTE_1.py │ │ ├── flatten_BTE_2.py │ │ └── flatten_BTE_3.py │ ├── Exer-31-Pig-Latin-translation-of-a-file │ │ ├── README.md │ │ ├── plfile.py │ │ ├── plfile_BTE_1.py │ │ ├── plfile_BTE_2.py │ │ ├── plfile_BTE_3.py │ │ └── plfile_BTE_3_alternative_solution.py │ ├── Exer-32-Flip-a-dict │ │ ├── README.md │ │ ├── flipped_dict.py │ │ ├── flipped_dict_BTE_1.py │ │ ├── flipped_dict_BTE_2.py │ │ └── flipped_dict_BTE_3.py │ ├── Exer-33-Transform-values │ │ ├── README.md │ │ ├── transform_values.py │ │ ├── transform_values_BTE_1.py │ │ ├── transform_values_BTE_2.py │ │ ├── transform_values_BTE_2_alternative_solution.py │ │ └── transform_values_BTE_3.py │ ├── Exer-34-Almost-supervocalic-words │ │ ├── README.md │ │ ├── get_sv.py │ │ ├── get_sv_BTE_1.py │ │ ├── get_sv_BTE_2.py │ │ └── get_sv_BTE_3.py │ ├── Exer-35-A-Gematria-Part-1 │ │ ├── README.md │ │ ├── gematria_dict.py │ │ ├── gematria_dict_BTE_1.py │ │ ├── gematria_dict_BTE_2.py │ │ ├── gematria_dict_BTE_3.py │ │ └── gematria_dict_BTE_3_alternative_solution.py │ ├── Exer-35-B-Gematria-Part-2 │ │ ├── README.md │ │ ├── gematria_equal_words.py │ │ ├── gematria_equal_words_BTE_1.py │ │ ├── gematria_equal_words_BTE_2.py │ │ └── gematria_equal_words_BTE_3.py │ └── README.md ├── CHPT-08-Modules-and-packages │ ├── Exer-36-Sales-tax │ │ ├── README.md │ │ ├── freedonia.py │ │ ├── sales_tax_BTE_1.py │ │ ├── sales_tax_BTE_2.py │ │ ├── sales_tax_BTE_3.py │ │ └── using_freedonia_as_module.py │ ├── Exer-37-Menu │ │ ├── README.md │ │ ├── menu.py │ │ ├── menu_BTE_1.py │ │ ├── menu_BTE_2.py │ │ ├── menu_BTE_3.py │ │ ├── using_menu_BTE_3.py │ │ └── using_menu_as _module.py │ └── README.md ├── CHPT-09-Objects │ ├── Exer-38-Ice-cream-scoop │ │ ├── README.md │ │ ├── scoop.py │ │ ├── scoop_BTE_1.py │ │ ├── scoop_BTE_2.py │ │ └── scoop_BTE_3.py │ ├── Exer-39-Ice-cream-bowl │ │ ├── README.md │ │ ├── ice_cream_bowl.py │ │ ├── ice_cream_bowl_BTE_1.py │ │ ├── ice_cream_bowl_BTE_2.py │ │ └── ice_cream_bowl_BTE_3.py │ ├── Exer-40-Ice-cream-bowl-with-limits │ │ ├── README.md │ │ ├── ice_cream_bowl_with_limits.py │ │ ├── ice_cream_bowl_with_limits_BTE_1.py │ │ ├── ice_cream_bowl_with_limits_BTE_2.py │ │ └── ice_cream_bowl_with_limits_BTE_3.py │ ├── Exer-41-A-bigger-bowl │ │ ├── BTE_1.py │ │ ├── BTE_2.py │ │ ├── BTE_3.py │ │ ├── README.md │ │ ├── bigger_bowl.py │ │ └── person_class.py │ ├── Exer-42-FlexibleDict │ │ ├── FlexibleDict.py │ │ ├── FlexibleDict_BTE_1.py │ │ ├── FlexibleDict_BTE_2.py │ │ ├── FlexibleDict_BTE_3.py │ │ └── README.md │ ├── Exer-43-Animals │ │ ├── README.md │ │ ├── animals.py │ │ ├── animals_BTE_1.py │ │ ├── animals_BTE_2.py │ │ └── animals_BTE_3.py │ ├── Exer-44-Cage │ │ ├── BTE_1.py │ │ ├── BTE_2.py │ │ ├── BTE_3.py │ │ ├── README.md │ │ └── cage.py │ ├── Exer-45-Zoo │ │ ├── README.md │ │ ├── zoo.py │ │ ├── zoo_BTE_1.py │ │ ├── zoo_BTE_2.py │ │ └── zoo_BTE_3.py │ └── README.md ├── CHPT-10-Iterators-and-generators │ ├── Exer-46-MyEnumerate │ │ ├── README.md │ │ ├── louditerator_class.py │ │ ├── myenumerate.py │ │ ├── myenumerate_BTE_1.py │ │ ├── myenumerate_BTE_2.py │ │ └── myenumerate_BTE_3.py │ ├── Exer-47-Circle │ │ ├── README.md │ │ ├── circle.py │ │ ├── circle_BTE_1.py │ │ ├── circle_BTE_2.py │ │ └── circle_BTE_3.py │ ├── Exer-48-All-lines-all-files │ │ ├── README.md │ │ ├── all_lines.py │ │ ├── all_lines_BTE_1.py │ │ ├── all_lines_BTE_2.py │ │ └── all_lines_BTE_3.py │ ├── Exer-49-Elapsed-since │ │ ├── README.md │ │ ├── elapsed_since.py │ │ ├── elapsed_since_BTE_1.py │ │ ├── elapsed_since_BTE_2.py │ │ └── elapsed_since_BTE_3.py │ ├── Exer-50-MyChain │ │ ├── README.md │ │ └── mychain.py │ └── README.md └── README.md ├── CHPT-01-Numeric-Types ├── Exer-01-Number-guessing-game │ ├── Exer-01-Number-guessing-game.ipynb │ ├── Number-guessing-game.py │ ├── Number-guessing-game_BTE_1.py │ ├── Number-guessing-game_BTE_3.py │ └── README.md ├── Exer-02-Summing-numbers │ ├── README.md │ ├── summing-numbers.py │ ├── summing-numbers_BTE_1.py │ ├── summing-numbers_BTE_2.py │ ├── summing-numbers_BTE_3.py │ └── summing-numbers_BTE_4.py ├── Exer-03-Run-timing │ ├── README.md │ ├── run-timing-BTE-1.py │ ├── run-timing-BTE-2.py │ └── run-timing.py ├── Exer-04-Hexadecimal-output │ ├── README.md │ ├── hexadecimal-output.py │ └── hexadecimal-output_BTE_1.py └── README.md ├── CHPT-02-Strings ├── Exer-05-Pig-Latin │ ├── C5-Handle-capitalized-words.py │ ├── C5-oig-latin-alternative_vers.py │ ├── README.md │ └── pig_latin.py ├── Exer-06-Pig-Latin-sentence │ ├── README.md │ ├── pig-latin-sentence-BTE-1.py │ ├── pig-latin-sentence-BTE-2-alternative-solution-2.py │ ├── pig-latin-sentence-BTE-2-alternative-solution.py │ ├── pig-latin-sentence-BTE-2.py │ └── pig-latin-sentence.py ├── Exer-07-Ubbi-Dubbi │ ├── README.md │ ├── ubbi-dubbi-BTE-1.py │ ├── ubbi-dubbi-BTE-2.py │ ├── ubbi-dubbi-BTE-3.py │ ├── ubbi-dubbi-BTE-3_alternative_method.py │ └── ubbi-dubbi.py ├── Exer-08-Sorting-a-string │ ├── README.md │ ├── my_text.txt │ ├── sorting-a-string-BTE-1.py │ ├── sorting-a-string-BTE-2.py │ ├── sorting-a-string-BTE-3.py │ └── sorting-a-string.py └── README.md ├── CHPT-03-Lists-and-tuples ├── Exer-09-First-last │ ├── README.md │ ├── firstlast-BTE-1.py │ ├── firstlast-BTE-2.py │ ├── firstlast-BTE-3.py │ ├── firstlast-BTE-4.py │ ├── firstlast-BTE-5.py │ ├── firstlast-BTE-6.py │ └── firstlast.py ├── Exer-10-Summing-anything │ ├── README.md │ ├── mysum.py │ ├── mysum_BTE_1.py │ ├── mysum_BTE_2.py │ ├── mysum_BTE_2_alternative_solution.py │ ├── mysum_BTE_3.py │ └── mysum_BTE_3_alternative_solution.py ├── Exer-11-Alphabetizing-names │ ├── README.md │ ├── alphabetize_names.py │ ├── alphabetize_names_BTE_1.py │ ├── alphabetize_names_BTE_2.py │ ├── alphabetize_names_BTE_2_alternative_solution.py │ ├── alphabetize_names_BTE_2_alternative_solution_2.py │ └── alphabetize_names_BTE_3.py ├── Exer-12-Word-with-most-repeated-letters │ ├── README.md │ ├── most_repeating_word.py │ ├── most_repeating_word_BTE_1.py │ ├── most_repeating_word_BTE_1_alternative_solution.py │ └── most_repeating_word_BTE_1_alternative_solution_2.py ├── Exer-13-Printing-tuple-records │ ├── BTE_1.py │ ├── BTE_1_alternative_version.py │ ├── BTE_2.py │ ├── README.md │ └── format_sort_records.py └── README.md ├── CHPT-04-Dictionaries-and-sets ├── Exer-14-Restaurant │ ├── BTE_2.py │ ├── README.md │ ├── restaurant.py │ ├── restaurant_BTE_1.py │ └── restaurant_BTE_1_alternative_solution.py ├── Exer-15-Rainfall │ ├── README.md │ ├── log_file.txt │ ├── rainfall.py │ ├── rainfall_BTE_1.py │ ├── rainfall_BTE_2.py │ ├── rainfall_BTE_3.py │ ├── rainfall_alternative_solution.py │ └── txt_file.txt ├── Exer-16-Dictdiff │ ├── README.md │ ├── dictdiff.py │ ├── dictdiff_BTE_1.py │ ├── dictdiff_BTE_1_alternative_solution.py │ ├── dictdiff_BTE_2.py │ └── dictdiff_BTE_3.py ├── Exer-17-How-many-different-numbers │ ├── README.md │ ├── how_many_different_numbers.py │ ├── how_many_different_numbers_BTE_1.py │ ├── how_many_different_numbers_BTE_2.py │ ├── how_many_different_numbers_BTE_3.py │ └── log_file.txt └── README.md ├── CHPT-05-Files ├── Exer-18-Final-line │ ├── README.md │ ├── get_final_line.py │ ├── get_final_line_BTE_1.py │ ├── get_final_line_BTE_1_alternative_solution.py │ ├── get_final_line_BTE_2.py │ ├── get_final_line_BTE_3.py │ ├── get_final_line_BTE_3_alternative_solution.py │ ├── get_final_line_alternative_solution.py │ ├── get_final_line_alternative_solution_2.py │ ├── num_file.txt │ └── sonnet_126.txt ├── Exer-19-etc-passwd-to-dict │ ├── README.md │ ├── passwd.txt │ ├── passwd_to_dict.py │ └── passwd_to_dict_alternative_solution.py ├── Exer-20-Word-count │ ├── README.md │ ├── wcount.py │ ├── wcount_BTE_1.py │ ├── wcount_BTE_2.py │ ├── wcount_BTE_2_alternative_solution.py │ ├── wcount_BTE_2_alternative_solution_2.py │ └── wcountfile.txt ├── Exer-21-Longest-word-per-file │ ├── README.md │ ├── longest_word.py │ ├── longest_word_BTE_2.py │ ├── longest_word_BTE_3.py │ ├── mini-access-log.txt │ ├── txt_1.txt │ ├── txt_2.txt │ └── txt_3.txt ├── Exer-22-Reading-and-writing-CSV │ ├── README.md │ ├── linux-etc-passwd.txt │ ├── passwd.csv │ ├── passwd_to_csv.py │ ├── passwd_to_csv_BTE_1.py │ ├── passwd_to_csv_BTE_2.py │ └── passwd_to_csv_BTE_3.py ├── Exer-23-JSON │ ├── README.md │ ├── linux-etc-passwd.txt │ ├── print_scores.py │ ├── print_scores_BTE_1.py │ ├── print_scores_BTE_2.py │ ├── print_scores_BTE_3.py │ └── scores │ │ ├── 10a.json │ │ ├── 9a.json │ │ ├── 9b.json │ │ └── README.md ├── Exer-24-Reverse-lines │ ├── README.md │ ├── data_vwl.txt │ ├── linux-etc-passwd.txt │ ├── reverse_lines.py │ ├── reverse_lines_BTE_1.py │ ├── reverse_lines_BTE_2.py │ └── reverse_lines_BTE_3.py └── README.md ├── CHPT-06-Functions ├── Exer-25-XML-generator │ ├── README.md │ ├── myxml.py │ ├── myxml_BTE_1.py │ ├── myxml_BTE_1_alternative_solution.py │ ├── myxml_BTE_2.py │ ├── myxml_BTE_3.py │ ├── myxml_alternative_solution.py │ └── sonnet_126.txt ├── Exer-26-Prefix-notation-calculator │ ├── README.md │ ├── calc.py │ ├── calc_BTE_1.py │ ├── calc_BTE_2.py │ ├── calc_BTE_2_alternative_solution.py │ ├── calc_BTE_3.py │ ├── calc_BTE_3_alternative_solution.py │ └── sonnet_126.txt ├── Exer-27-Password-generator │ ├── README.md │ ├── create_password_generator.py │ ├── create_password_generator_BTE_1.py │ ├── create_password_generator_BTE_2.py │ └── create_password_generator_BTE_3.py └── README.md ├── CHPT-07-Functional-programming-with-comprehensions ├── Exer-28-Join-numbers │ ├── README.md │ ├── join_numbers.py │ ├── join_numbers_BTE_1.py │ ├── join_numbers_BTE_2.py │ ├── join_numbers_BTE_3.py │ └── text.txt ├── Exer-29-Add-numbers │ ├── README.md │ ├── add_numbers.py │ ├── add_numbers_BTE_1.py │ ├── add_numbers_BTE_3.py │ └── text.txt ├── Exer-30-Flatten-a-list │ ├── Figure_7_1.PNG │ ├── README.md │ ├── flatten.py │ ├── flatten_BTE_1.py │ ├── flatten_BTE_2.py │ └── flatten_BTE_3.py ├── Exer-31-Pig-Latin-translation-of-a-file │ ├── README.md │ ├── plfile.py │ ├── plfile_BTE_1.py │ ├── plfile_BTE_2.py │ ├── plfile_BTE_3.py │ └── plfile_BTE_3_alternative_solution.py ├── Exer-32-Flip-a-dict │ ├── README.md │ ├── flipped_dict.py │ ├── flipped_dict_BTE_1.py │ ├── flipped_dict_BTE_2.py │ ├── flipped_dict_BTE_3.py │ └── my_data_dir │ │ ├── README.md │ │ ├── config_file │ │ ├── sonnet_1.txt │ │ ├── sonnet_2.txt │ │ ├── sonnet_3.txt │ │ └── sonnet_4.txt ├── Exer-33-Transform-values │ ├── README.md │ ├── transform_values.py │ ├── transform_values_BTE_1.py │ ├── transform_values_BTE_2.py │ ├── transform_values_BTE_2_alternative_solution.py │ ├── transform_values_BTE_3.py │ ├── user_db_with_com.txt │ └── user_db_without_com.txt ├── Exer-34-Almost-supervocalic-words │ ├── README.md │ ├── get_sv.py │ ├── get_sv_BTE_1.py │ ├── get_sv_BTE_2.py │ ├── get_sv_BTE_3.py │ ├── user_db_with_com.txt │ └── words.txt ├── Exer-35-A-Gematria-Part-1 │ ├── README.md │ ├── cities.json │ ├── config.txt │ ├── gematria_dict.py │ ├── gematria_dict_BTE_1.py │ ├── gematria_dict_BTE_2.py │ ├── gematria_dict_BTE_3.py │ └── gematria_dict_BTE_3_alternative_solution.py ├── Exer-35-B-Gematria-Part-2 │ ├── README.md │ ├── gematria_equal_words.py │ ├── gematria_equal_words_BTE_1.py │ ├── gematria_equal_words_BTE_2.py │ ├── gematria_equal_words_BTE_3.py │ └── words.txt └── README.md ├── CHPT-08-Modules-and-packages ├── Exer-36-Sales-tax │ ├── README.md │ ├── freedonia.py │ ├── sales_tax_BTE_1.py │ ├── sales_tax_BTE_2.py │ ├── sales_tax_BTE_3.py │ └── using_freedonia_as_module.py ├── Exer-37-Menu │ ├── README.md │ ├── menu.py │ ├── menu_BTE_1.py │ └── using_menu_as _module.py └── README.md ├── CHPT-09-Objects ├── Exer-38-Ice-cream-scoop │ ├── README.md │ ├── scoop.py │ ├── scoop_BTE_1.py │ ├── scoop_BTE_2.py │ └── scoop_BTE_3.py ├── Exer-39-Ice-cream-bowl │ ├── README.md │ ├── ice_cream_bowl.py │ ├── ice_cream_bowl_BTE_1.py │ ├── ice_cream_bowl_BTE_2.py │ └── ice_cream_bowl_BTE_3.py ├── Exer-40-Ice-cream-bowl-with-limits │ ├── README.md │ ├── ice_cream_bowl_with_limits.py │ ├── ice_cream_bowl_with_limits_BTE_1.py │ ├── ice_cream_bowl_with_limits_BTE_2.py │ └── ice_cream_bowl_with_limits_BTE_3.py ├── Exer-41-A-bigger-bowl │ ├── BTE_1.py │ ├── BTE_2.py │ ├── BTE_3.py │ ├── README.md │ ├── bigger_bowl.py │ └── person_class.py ├── Exer-42-FlexibleDict │ ├── FlexibleDict.py │ ├── FlexibleDict_BTE_1.py │ ├── FlexibleDict_BTE_2.py │ ├── FlexibleDict_BTE_3.py │ └── README.md ├── Exer-43-Animals │ ├── README.md │ ├── animals.py │ ├── animals_BTE_1.py │ ├── animals_BTE_2.py │ └── animals_BTE_3.py ├── Exer-44-Cage │ ├── BTE_1.py │ ├── BTE_2.py │ ├── BTE_3.py │ ├── README.md │ └── cage.py ├── Exer-45-Zoo │ ├── README.md │ ├── zoo.py │ ├── zoo_BTE_1.py │ ├── zoo_BTE_2.py │ └── zoo_BTE_3.py └── README.md ├── CHPT-10-Iterators-and-generators ├── Exer-46-MyEnumerate │ ├── README.md │ ├── louditerator_class.py │ ├── myenumerate.py │ ├── myenumerate_BTE_1.py │ ├── myenumerate_BTE_2.py │ └── myenumerate_BTE_3.py ├── Exer-47-Circle │ ├── README.md │ ├── circle.py │ ├── circle_BTE_1.py │ ├── circle_BTE_2.py │ └── circle_BTE_3.py ├── Exer-48-All-lines-all-files │ ├── README.md │ ├── all_lines.py │ ├── all_lines_BTE_1.py │ ├── all_lines_BTE_2.py │ └── all_lines_BTE_3.py ├── Exer-49-Elapsed-since │ ├── README.md │ ├── elapsed_since.py │ ├── elapsed_since_BTE_1.py │ ├── elapsed_since_BTE_2.py │ └── elapsed_since_BTE_3.py ├── Exer-50-MyChain │ ├── README.md │ └── mychain.py └── README.md └── README.md /2nd-Loop/CHPT-01-Numeric-Types/Exer-01-Number-guessing-game/Number-guessing-game.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def guessing_game(): 4 | 5 | answer = random.randint(0, 100) 6 | 7 | while True: 8 | user_guess = int(input("What is your guess? ")) 9 | 10 | if user_guess == answer: 11 | print("Right! The answer is {}".format(user_guess)) 12 | break 13 | 14 | if user_guess < answer: 15 | print("Your guess of {} is too low!".format(user_guess)) 16 | 17 | else: 18 | print("Your guess of {} is too high!".format(user_guess)) 19 | 20 | guessing_game() 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-01-Number-guessing-game/README.md: -------------------------------------------------------------------------------- 1 | ```python 2 | import random 3 | 4 | def guessing_game(): 5 | 6 | answer = random.randint(0, 100) 7 | 8 | while True: 9 | user_guess = int(input("What is your guess? ")) 10 | 11 | if user_guess == answer: 12 | print("Right! The answer is {}".format(user_guess)) 13 | break 14 | 15 | if user_guess < answer: 16 | print("Your guess of {} is too low!".format(user_guess)) 17 | 18 | else: 19 | print("Your guess of {} is too high!".format(user_guess)) 20 | 21 | guessing_game() 22 | ``` 23 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-02-Summing-numbers/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-02-Summing-numbers/summing-numbers.py: -------------------------------------------------------------------------------- 1 | 2 | def mysum(*numbers): 3 | output = 0 4 | for number in numbers: 5 | output += number 6 | return output 7 | 8 | 9 | print(mysum(10, 20, 30, 40)) 10 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-02-Summing-numbers/summing-numbers_BTE_2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a function that takes a list of numbers. It should return 3 | the average (i.e., arithmetic mean) of those numbers. 4 | """ 5 | 6 | def mysum(li): 7 | output = 0 8 | len_li = len(li) 9 | for item in li: 10 | output += item 11 | avg_num = output // len_li 12 | return avg_num 13 | 14 | print(mysum([10, 20, 30, 40])) 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-02-Summing-numbers/summing-numbers_BTE_4.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that takes a list of Python objects. Sum the objects 3 | that either are integers or can be turned into integers, ignoring the others. 4 | ''' 5 | 6 | def sum_int(li): 7 | val = 0 8 | for item in li: 9 | try: 10 | val += int(item) 11 | except ValueError: 12 | pass 13 | return val 14 | 15 | mylist = [1, 2, 3, 6.5, '4', 'A', 'B'] 16 | 17 | print(sum_int(mylist)) 18 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-03-Run-timing/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-03-Run-timing/run-timing-BTE-1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that takes a float and two integers (before and after). 3 | The function should return a float consisting of before digits 4 | before the decimal point and after digits after. Thus, if we call 5 | the function with 1234.5678, 2 and 3, the return value should be 34.567. 6 | ''' 7 | 8 | def cropNumber(fl_num, bef_int_num, aft_int_num): 9 | str_bef = str(int(fl_num)) 10 | str_bef = str_bef[-bef_int_num:] 11 | str_fl = float(str_bef) 12 | 13 | 14 | num_dec = fl_num - int(fl_num) 15 | num_dec = str(num_dec) 16 | num_dec = num_dec[0:aft_int_num + 2] 17 | 18 | return str_fl + float(num_dec) 19 | 20 | 21 | 22 | 23 | print(cropNumber(1234.5678, 2, 3)) 24 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-03-Run-timing/run-timing-BTE-2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Explore the Decimal class (http://mng.bz/oPVr), which has an alternative floating-point 3 | representation that’s as accurate as any decimal number can be. Write a function 4 | that takes two strings from the user, turns them into decimal instances, 5 | and then prints the floating-point sum of the user’s two inputs. 6 | In other words, make it possible for the user to enter 0.1 and 0.2, and for us to get 0.3 back. 7 | ''' 8 | 9 | def add_flo(val1, val2): 10 | sum_of_flo = float(val1 + val2) 11 | return f"{sum_of_flo:.1f}" 12 | 13 | print(add_flo(0.1, 0.2)) 14 | 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-03-Run-timing/run-timing.py: -------------------------------------------------------------------------------- 1 | def run_timing(): 2 | """Asks the user repeatedly for numeric input. Prints the average time 3 | an d number of runs.""" 4 | 5 | number_of_runs = 0 6 | total_time = 0 7 | 8 | while True: 9 | one_run = input('Enter 10 km run time: ') 10 | if one_run == '0': 11 | break 12 | if not one_run: 13 | break 14 | number_of_runs += 1 15 | total_time += float(one_run) 16 | 17 | average_time = total_time / number_of_runs 18 | print(f'Average of {average_time} over {number_of_runs} runs') 19 | 20 | run_timing() 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-04-Hexadecimal-output/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-04-Hexadecimal-output/hexadecimal-output.py: -------------------------------------------------------------------------------- 1 | 2 | def hex_output(): 3 | decnum = 0 4 | hexnum = input('Enter a hex number to convert: ') 5 | for power, digit in enumerate(reversed(hexnum)): 6 | decnum += int(digit, 16) * (16 ** power) 7 | print(decnum) 8 | 9 | hex_output() 10 | 11 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/Exer-04-Hexadecimal-output/hexadecimal-output_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a program that asks the user for their name and then produces a “name triangle”: 3 | the first letter of their name, then the first two letters, then the first three, 4 | and so forth, until the entire name is written on the final line. 5 | ''' 6 | 7 | n = input('Your name? ') 8 | n_l = '' 9 | for ch in n: 10 | n_l += ch 11 | print(n_l) 12 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-01-Numeric-Types/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-05-Pig-Latin/C5-Handle-capitalized-words.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Handle capitalized words—If a word is capitalized (i.e., the first letter is capitalized, 3 | but the rest of the word isn’t), then the Pig Latin translation should be similarly capitalized. 4 | ''' 5 | 6 | def pig_latin(word): 7 | final_string = '' 8 | if word[0] in 'aeiou': 9 | final_string = word + 'way' 10 | return final_string.capitalize() 11 | else: 12 | final_string = word[1:] + word[:1] + 'ay' 13 | return final_string.capitalize() 14 | 15 | print(pig_latin('python')) 16 | print(pig_latin('Elephant')) 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-05-Pig-Latin/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-05-Pig-Latin/pig_latin.py: -------------------------------------------------------------------------------- 1 | def pig_latin(word): 2 | if word[0] in 'aeiou': 3 | return f'{word}way' 4 | else: 5 | return f'{word[1:]}{word[:1]}ay' 6 | 7 | 8 | print(pig_latin('computer')) 9 | print(pig_latin('elephant')) 10 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-06-Pig-Latin-sentence/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-06-Pig-Latin-sentence/pig-latin-sentence-BTE-1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Take a text file, creating (and printing) a nonsensical sentence from the nth 4 | word on each of the first 10 lines, where n is the line number. 5 | ''' 6 | 7 | N = int(input("Take a number between 0 - 5: ")) 8 | 9 | st_nouns = "puppy car rabbit girl monkey" 10 | st_verbs = "runs hits jumps drives barfs" 11 | st_adv = "crazily dutifully foolishly merrily occasionally" 12 | st_adj = "adorable clueless dirty odd stupid" 13 | 14 | nouns_tup = tuple(st_nouns.split(' ')) 15 | verbs_tup = tuple(st_verbs.split(' ')) 16 | adv_tup = tuple(st_adv.split(' ')) 17 | adj_tup = tuple(st_adj.split(' ')) 18 | 19 | print(nouns_tup[N].capitalize() + ' ' + verbs_tup[N] + ' ' + adv_tup[N] + ' ' + adj_tup[N] + '.') -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-06-Pig-Latin-sentence/pig-latin-sentence-BTE-2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that transposes a list of strings, in which each string contains 4 | multiple words separated by whitespace. Specifically, it should perform in such a way 5 | that if you were to pass the list ['abc def ghi', 'jkl mno pqr', 'stu vwx yz'] to the function, 6 | it would return ['abc jkl stu', 'def mno vwx', 'ghi pqr yz']. 7 | ''' 8 | 9 | old_list = ['abc def ghi', 'jkl mno pqr', 'stu vwx yz'] 10 | 11 | lists = [x.split() for x in old_list] 12 | 13 | print( [ " ".join(x) for x in zip(*lists) ]) 14 | 15 | 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-06-Pig-Latin-sentence/pig-latin-sentence.py: -------------------------------------------------------------------------------- 1 | 2 | def pl_sentence(sentence): 3 | output = [] 4 | for word in sentence.split(): 5 | if word[0] in 'aeiou': 6 | output.append(f'{word}way') 7 | else: 8 | output.append(f'{word[1:]}{word[0]}ay') 9 | 10 | return ' '.join(output) 11 | 12 | print(pl_sentence('this is a test')) 13 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-07-Ubbi-Dubbi/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-07-Ubbi-Dubbi/ubbi-dubbi-BTE-1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Handle capitalized words—If a word is capitalized (i.e., the first letter is capitalized, 4 | but the rest of the word isn’t), then the Ubbi Dubbi translation should be similarly capitalized. 5 | ''' 6 | 7 | def ubbi_dubbi(word): 8 | output = [] 9 | for letter in word: 10 | if letter in 'aeiou': 11 | output.append(f'ub{letter}') 12 | if word.isupper(): 13 | word.isupper() 14 | else: 15 | output.append(letter) 16 | return ''.join(output) 17 | 18 | print(ubbi_dubbi('Python')) 19 | print(ubbi_dubbi('Crwth')) 20 | 21 | # The crwth is a instrument, associated particularly with Welsh music. 22 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-07-Ubbi-Dubbi/ubbi-dubbi-BTE-2.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Remove author names—In academia, it’s common to remove the authors’ names 4 | from a paper submitted for peer review. Given a string containing an article and 5 | a separate list of strings containing authors’ names, replace all names in the 6 | article with _ characters. 7 | """ 8 | 9 | def rem_auth_name(text, auth_lst): 10 | for auth_name in auth_lst: 11 | if auth_name in text: 12 | text = text.replace(auth_name, '_'*len(auth_name)) 13 | return text 14 | 15 | 16 | my_text = "Author of this article is Ada Lovelace.\nSecond author of the article is Marie Curie'" 17 | my_auth_lst = ['Ada Lovelace', 'Marie Curie'] 18 | 19 | print(rem_auth_name(my_text, my_auth_lst)) 20 | 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-07-Ubbi-Dubbi/ubbi-dubbi.py: -------------------------------------------------------------------------------- 1 | 2 | def ubbi_dubbi(word): 3 | output = [] 4 | for letter in word: 5 | if letter in 'aeiou': 6 | output.append(f'ub{letter}') 7 | else: 8 | output.append(letter) 9 | 10 | return ''.join(output) 11 | 12 | print(ubbi_dubbi('python')) 13 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-08-Sorting-a-string/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-08-Sorting-a-string/sorting-a-string-BTE-1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Given the string “Tom Dick Harry,” break it into individual words, 4 | and then sort those words alphabetically. Once they’re sorted, print them 5 | with commas (,) between the names. 6 | ''' 7 | 8 | s = "Tom Dick Harry" 9 | 10 | splitted_and_sorted = sorted(s.split()) 11 | 12 | result = ', '.join(splitted_and_sorted) 13 | 14 | print(result) 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-08-Sorting-a-string/sorting-a-string-BTE-2.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Which is the longest word in a text file? 4 | """ 5 | 6 | def find_longest(fname): 7 | lo_wo = '' 8 | with open(fname, 'r') as f: 9 | for li in f: 10 | t = '' 11 | for c in li: 12 | if c.isalnum() or c == ' ': 13 | t += c 14 | lgt = sorted(t.split(), key=len)[-1] 15 | if len(lo_wo) < len(lgt): 16 | lo_wo = lgt 17 | return lo_wo, len(lo_wo) 18 | 19 | print(find_longest('my_text.txt')) 20 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-08-Sorting-a-string/sorting-a-string-BTE-3.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Which is the last word, alphabetically, in a text file? 4 | """ 5 | def find_last(fname): 6 | la_wo = '' 7 | with open(fname, 'r') as f: 8 | for l in f: 9 | t = '' 10 | for c in l: 11 | if c.isalnum() or c == ' ': 12 | t += c 13 | final = sorted(t.split())[-1] 14 | if la_wo < final: 15 | la_wo = final 16 | 17 | return la_wo 18 | 19 | 20 | print(find_last('my_text.txt')) 21 | 22 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/Exer-08-Sorting-a-string/sorting-a-string.py: -------------------------------------------------------------------------------- 1 | def strsort(a_string): 2 | return ''.join(sorted(a_string)) 3 | 4 | print(strsort('cbjeaf')) 5 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-02-Strings/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-09-First-last/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that takes a list or tuple of numbers. Return a two-element list, 4 | containing (respectively) the sum of the even-indexed numbers and the sum of the odd-indexed numbers. 5 | So calling the function as even_odd_sums([10, 20, 30, 40, 50, 60]), you’ll get back [90, 120]. 6 | ''' 7 | 8 | def even_odd_sums(sequence): 9 | even_sum = 0 10 | odd_sum = 0 11 | for i, item in enumerate(sequence): 12 | if i % 2 == 0: 13 | even_sum += item 14 | else: 15 | odd_sum += item 16 | return even_sum, odd_sum 17 | 18 | print(even_odd_sums([10, 20, 30, 40, 50, 60])) 19 | 20 | 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that takes a list or tuple of numbers. Return a two-element list, 4 | containing (respectively) the sum of the even-indexed numbers and the sum of the odd-indexed numbers. 5 | So calling the function as even_odd_sums([10, 20, 30, 40, 50, 60]), you’ll get back [90, 120]. 6 | 7 | Alternative Solution-I 8 | ''' 9 | 10 | def even_odd_sums(iter): 11 | return [sum(iter[::2]), sum(iter[1::2] )] 12 | 13 | print(even_odd_sums([10, 20, 30, 40, 50, 60])) 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that takes a list or tuple of numbers. Return a two-element list, 4 | containing (respectively) the sum of the even-indexed numbers and the sum of the odd-indexed numbers. 5 | So calling the function as even_odd_sums([10, 20, 30, 40, 50, 60]), you’ll get back [90, 120]. 6 | 7 | Alternative Solution-II: 8 | ''' 9 | 10 | def even_odd_sums(seq): 11 | 12 | sum_even = sum(seq[0::2]) 13 | sum_odd = sum(seq[1::2]) 14 | return [sum_even, sum_odd] 15 | 16 | print(even_odd_sums([10, 20, 30, 40, 50, 60])) 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-4.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that takes a list or tuple of numbers. Return the result of alternately adding and subtracting numbers 3 | from each other. So calling the function as plus_minus([10, 20, 30, 40, 50, 60]), 4 | you’ll get back the result of 10+20-30+40-50+60, or 50. 5 | ''' 6 | 7 | def plus_minus(iter): 8 | str_acc = f'{iter[0]}' 9 | num_sum = iter[0] 10 | for i in range(1, len(iter)): 11 | if not (i % 2): 12 | str_acc += f'-{iter[i]}' 13 | num_sum -= iter[i] 14 | else: 15 | str_acc += f'+{iter[i]}' 16 | num_sum += iter[i] 17 | return str_acc, num_sum 18 | 19 | print(plus_minus([10, 20, 30, 40, 50, 60])) 20 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-5.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that takes a list or tuple of numbers. Return the result of alternately adding and subtracting numbers 3 | from each other. So calling the function as plus_minus([10, 20, 30, 40, 50, 60]), 4 | you’ll get back the result of 10+20-30+40-50+60, or 50. 5 | 6 | Alternative solution: 7 | ''' 8 | 9 | def plus_minus(seq): 10 | 11 | return seq[0] + sum(seq[1::2]) - sum(seq[2::2]) 12 | 13 | print(plus_minus([10, 20, 30, 40, 50, 60])) 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-6.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that partly emulates the built-in zip function (http://mng.bz/ Jyzv), 4 | taking any number of iterables and returning a list of tuples. Each tuple will contain 5 | one element from each of the iterables passed to the function. Thus, if I call 6 | myzip([10, 20,30], 'abc'), the result will be [(10, 'a'), (20, 'b'), (30, 'c')]. You can return 7 | a list (not an iterator) and can assume that all of the iterables are of the same length. 8 | ''' 9 | 10 | 11 | 12 | def myzip(iterable): 13 | new_iter = [ [(elem[x]) for elem in iterable] for x in range(len(iterable[0])) ] 14 | return [tuple(elem) for elem in new_iter] 15 | 16 | print(myzip([[10, 20,30], 'abc'])) 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast.py: -------------------------------------------------------------------------------- 1 | 2 | def firstlast(sequence): 3 | return sequence[:1] + sequence[-1:] 4 | 5 | test_str = 'abcdef' 6 | test_lst = [1, 2, 3, 4] 7 | 8 | print( firstlast(test_str) ) 9 | 10 | print( firstlast(test_lst) ) 11 | 12 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-10-Summing-anything/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-10-Summing-anything/mysum.py: -------------------------------------------------------------------------------- 1 | 2 | def mysum(*items): 3 | if not items: 4 | return items 5 | output = items[0] 6 | for item in items[1:]: 7 | output += item 8 | return output 9 | 10 | print(mysum()) 11 | print(mysum(10, 20, 30, 40)) 12 | print(mysum('a', 'b', 'c', 'd')) 13 | print(mysum([10, 20, 30], [40, 50, 60], [70, 80])) 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names.py: -------------------------------------------------------------------------------- 1 | 2 | import operator 3 | 4 | PEOPLE = [{'first': 'Reuven', 'last': 'Lerner', 5 | 'email': 'reuven@lerner.co.il'}, 6 | {'first': 'Donald', 'last': 'Trump', 7 | 'email': 'president@whitehouse.gov'}, 8 | {'first': 'Vladimir', 'last': 'Putin', 9 | 'email': 'president@kremvax.ru'} 10 | ] 11 | 12 | def alphabetize_names(list_of_dicts): 13 | return sorted(list_of_dicts, key=operator.itemgetter('last', 'first')) 14 | 15 | print(alphabetize_names(PEOPLE)) 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a sequence of positive and negative numbers, sort them by absolute value. 3 | ''' 4 | 5 | def sorting_numbers(iter): 6 | return sorted(iter, key=abs) 7 | 8 | print(sorting_numbers([7, 15, 20, 1])) 9 | 10 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of strings, sort them according to how many vowels they contain. 3 | ''' 4 | 5 | def vowel_sort(iter): 6 | VOWELS = ['a', 'e', 'i', 'o', 'u'] 7 | return sorted(iter, key=lambda x: sum([x.count(c) for c in VOWELS])) 8 | 9 | 10 | str_lst = ['eyewitness', 'Robot', 'abbreviation'] 11 | 12 | print(vowel_sort(str_lst)) 13 | 14 | 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_2_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of strings, sort them according to how many vowels they contain. 3 | ''' 4 | 5 | def vowel_sort(iter): 6 | 7 | return sorted( iter, key=lambda x: x.count('a') + x.count('e') + x.count('u') + 8 | x.count('i') + x.count('o')) 9 | 10 | 11 | str_lst = ['eyewitness', 'Robot', 'abbreviation'] 12 | 13 | print(vowel_sort(str_lst)) 14 | 15 | 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_2_alternative_solution_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of strings, sort them according to how many vowels they contain. 3 | ''' 4 | 5 | def vowel_cnt(word): 6 | cnt = 0 7 | for ch in word.lower(): 8 | if ch in 'aeiou': 9 | cnt += 1 10 | return cnt 11 | 12 | def vowel_sort(iter): 13 | return sorted(iter, key=vowel_cnt) 14 | 15 | 16 | str_lst = ['eyewitness', 'Robot', 'abbreviation'] 17 | 18 | print(vowel_sort(str_lst)) 19 | 20 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of lists, with each list containing zero or more numbers, 3 | sort by the 4 | sum of each inner list’s numbers. 5 | ''' 6 | 7 | my_list = [[0, 1, 2], [3, 4], []] 8 | 9 | 10 | def sort_lst(iter): 11 | return sorted(iter, key=sum) 12 | 13 | 14 | print(sort_lst(my_list)) 15 | 16 | 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/most_repeating_word.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from collections import Counter 4 | import operator 5 | 6 | WORDS = ['this', 'is', 'an', 'elementary', 'test', 'example'] 7 | 8 | def most_repeating_letter_count(word): 9 | return Counter(word).most_common(1)[0][1] 10 | 11 | def most_repeating_word(words): 12 | return max(words, 13 | key=most_repeating_letter_count) 14 | 15 | print(most_repeating_word(WORDS)) 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/most_repeating_word_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Instead of finding the word with the greatest number of repeated letters, 4 | find the word with the greatest number of repeated vowels. 5 | ''' 6 | from collections import Counter 7 | 8 | WORDS = ['this', 'is', 'an', 'elementary', 'test', 'example'] 9 | 10 | def vow_word(wo): 11 | vwl = ('a', 'e', 'i', 'o', 'u') 12 | c = Counter(wo) 13 | return max([c[v] for v in vwl]) 14 | 15 | def most_rep_vwl(wos): 16 | return max(wos, key=vow_word) 17 | 18 | print(most_rep_vwl(WORDS)) 19 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/most_repeating_word_BTE_1_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Instead of finding the word with the greatest number of repeated letters, 4 | find the word with the greatest number of repeated vowels. 5 | ''' 6 | 7 | from collections import Counter 8 | 9 | WORDS = ['this', 'is', 'an', 'elementary', 'test', 'example'] 10 | 11 | def vow_word(wo): 12 | vwl = '' 13 | for ch in wo.lower(): 14 | if ch in 'aeiou': 15 | vwl += ch 16 | 17 | return Counter(vwl).most_common(1)[0][1] 18 | 19 | def most_rep_vwl(wos): 20 | return max(wos, key=vow_word) 21 | 22 | print(most_rep_vwl(WORDS)) 23 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/most_repeating_word_BTE_1_alternative_solution_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Instead of finding the word with the greatest number of repeated letters, 4 | find the word with the greatest number of repeated vowels. 5 | ''' 6 | 7 | from collections import Counter 8 | import operator 9 | 10 | WORDS = ['this', 'is', 'an', 'elementary', 'test', 'example'] 11 | 12 | def most_rep(wo): 13 | return operator.getitem(operator.getitem(Counter(wo).most_common(), 0), 1) 14 | 15 | def vwl_cnt(wo): 16 | vwl = 'aeuio' 17 | filter(lambda x: x in vwl, wo) 18 | return most_rep(wo) 19 | 20 | def most_repeating_vwl(wos): 21 | return max(wos, key=vwl_cnt) 22 | 23 | print(most_repeating_vwl(WORDS)) 24 | 25 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/most_repeating_word_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a program to read /etc/passwd on a Unix computer. The first field 4 | contains the username, and the final field contains the user’s shell, 5 | the command interpreter. Display the shells in decreasing order of popularity, 6 | such that the most popular shell is shown first, the second most popular 7 | shell second, and so forth. 8 | ''' 9 | 10 | user = "luke" 11 | with open("etc_passwd.txt") as file: 12 | for line in file: 13 | if line.split(":")[0] == user: 14 | if line.rstrip("\n").split(":")[6] in ["/usr/sbin/nologin", "/bin/false"]: 15 | print("User is not allowed to login") 16 | else: 17 | print(line.rstrip("\n").split(":")[6]) 18 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-13-Printing-tuple-records/BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | import collections 3 | from operator import itemgetter 4 | 5 | PEOPLE = [('Donald', 'Trump', 7.85), 6 | ('Vladimir', 'Putin', 3.626), 7 | ('Jinping', 'Xi', 10.603)] 8 | 9 | 10 | def sort_using_ntuple(iter): 11 | 12 | st = '' 13 | person = collections.namedtuple('person', ('firstname', 'lastname', 'hours')) 14 | persons = [person(p[0], p[1], p[-1]) for p in iter] 15 | for item in sorted(persons, key=lambda x: (x.lastname, x.firstname)): 16 | st += f'{item.lastname:<10} {item.firstname:<10} {item.hours:>5.2f}\n' 17 | return st 18 | 19 | print(sort_using_ntuple(PEOPLE)) 20 | 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-13-Printing-tuple-records/BTE_1_alternative_version.py: -------------------------------------------------------------------------------- 1 | 2 | import collections 3 | from operator import itemgetter 4 | 5 | PEOPLE = [('Donald', 'Trump', 7.85), 6 | ('Vladimir', 'Putin', 3.626), 7 | ('Jinping', 'Xi', 10.603)] 8 | 9 | def format_sort_records(iter): 10 | output = [] 11 | template = '{1:10} {0:10} {2:5.2f}' 12 | 13 | person = collections.namedtuple('person', ('firstname', 'lastname', 'hours')) 14 | persons = [person(p[0],p[1],p[-1]) for p in iter] 15 | 16 | for one_person in sorted(persons, key=itemgetter(1, 0)): 17 | output.append(template.format(*one_person)) 18 | 19 | return output 20 | 21 | print('\n'.join(format_sort_records(PEOPLE))) 22 | 23 | 24 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-13-Printing-tuple-records/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/Exer-13-Printing-tuple-records/format_sort_records.py: -------------------------------------------------------------------------------- 1 | 2 | from operator import itemgetter 3 | 4 | PEOPLE = [('Donald', 'Trump', 7.85), ('Vladimir', 'Putin', 3.626), ('Jinping', 'Xi', 10.603)] 5 | 6 | def format_sort_records(list_of_tuples): 7 | output = [] 8 | template = '{1:10} {0:10} {2:5.2f}' 9 | 10 | for one_person in sorted(list_of_tuples, key=itemgetter(1, 0)): 11 | output.append(template.format(*one_person)) 12 | 13 | return output 14 | 15 | print('\n'.join(format_sort_records(PEOPLE))) 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-03-Lists-and-tuples/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-14-Restaurant/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-14-Restaurant/restaurant.py: -------------------------------------------------------------------------------- 1 | 2 | MENU = {'sandwich':10, 'tea':7, 'salad':9} 3 | 4 | def restaurant(): 5 | 6 | total = 0 7 | while True: 8 | order = input("Enter your order: ").strip() 9 | 10 | if not order: 11 | break 12 | 13 | if order in MENU: 14 | price = MENU[order] 15 | total += int(price) 16 | print(f'{order} costs {price}, total is now {total}') 17 | 18 | else: 19 | print(f'We are fresh out of {order} today.') 20 | print(f'Your total is {total}') 21 | 22 | restaurant() 23 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/rainfall.py: -------------------------------------------------------------------------------- 1 | 2 | def get_rainfall(): 3 | 4 | rainfall = {} 5 | 6 | while True: 7 | city_name = input("Enter city name: ").strip() 8 | if not city_name: 9 | break 10 | mm_rain = input("Enter mm rain: ") 11 | rainfall[city_name] = rainfall.get(city_name, 0) + int(mm_rain) 12 | for key, value in rainfall.items(): 13 | print(f'{key}: {value}') 14 | 15 | get_rainfall() 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/rainfall_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Open a log file from a Unix/Linux system—for example, one from the Apache 3 | server. For each response code (i.e., three-digit code indicating the HTTP 4 | request’s success or failure), store a list of IP addresses that generated 5 | that code. 6 | ''' 7 | 8 | def log_chq(fname): 9 | rsp_code = {} 10 | with open(fname, 'r') as f: 11 | for l in f: 12 | l = l.split() 13 | print(l) 14 | rsp_code[l[8]] = rsp_code.get(l[8], []) + l[:1] 15 | return rsp_code 16 | 17 | print(log_chq('log_file.txt')) 18 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/rainfall_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Read through a text file on disk. Use a dict to track how many words 3 | of each length are in the file—that is, how many three-letter words, 4 | four-letter words, five-letter words, and so on. Display your results. 5 | ''' 6 | 7 | def file_chq(fname): 8 | sym = ['.',',','?','!','\n'] 9 | wo_li = {} 10 | with open(fname, 'r') as f: 11 | for l in f: 12 | for c in sym: 13 | l = l.replace(c, '') 14 | l = l.split() 15 | for wo in l: 16 | wo_li[len(wo)] = wo_li.get(len(wo), 0) + 1 17 | for nr in wo_li: 18 | print(f'The file contains {wo_li[nr]} words with {nr} letters.') 19 | 20 | 21 | file_chq('txt_file.txt') 22 | 23 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/rainfall_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def get_rainfall(): 4 | rainfall = {} 5 | while True: 6 | cname = input("Enter the city: ") 7 | if not cname: 8 | print("No entry. Displaying the results:") 9 | break 10 | rain_val = input("Enter in mm:") 11 | rainfall[cname] = rainfall.get(cname, 0) + int(rain_val) 12 | for k, v in rainfall.items(): 13 | print("{0:5} : {1:5}".format(k,v)) 14 | 15 | get_rainfall() 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/dictdiff.py: -------------------------------------------------------------------------------- 1 | 2 | d1 = {'a':1, 'b':2, 'c':3} 3 | d2 = {'a':1, 'b':2, 'd':4} 4 | d3 = {'a':1, 'b':3, 'd':5} 5 | 6 | def dictdiff(first, second): 7 | output = {} 8 | all_keys = first.keys() | second.keys() 9 | for key in all_keys: 10 | if first.get(key) != second.get(key): 11 | output[key] = [first.get(key), second.get(key)] 12 | return output 13 | 14 | print(dictdiff(d1, d2)) 15 | print(dictdiff(d2, d3)) 16 | 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/dictdiff_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The dict.update method merges two dicts. Write a function that takes any number 3 | of dicts and returns a dict that reflects the combination of all of them. 4 | If the same key appears in more than one dict, then the most recently merged 5 | dict’s value should appear in the output. 6 | ''' 7 | 8 | def mult_di(*args): 9 | fin_di = {} 10 | for di in args: 11 | fin_di.update(di) 12 | return fin_di 13 | 14 | 15 | d1 = {'a':1, 'b':2, 'c':3} 16 | d2 = {'a':1, 'b':2, 'd':4} 17 | d3 = {'a':1, 'b':3, 'd':5} 18 | 19 | print(mult_di(d1, d2, d3)) 20 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/dictdiff_BTE_1_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The dict.update method merges two dicts. Write a function that takes any number 3 | of dicts and returns a dict that reflects the combination of all of them. 4 | If the same key appears in more than one dict, then the most recently merged 5 | dict’s value should appear in the output. 6 | ''' 7 | 8 | def mult_di(*args): 9 | fin_di = {} 10 | for di in args: 11 | fin_di = {**fin_di, **di} 12 | return fin_di 13 | 14 | 15 | d1 = {'a':1, 'b':2, 'c':3} 16 | d2 = {'a':1, 'b':2, 'd':4} 17 | d3 = {'a':1, 'b':3, 'd':5} 18 | 19 | print(mult_di(d1, d2, d3)) 20 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/dictdiff_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that takes any even number of arguments and returns a dict 4 | based on them. The even-indexed arguments become the dict keys, while the odd- 5 | numbered arguments become the dict values. Thus, calling the function with the 6 | arguments ('a', 1, 'b', 2) will result in the dict {'a':1, 'b':2} being returned. 7 | ''' 8 | 9 | 10 | def even_ind_di(*elem): 11 | return {k:v for k,v in zip(elem[::2], elem[1::2])} 12 | 13 | print(even_ind_di('0', 1, '2', 3, 'a', 4, '5', 'b', '6', 7, 'c')) 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/how_many_different_numbers.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def how_many_different_numbers(numbers): 4 | return len(set(numbers)) 5 | 6 | 7 | print(how_many_different_numbers([10, 20, 30])) 8 | print(how_many_different_numbers([10, 20, 30, 10, 20, 30])) 9 | 10 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/how_many_different_numbers_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Read through a server (e.g., Apache or nginx) log file. What were the different 4 | IP addresses that tried to access your server? 5 | ''' 6 | 7 | def log_chq(fname): 8 | ip_s = set() 9 | with open(fname, 'r') as f: 10 | for l in f: 11 | ip_s.add(l.partition(' ')[0]) 12 | return ip_s 13 | 14 | print(log_chq('log_file.txt')) 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/how_many_different_numbers_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Reading from that same server log, what response codes were returned to users? 3 | The 200 code represents “OK,” but there are also 403, 404, and 500 errors. 4 | (Regular expressions aren’t required here but will probably help.) 5 | ''' 6 | 7 | 8 | def log_chq_2(fname): 9 | er_set = set() 10 | with open(fname, 'r') as f: 11 | for l in f: 12 | er_set.add(l.split(' ')[8]) 13 | return er_set 14 | 15 | print(log_chq_2('log_file.txt')) 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/how_many_different_numbers_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Use os.listdir (http://mng.bz/YreB) to get the names of files in the current directory. 3 | What file extensions (i.e., suffixes following the final . character) appear in that directory? 4 | It’ll probably be helpful to use os.path.splitext (http://mng.bz/GV4v). 5 | ''' 6 | 7 | import os 8 | 9 | def file_chq(path): 10 | return set( [f.partition('.')[-1] for f in os.listdir(path)] ) 11 | 12 | 13 | print(file_chq('/Users/User/Documents/')) 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-04-Dictionaries-and-sets/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-18-Final-line/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-18-Final-line/get_final_line.py: -------------------------------------------------------------------------------- 1 | 2 | # Given a filename, return the final line in that file. 3 | 4 | def get_final_line(fname): 5 | fin_li = '' 6 | for cur_li in open(fname): 7 | fin_li = cur_li 8 | return fin_li 9 | 10 | print(get_final_line('sonnet_126.txt')) 11 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-18-Final-line/get_final_line_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Iterate over the lines of a text file. Find all of the words (i.e., non-whitespace 3 | surrounded by whitespace) that contain only integers, and sum them. 4 | ''' 5 | 6 | def find_num(fname): 7 | with open(fname) as f: 8 | n_sum = 0 9 | for l in f: 10 | n_sum += sum([int(w) for w in l.split() if w.isdigit()]) 11 | return n_sum 12 | 13 | print(find_num('sonnet_126.txt')) 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-18-Final-line/get_final_line_BTE_1_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Iterate over the lines of a text file. Find all of the words (i.e., non-whitespace 3 | surrounded by whitespace) that contain only integers, and sum them. 4 | ''' 5 | 6 | def find_num(fname): 7 | with open(fname) as f: 8 | n_sum = 0 9 | for l in f: 10 | for w in l.split(): 11 | if w.isdigit(): 12 | n_sum += int(w) 13 | return n_sum 14 | 15 | print(find_num('sonnet_126.txt')) 16 | 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-18-Final-line/get_final_line_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Read through a text file, line by line. Use a dict to keep track of how many times 3 | each vowel (a, e, i, o, and u) appears in the file. Print the resulting tabulation. 4 | ''' 5 | 6 | from collections import Counter 7 | 8 | def vwl_cnt(fname): 9 | vwl_di = {'a': 0, 'e': 0, 'i': 0, 'o': 0, 'u': 0} 10 | with open(fname) as f: 11 | for l in f: 12 | c = Counter(l) 13 | for k in vwl_di: 14 | vwl_di[k] += c.get(k, 0) 15 | 16 | for x, y in vwl_di.items(): 17 | print(x, y) 18 | 19 | print(vwl_cnt('sonnet_126.txt')) 20 | 21 | 22 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-18-Final-line/get_final_line_BTE_3_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Read through a text file, line by line. Use a dict to keep track of how many times 3 | each vowel (a, e, i, o, and u) appears in the file. Print the resulting tabulation. 4 | ''' 5 | 6 | def vwl_cnt(fname): 7 | vwl_di = {'a': 0, 'e': 0, 'i': 0, 'o': 0, 'u':0} 8 | with open(fname) as f: 9 | c = ' ' 10 | while c: 11 | c = f.read(1) 12 | if not(c in vwl_di): 13 | continue 14 | vwl_di[c] += 1 15 | for x, y in vwl_di.items(): 16 | print(x, y) 17 | 18 | print(vwl_cnt('sonnet_126.txt')) 19 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-18-Final-line/get_final_line_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | # Given a filename, return the final line in that file. 3 | 4 | def get_final_line(fname): 5 | with open(fname, 'rb+') as f: 6 | f.seek(-2, 2) 7 | s = f.read(1) 8 | ch = s 9 | 10 | while True: 11 | f.seek(-2, 1) 12 | ch = f.read(1) 13 | if ch == b'\n': 14 | break 15 | s += ch 16 | 17 | print(str(s[::-1]), 'utf-8') 18 | 19 | get_final_line('sonnet_126.txt') 20 | 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-18-Final-line/get_final_line_alternative_solution_2.py: -------------------------------------------------------------------------------- 1 | 2 | # Given a filename, return the final line in that file. 3 | 4 | 5 | 6 | def get_final_line(fname): 7 | with open(fname, 'r') as f: 8 | print(f.readlines()[-1]) 9 | 10 | get_final_line('sonnet_126.txt') 11 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-19-etc-passwd-to-dict/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-19-etc-passwd-to-dict/passwd_to_dict.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def passwd_to_dict(fname): 4 | return { 5 | one_line.split(':')[0] : int(one_line.split(':')[2]) 6 | for one_line in open(fname) 7 | if not one_line.startswith(('#', '\n')) 8 | } 9 | 10 | print(passwd_to_dict('passwd.txt')) 11 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-19-etc-passwd-to-dict/passwd_to_dict_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Read through /etc/passwd, creating a dict in which user login shells (the final 3 | field on each line) are the keys. Each value will be a list of the users for 4 | whom that shell is defined as their login shell. 5 | ''' 6 | 7 | def shell_chq(fname): 8 | sh_di = {} 9 | with open(fname) as f: 10 | for l in f: 11 | if l.startswith(('#', '\n')): 12 | continue 13 | l = l.replace('\n', '').split(':') 14 | sh_di[l[-1]] = list(sh_di.get(l[-1], [])) + [l[0]] 15 | 16 | for k, v in sh_di.items(): 17 | print(k, ':', v) 18 | 19 | shell_chq('passwd.txt') 20 | 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-19-etc-passwd-to-dict/passwd_to_dict_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Ask the user to enter integers, separated by spaces. From this input, create a dict 3 | whose keys are the factors for each number, and the values are lists containing those 4 | of the users’ integers that are multiples of those factors. 5 | ''' 6 | 7 | def get_factor(num): 8 | return { x for x in range(1, num + 1) if not num % x } 9 | 10 | def factor_chq(): 11 | nums = input('> ').split() 12 | nums = [int(num) for num in nums if num.isdigit()] 13 | d_keys = list(map(get_factor, nums)) 14 | s_keys = set() 15 | for n in d_keys: 16 | s_keys.update(n) 17 | d_keys = { k:[k*v for v in nums] for k in s_keys } 18 | print(d_keys) 19 | 20 | factor_chq() 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-19-etc-passwd-to-dict/passwd_to_dict_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | def passwd_to_dict(fname): 3 | users = {} 4 | with open(fname) as passwd: 5 | for line in passwd: 6 | if not line.startswith(('#', '\n')): 7 | user_info = line.split(':') 8 | users[user_info[0]] = int(user_info[2]) 9 | return users 10 | 11 | print(passwd_to_dict('passwd.txt')) 12 | 13 | 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-20-Word-count/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-20-Word-count/wcount.py: -------------------------------------------------------------------------------- 1 | 2 | def wcount(fname): 3 | cnts = {'characters': 0, 4 | 'words': 0, 5 | 'lines': 0} 6 | unq_wo = set() 7 | for x in open(fname): 8 | cnts['lines'] += 1 9 | cnts['characters'] += len(x) 10 | cnts['words'] += len(x.split()) 11 | unq_wo.update(x.split()) 12 | print(unq_wo) 13 | cnts['unique words'] = len(unq_wo) 14 | for k, v in cnts.items(): 15 | print(f'{k}: {v}') 16 | 17 | wcount('wcountfile.txt') 18 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-20-Word-count/wcount_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Ask the user to enter the name of a text file and then (on one line, 3 | separated by spaces) words whose frequencies should be counted in that file. 4 | Count how many times those words appear in a dict, using the user-entered 5 | words as the keys and the counts as the values. 6 | ''' 7 | 8 | from os import path 9 | 10 | def cnt_wrd(): 11 | val = input('> ').split() 12 | fname = val[0] 13 | wrd_cnt_di = {k: 0 for k in val[1:]} 14 | with open(fname) as f: 15 | for l in f: 16 | wrds = l.strip().split() 17 | for wrd in wrds: 18 | if wrd in wrd_cnt_di: 19 | wrd_cnt_di[wrd] += 1 20 | print(wrd_cnt_di) 21 | 22 | cnt_wrd() 23 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-20-Word-count/wcount_BTE_2_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a dict in which the keys are the names of files on your system and the 3 | values are the sizes of those files. To calculate the size, you can use os.stat 4 | (http://mng.bz/dyyo). 5 | ''' 6 | 7 | import os 8 | 9 | def fl_sz(pth): 10 | fl_di = {} 11 | for fl in os.scandir(pth): 12 | fl_di[fl.name] = fl.stat().st_size 13 | print(fl_di) 14 | 15 | fl_sz('my_directory') 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-20-Word-count/wcount_BTE_2_alternative_solution_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a dict in which the keys are the names of files on your system and the 3 | values are the sizes of those files. To calculate the size, you can use os.stat 4 | (http://mng.bz/dyyo). 5 | ''' 6 | 7 | from pathlib import Path 8 | 9 | def fl_sz(pth): 10 | fl_di = {} 11 | for fl in Path(pth).iterdir(): 12 | if fl.is_dir(): 13 | continue 14 | fl_di[fl.name] = fl.stat().st_size 15 | print(fl_di) 16 | 17 | fl_sz('my_directory') 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-21-Longest-word-per-file/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-21-Longest-word-per-file/longest_word.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | def find_longest_word(filename): 5 | longest_word = '' 6 | try: 7 | for one_line in open(filename): 8 | for one_word in one_line.split(): 9 | if len(one_word) > len(longest_word): 10 | longest_word = one_word 11 | except (OSError, UnicodeDecodeError) as e: 12 | print(f'Ignoring {filename}: {e}') 13 | return longest_word 14 | 15 | def find_all_longest_words(dirname): 16 | return {filename: find_longest_word(os.path.join(dirname, filename)) 17 | for filename in os.listdir(dirname) 18 | if os.path.isfile(os.path.join(dirname, filename))} 19 | 20 | print(find_all_longest_words('.')) 21 | 22 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-21-Longest-word-per-file/longest_word_BTE_3.py: -------------------------------------------------------------------------------- 1 | """ 2 | Open an HTTP server’s log file. (If you lack one, then you can read one from 3 | me at http://mng.bz/vxxM.) Summarize how many requests resulted in numeric 4 | response codes—202, 304, and so on. 5 | """ 6 | 7 | def log_chq(fname): 8 | cnt_di = {} 9 | with open(fname) as f: 10 | for l in f: 11 | l = l.split() 12 | cnt_di[l[8]] = cnt_di.get(l[8], 0) + 1 13 | return cnt_di 14 | 15 | print(log_chq('mini-access-log.txt')) 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-22-Reading-and-writing-CSV/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-22-Reading-and-writing-CSV/passwd_to_csv.py: -------------------------------------------------------------------------------- 1 | 2 | import csv 3 | 4 | def passwd_to_csv(passwd_filename, csv_filename): 5 | with open(passwd_filename) as passwd, open(csv_filename, 'w') as output: 6 | infile = csv.reader(passwd, delimiter=':') 7 | outfile = csv.writer(output, delimiter='\t') 8 | 9 | for one_record in infile: 10 | if len(one_record) > 1: 11 | outfile.writerow((one_record[0], one_record[2])) 12 | 13 | passwd_to_csv('linux-etc-passwd.txt', 'passwd3.csv') 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-22-Reading-and-writing-CSV/passwd_to_csv_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that writes a dict to a CSV file. Each line in the CSV file 3 | should contain three fields: (1) the key, which we’ll assume to be a string, 4 | (2) the value, and (3) the type of the value (e.g., str or int). 5 | ''' 6 | 7 | import csv 8 | 9 | def csv_from_di(res_file='di_val_typ.csv'): 10 | di_val = {'first': '1', 'second': 2, 'three': [3, 4, '5'], 'fourth': True, 'fifth': (6, 7)} 11 | with open(res_file, 'w') as csv_wr: 12 | wr = csv.writer(csv_wr) 13 | for k in di_val: 14 | wr.writerow( [k, di_val[k], type(di_val[k]) ] ) 15 | 16 | csv_from_di() 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-23-JSON/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-23-JSON/print_scores_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | For a slightly different challenge, turn each line in the file into a Python dict. 4 | This will require identifying each field with a unique column or key name. If you’re 5 | not sure what each field in /etc/passwd does, you can give it an arbitrary name. 6 | """ 7 | 8 | import csv 9 | import json 10 | 11 | def csv_di_json(fname): 12 | di_tp = {} 13 | cnt = 0 14 | with open(fname) as csv_rd, open('outfl_di_BTE_2.json', 'w') as outfl_json: 15 | for l in csv.reader(csv_rd, delimiter=':'): 16 | if not l[0].startswith('#'): 17 | di_tp[cnt] = { i:v for i, v in enumerate(l)} 18 | cnt += 1 19 | json.dump(di_tp, outfl_json, indent=4) 20 | 21 | csv_di_json('linux-etc-passwd.txt') 22 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-24-Reverse-lines/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/Exer-24-Reverse-lines/reverse_lines.py: -------------------------------------------------------------------------------- 1 | 2 | def reverse_lines(infname, outfname): 3 | with open(infname) as inf, open(outfname, 'w') as outf: 4 | for one_line in inf: 5 | outf.write(f'{one_line.rstrip()[::-1]}\n') 6 | 7 | reverse_lines('input_text.txt', 'output_text3.txt') 8 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-05-Files/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-25-XML-generator/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-25-XML-generator/myxml.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def myxml(tagname, content='', **kwargs): 4 | attributes = ''.join(f'{key}="{value}"' for key, value in kwargs.items()) 5 | return f'<{tagname}{attributes}>{content}' 6 | 7 | print(myxml('foo')) 8 | print(myxml('foo', 'text')) 9 | print(myxml('foo', 'bar', a=1, b=2, c=3)) 10 | 11 | 12 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-25-XML-generator/myxml_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a “factorial” function that takes any number of numeric arguments and 3 | returns the result of multiplying them all by one another. 4 | ''' 5 | 6 | def fact_fun(*args): 7 | if len(args) == 1: 8 | return args[0] 9 | return args[0] * fact_fun(*args[1:]) 10 | 11 | print(fact_fun(2)) 12 | print(fact_fun(2, 3, 4)) 13 | 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-25-XML-generator/myxml_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write an anyjoin function that works similarly to str.join, except that the first 3 | argument is a sequence of any types (not just of strings), and the second argument 4 | is the “glue” that we put between elements, defaulting to " " (a space). 5 | 6 | So anyjoin([1,2,3]) will return 1 2 3, 7 | and anyjoin('abc', pass:'**') will return pass:a**b**c. 8 | ''' 9 | 10 | def anyjoin(iter, glue=' '): 11 | return glue.join([str(x) for x in iter]) 12 | 13 | print(anyjoin([1,2,3])) 14 | print(anyjoin('abc', glue='**')) 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-25-XML-generator/myxml_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | def myxml(*args, **kwargs): 3 | tag, content = " ".join(args[:1]), ". ".join(args[1:]) 4 | attr_di = [f'{k}="{v}"' for k, v in kwargs.items()] 5 | attr_di.insert(0, tag) 6 | return f'<{" ".join(attr_di)}>{content}' 7 | 8 | print(myxml('foo')) 9 | print(myxml('foo', 'text')) 10 | print(myxml('foo', 'bar', a=1, b=2, c=3) ) 11 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-26-Prefix-notation-calculator/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-26-Prefix-notation-calculator/calc_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function, apply_to_each, that takes two arguments: a function that takes a single argument, 3 | and an iterable. Return a list whose values are the result of applying the function to each element 4 | in the iterable. 5 | ''' 6 | 7 | def double(num): 8 | return num * 2 9 | 10 | def apply_to_each(fun, my_iter): 11 | return [fun(item) for item in my_iter] 12 | 13 | print(apply_to_each(double, [4, 5, 6])) 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-26-Prefix-notation-calculator/calc_BTE_2_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function, apply_to_each, that takes two arguments: a function that takes a single argument, 3 | and an iterable. Return a list whose values are the result of applying the function to each element 4 | in the iterable. 5 | ''' 6 | 7 | def apply_to_each(fun, my_iter): 8 | return [fun(item) for item in my_iter] 9 | 10 | print(apply_to_each( (lambda x: x * 2), [4, 5, 6])) 11 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-26-Prefix-notation-calculator/calc_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function, transform_lines, that takes three arguments: a function 4 | that takes a single argument, the name of an input file, and the name of 5 | an output file. Calling the function will run the function on each line 6 | of the input file, with the results written to the output file. 7 | 8 | (Hint: the previous exercise and this one are closely related.) 9 | ''' 10 | 11 | def to_lower(txt): 12 | return txt.lower() 13 | 14 | def transform_lines(fun, f_in, f_out): 15 | with open(f_in) as f_rd, open(f_out, 'w') as f_wr: 16 | for l in f_rd: 17 | f_wr.write( fun(l) ) 18 | 19 | transform_lines(to_lower, 'sonnet_126.txt', 'output2.txt') 20 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-26-Prefix-notation-calculator/calc_BTE_3_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function, transform_lines, that takes three arguments: a function 4 | that takes a single argument, the name of an input file, and the name of 5 | an output file. Calling the function will run the function on each line 6 | of the input file, with the results written to the output file. 7 | 8 | (Hint: the previous exercise and this one are closely related.) 9 | ''' 10 | 11 | def transform_lines(fun, f_in, f_out): 12 | with open(f_in) as f_rd, open(f_out, 'w') as f_wr: 13 | for l in f_rd: 14 | f_wr.write(fun(l)) 15 | 16 | transform_lines( (lambda x: x.lower()), 'sonnet_126.txt', 'output_2.txt') 17 | 18 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-27-Password-generator/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-27-Password-generator/create_password_generator.py: -------------------------------------------------------------------------------- 1 | 2 | import random 3 | 4 | def create_p_gen(chars): 5 | 6 | def create_p(length): 7 | output = [] 8 | for i in range(length): 9 | output.append(random.choice(chars)) 10 | return ''.join(output) 11 | 12 | return create_p 13 | 14 | f = create_p_gen('abcdefghij!@#$%') 15 | 16 | print(f(10)) 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-27-Password-generator/create_password_generator_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function, getitem, that takes a single argument and returns a function f. 3 | The returned f can then be invoked on any data structure whose elements can be 4 | selected via square brackets, and then returns that item. So if I invoke f = getitem('a'), 5 | and if I have a dict d = {'a':1, 'b':2}, then f(d) will return 1. 6 | (This is very similar to operator.itemgetter, a very useful function in many circumstances.) 7 | ''' 8 | 9 | def get_item(item): 10 | def fun(iter): 11 | return iter[item] 12 | return fun 13 | 14 | f = get_item(1) 15 | print(f('asd')) 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/Exer-27-Password-generator/create_password_generator_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function, doboth, that takes two functions as arguments (f1 and f2) 3 | and returns a single function, g. Invoking g(x) should return the same result 4 | as invoking f2(f1(x)). 5 | ''' 6 | 7 | def doboth(fun1, fun2): 8 | def g(x): 9 | return fun2(fun1(x)) 10 | return g 11 | 12 | f1 = lambda x: x.rstrip('\nxyz') 13 | f2 = lambda x: x.lstrip(' 246') 14 | 15 | strip_string_from_sides = doboth(f1, f2) 16 | 17 | print(strip_string_from_sides(' 24444.Final String.\nzzyyx')) 18 | print(f2(f1(' 24444.Final String.\nzzyyx'))) 19 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-06-Functions/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/join_numbers.py: -------------------------------------------------------------------------------- 1 | 2 | mylist = [10, 20, 30] 3 | 4 | def join_numbers(numbers): 5 | return ','.join(str(x) for x in numbers) 6 | 7 | print(join_numbers(mylist)) 8 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/join_numbers_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | As in the exercise, take a list of integers and turn them into strings. However, 4 | you’ll only want to produce strings for integers between 0 and 10. Doing this 5 | will require understanding the if statement in list comprehensions as well. 6 | ''' 7 | 8 | def int_to_str(*args): 9 | return [str(x) for x in args if x >= 0 and x <= 10] 10 | 11 | print(int_to_str(*[21, 2, 4, 9, 10, 33, 66])) 12 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/join_numbers_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Given a list of strings containing hexadecimal numbers, sum the numbers together. 4 | ''' 5 | 6 | def hex_sum(hex_lst): 7 | return sum(int(x, base=16) for x in hex_lst) 8 | 9 | print(hex_sum( [hex(4), hex(9), hex(-4), hex(11)] )) 10 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/join_numbers_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Use a list comprehension to reverse the word order of lines in a text file. 4 | That is, if the first line is 5 | abc def 6 | and the second line is 7 | ghi jkl, 8 | then you should return the list 9 | ['def abc', 'jkl ghi']. 10 | ''' 11 | 12 | def rev_wrd_ordr(fname='text.txt'): 13 | res = [] 14 | with open(fname) as f: 15 | res = [' '.join(line.strip().split()[::-1]) for line in f] 16 | return res 17 | 18 | print(rev_wrd_ordr()) 19 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-29-Add-numbers/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-29-Add-numbers/add_numbers.py: -------------------------------------------------------------------------------- 1 | 2 | def sum_numbers(numbers): 3 | return sum(int(number) 4 | for number in numbers.split() 5 | if number.isdigit()) 6 | 7 | print(sum_numbers('1 2 3 a b c 4')) 8 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-29-Add-numbers/add_numbers_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Show the lines of a text file that contain at least one vowel and contain 4 | more than 20 characters. 5 | ''' 6 | 7 | def show_lines(fname='text.txt'): 8 | res = [] 9 | with open(fname) as f: 10 | f_lines = filter(lambda x: len(x) > 20, (li for li in f)) 11 | for li in f_lines: 12 | for c in li: 13 | if c.lower() in 'aeiuo': 14 | print(li.rstrip()) 15 | break 16 | 17 | show_lines() 18 | 19 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-30-Flatten-a-list/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-30-Flatten-a-list/flatten.py: -------------------------------------------------------------------------------- 1 | 2 | mylist = [[10, 20, 30], [40, 50, 60], [70, 80, 90, 100]] 3 | 4 | def flatten(the_list): 5 | return [one_item 6 | for one_sublist in the_list 7 | for one_item in one_sublist] 8 | 9 | print(flatten(mylist)) 10 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-30-Flatten-a-list/flatten_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Redo this exercise, but replace each grandchild’s name (currently a string) 4 | with a dict. Each dict will contain two name-value pairs, name and age. Produce 5 | a list 6 | of the grandchildren’s names, sorted by age, from eldest to youngest. 7 | ''' 8 | 9 | my_fml_tr = {'A': {'B': 12, 'C': 7, 'D': 13}, 'E': {'F': 14, 'G': 1}} 10 | 11 | def sort_by_age(fml_tr): 12 | grandch = {in_k:fml_tr[k][in_k] 13 | for k in fml_tr 14 | for in_k in fml_tr[k]} 15 | print(grandch) 16 | return sorted(grandch, key=lambda x: grandch[x]) 17 | 18 | print(sort_by_age(my_fml_tr)) 19 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-31-Pig-Latin-translation-of-a-file/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-31-Pig-Latin-translation-of-a-file/plfile.py: -------------------------------------------------------------------------------- 1 | 2 | def plword(word): 3 | if word[0] in 'aeiou': 4 | return word + 'way' 5 | return word[1:] + word[0] + 'ay' 6 | 7 | def plfile(fname): 8 | return ' '.join(plword(one_word) 9 | for one_line in open(fname) 10 | for one_word in one_line.split()) 11 | 12 | print(plfile('sonnet_126.txt')) 13 | print('#####################') 14 | ### 15 | 16 | def plword(word): 17 | if word[0] in 'aeiou': 18 | return word + 'way' 19 | return word[1:] + word[0] + 'ay' 20 | 21 | def plfile(fname): 22 | return ' '.join(plword(one_word) 23 | for one_line in open(fname) 24 | for one_word in one_line.split()) 25 | 26 | print(plfile('sonnet_126.txt')) 27 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-31-Pig-Latin-translation-of-a-file/plfile_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Use a nested list comprehension to transform a list of dicts into a list 4 | of two- element (name-value) tuples, each of which represents one of the 5 | name-value pairs in one of the dicts. If more than one dict has the same 6 | name-value pair, then the tuple should appear twice. 7 | ''' 8 | 9 | def nested_lst(di_lst): 10 | tpl_lst = [ (k, item[k]) for item in di_lst for k in item] 11 | tpl = [tpl_lst.remove(item) for item in tpl_lst if tpl_lst.count(item) > 2] 12 | return tpl_lst 13 | 14 | print(nested_lst([{'a': 1}, {'a': 1, 'b': 2}, {'c': 1, 'b': 2, 'a': 1, 'd': 3}])) 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/flipped_dict.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | my_dict = {'a':1, 'b':2, 'c':3, 'd':3} 4 | 5 | def flipped_dict(a_dict): 6 | return { 7 | value : key 8 | for key, value in a_dict.items() 9 | } 10 | 11 | print(flipped_dict(my_dict)) 12 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/flipped_dict_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Given a string containing several (space-separated) words, create a dict 4 | in which the keys are the words, and the values are the number of vowels 5 | in each word. If the string is “this is an easy test,” then the resulting 6 | dict would be {'this':1, 'is':1, 'an':1, 'easy':2, 'test':1}. 7 | ''' 8 | 9 | def vwls_cnt_dict(a_str): 10 | vwls = 'aeuoi' 11 | return {word:sum([1 if c.lower() in vwls else 0 for c in word]) 12 | for word in a_str.split()} 13 | 14 | print(vwls_cnt_dict('this is an easy test,')) 15 | 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/flipped_dict_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Create a dict whose keys are filenames and whose values are the lengths of the 4 | files. The input can be a list of files from os.listdir (http://mng.bz/YreB) 5 | or glob.glob (http://mng.bz/044N). 6 | ''' 7 | """ 8 | from pathlib import Path 9 | 10 | def cnt_fl_di(cnt_pth): 11 | fl_di = {} 12 | my_path = Path(cnt_pth) 13 | fl_di = {fl.name:fl.stat().st_size for fl in my_path.iterdir() if fl.is_file()} 14 | return fl_di 15 | 16 | print(cnt_fl_di('my_data_dir')) 17 | """ 18 | 19 | import stylecloud 20 | 21 | stylecloud.gen_stylecloud(file_path='con.txt') 22 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/flipped_dict_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Find a configuration file in which the lines look like "name=value." 4 | Use a dict comprehension to read from the file, turning each line 5 | into a key-value pair. 6 | ''' 7 | 8 | 9 | def di_frm_fl(fname): 10 | with open(fname) as f: 11 | return {l.split(':')[0]:l.split(':')[1] for l in f} 12 | 13 | print(di_frm_fl('my_data_dir/config_file')) 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-33-Transform-values/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-33-Transform-values/transform_values.py: -------------------------------------------------------------------------------- 1 | 2 | d = {'a':1, 'b':2, 'c':3} 3 | 4 | def transform_values(func, a_dict): 5 | return {key : func(value) 6 | for key, value in a_dict.items()} 7 | 8 | def square(x): 9 | return x ** 2 10 | 11 | print(transform_values(square, d)) 12 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/get_sv.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def get_sv(fname): 4 | vwls = {'a', 'e', 'i', 'o', 'u'} 5 | return {word 6 | for word in open(fname) 7 | if vwls <= set(word.lower())} 8 | 9 | print(get_sv('words.txt')) 10 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/get_sv_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | In the /etc/passwd file you used earlier, what different shells (i.e., command interpreters, 3 | named in the final field on each line) are assigned to users? Use a set comprehension to gather them. 4 | ''' 5 | 6 | def shell_chq(sh_file): 7 | return {l.split(':').[-1].strip() 8 | for l in open(sh_file) 9 | if not l.startswith('#')} 10 | 11 | print(shell_chq('user_db_with_com.txt')) 12 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/get_sv_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a text file, what are the lengths of the different words? 3 | Return a set of different word lengths in the file. 4 | ''' 5 | 6 | def wo_lngth(a_file): 7 | return {len(wrd.strip()) 8 | for wrd in open(a_file)} 9 | 10 | print(wo_lngth('words.txt')) 11 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/get_sv_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Create a list whose elements are strings—the names of people in your family. 4 | Now use a set comprehension (and, better yet, a nested set comprehension) to 5 | find which letters are used in your family members’ names. 6 | """ 7 | 8 | # Author's solution 9 | 10 | import string 11 | 12 | def letters_in_names(list_of_names): 13 | return {one_letter 14 | for one_letter in ''.join(list_of_names) 15 | if one_letter in string.ascii_letters} 16 | 17 | my_lst_names = ['Iris', 'Angel', 'Carlos', 'Mariate', 'Miguel'] 18 | print(letters_in_names(my_lst_names)) 19 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-35-A-Gematria-Part-1/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-35-A-Gematria-Part-1/gematria_dict.py: -------------------------------------------------------------------------------- 1 | 2 | import string 3 | 4 | def gematria_dict(): 5 | return { 6 | char : index 7 | for index, char in enumerate(string.ascii_lowercase, 1) 8 | } 9 | 10 | print(gematria_dict()) 11 | 12 | ### 13 | 14 | import string 15 | 16 | def gematria_dict(): 17 | return { 18 | char:index 19 | for index, char in enumerate(string.ascii_lowercase, 1) 20 | } 21 | 22 | print(gematria_dict()) 23 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-35-A-Gematria-Part-1/gematria_dict_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Create a dict based on the config file, as in the previous exercise, but this time, all of the 4 | values should be integers. This means that you’ll need to filter out (and ignore) those values 5 | that can’t be turned into integers. 6 | ''' 7 | 8 | def crt_dct_int(a_file): 9 | return {l.split('=')[0].strip():int(l.split('=')[-1].strip()) 10 | for l in open(a_file) 11 | if l.split('=')[-1].strip().isdigit() 12 | } 13 | 14 | print(crt_dct_int('config.txt')) 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/gematria_equal_words.py: -------------------------------------------------------------------------------- 1 | 2 | import string 3 | 4 | def gematria_dict(): 5 | return {char: index 6 | for index, char 7 | in enumerate(string.ascii_lowercase, 1)} 8 | 9 | GEMATRIA = gematria_dict() 10 | 11 | def gematria_for(word): 12 | return sum(GEMATRIA.get(one_char, 0) 13 | for one_char in word) 14 | 15 | def gematria_equal_words(input_word): 16 | our_score = gematria_for(input_word.lower()) 17 | return [one_word.strip() 18 | for one_word in open('words.txt') 19 | if gematria_for(one_word.lower()) == our_score] 20 | 21 | print(gematria_equal_words('xylophone')) 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/gematria_equal_words_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a dict whose keys are city names, and whose values are temperatures in 3 | Fahrenheit. Now use a dict comprehension to transform this dict into a new one, 4 | keeping the old keys but turning the values into the temperature in degrees Celsius. 5 | ''' 6 | 7 | fahr_temp_di = {'Lisbon, Portugal':69, 'Stockholm, Sweden':36, 8 | 'Warsaw, Poland':41, 'Germany, Berlin':46} 9 | 10 | def conv_to_cels(): 11 | return {key: round((val-32) * (5/9)) 12 | for key, val in fahr_temp_di.items()} 13 | 14 | print(conv_to_cels()) 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/gematria_equal_words_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a list of tuples in which each tuple contains three elements: (1) the author’s 3 | first and last names, (2) the book’s title, and (3) the book’s price in U.S. dollars. 4 | 5 | Use a dict comprehension to turn this into a dict whose keys are the book’s titles, 6 | with the values being another (sub-) dict, with keys for (a) the author’s first name, 7 | (b) the author’s last name, and (c) the book’s price in U.S. dollars. 8 | ''' 9 | 10 | tpl_lst = [ ('Isaac Asimov','Foundation', 9), ('Frank Herbert','Dune', 12), (' George Orwell', 'Nineteen Eighty-Four', 15) ] 11 | 12 | def tpl_li_dct(): 13 | return {tt: {nm:pr} 14 | for nm, tt, pr in tpl_lst} 15 | 16 | print(tpl_li_dct()) 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/gematria_equal_words_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a dict whose keys are currency names and whose values are the price of that currency 3 | in U.S. dollars. Write a function that asks the user what currency they use, then returns 4 | the dict from the previous exercise as before, but with its prices converted into the requested currency. 5 | ''' 6 | 7 | def con_val(): 8 | d = {'lt': 0.28, 'us': 0.83} 9 | value = input('Enter price and currency, to translate it to euros: ') 10 | cur_name = value.lower().strip().split()[-1] 11 | cur_price = value.strip().split()[0] 12 | return round(int(cur_price) * d.get(cur_name, 2)) if d.get(cur_name, 0) else 'Currency unknown' 13 | 14 | print(con_val()) 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-07-Functional-programming-with-comprehensions/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-36-Sales-tax/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-36-Sales-tax/freedonia.py: -------------------------------------------------------------------------------- 1 | 2 | RATES = { 3 | 'Chico': 0.5, 4 | 'Groucho': 0.7, 5 | 'Harpo': 0.5, 6 | 'Zeppo': 0.4 7 | } 8 | 9 | def time_percentage(hour): 10 | return hour / 24 11 | 12 | def calculate_tax(amount, state, hour): 13 | return amount + (amount * RATES[state] * time_percentage(hour)) 14 | 15 | # print(calculate_tax(500, 'Harpo', 12)) 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-36-Sales-tax/sales_tax_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a module providing a function that, given a string, returns a dict 4 | indicating how many characters provide a True result to each of the following 5 | functions: str.isdigit, str.isalpha, and str.isspace. 6 | The keys should be isdigit, isalpha, and isspace. 7 | ''' 8 | 9 | def analyze_string(s): 10 | output = {'isdigit': 0, 11 | 'isalpha': 0, 12 | 'isspace': 0} 13 | 14 | for one_character in s: 15 | for methodname in output: 16 | if getattr(one_character, methodname)(): 17 | output[methodname] += 1 18 | return output 19 | 20 | print(analyze_string('root:*:0:0::0:0:System Administrator:/var/root:/bin/sh')) 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-36-Sales-tax/sales_tax_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | The dict.fromkeys method (http://mng.bz/1zrV) makes it easy to create a new dict. 4 | For example, dict.fromkeys('abc') will create the dict {'a':None, 'b':None, 'c':None}. 5 | You can also pass a value that will be assigned to each key, as in 6 | dict.fromkeys('abc', 5), resulting in the dict {'a':5, 'b':5, 'c':5}. Implement a function 7 | that does the same thing as dict.keys but whose second argument is a function. The value 8 | associated with the key will be the result of invoking f(key). 9 | ''' 10 | 11 | def fromkeys_func(s, func): 12 | output = {} 13 | for one_item in s: 14 | output[one_item] = func(one_item) 15 | return output 16 | 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-36-Sales-tax/using_freedonia_as_module.py: -------------------------------------------------------------------------------- 1 | 2 | from freedonia import calculate_tax 3 | 4 | tax_at_12noon = calculate_tax(100, 'Harpo', 12) 5 | tax_at_9pm = calculate_tax(100, 'Harpo', 21) 6 | 7 | print(f'You owe a total of: {tax_at_12noon}') 8 | print(f'You owe a total of: {tax_at_9pm}') 9 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-37-Menu/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-37-Menu/menu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Function that takes keyword arguments. The value 4 | associated with each key is a function taking zero arguments. 5 | The user is asked to enter input. 6 | If the input matches a keyword, then the associated function 7 | is invoked, and its return value is returned to the user. 8 | If the input doesn't match a keyword, the user is asked to 9 | try again. 10 | """ 11 | 12 | def menu(**options): 13 | while True: 14 | option_string = '/'.join(sorted(options)) 15 | choice = input(f'Enter an option ({option_string}): ') 16 | if choice in options: 17 | return options[choice]() 18 | print('Not a valid option') 19 | 20 | 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-37-Menu/menu_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Turn menu.py into a Python package and upload it to PyPI. (I suggest using 4 | your name or initials, followed by “menu,” to avoid name collisions.) See 5 | the sidebar on the difference between modules and packages, and how you can 6 | participate in the PyPI ecosystem with your own open-source projects. 7 | ''' 8 | 9 | def menu(**options): 10 | while True: 11 | option_string = '/'.join(sorted(options)) 12 | choice = input(f'Enter an option ({option_string}): ') 13 | if choice in options: 14 | return options[choice]() 15 | print('Not a valid option') 16 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-37-Menu/menu_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Define a module stuff with three variables—a, b, and c—and two functions— foo 4 | and bar. Define __all__ such that from stuff import * will cause a, c, and 5 | bar to be imported, but not b and foo. 6 | ''' 7 | 8 | 9 | __all__ = ['a', 'c', 'bar'] 10 | a = 100 11 | b = [10, 20, 30] 12 | c = {'a': 1, 'b': 2, 'c': 3} 13 | 14 | def foo(): 15 | return 'Hello from foo!' 16 | 17 | def bar(): 18 | return 'Hello from bar!' 19 | 20 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-37-Menu/using_menu_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Define a module stuff with three variables—a, b, and c—and two functions— foo 4 | and bar. Define __all__ such that from stuff import * will cause a, c, and 5 | bar to be imported, but not b and foo. 6 | ''' 7 | 8 | from menu_BTE_3 import a, c, bar 9 | 10 | print(a) 11 | print(c) 12 | print(bar()) 13 | 14 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/Exer-37-Menu/using_menu_as _module.py: -------------------------------------------------------------------------------- 1 | 2 | from menu import menu 3 | 4 | def func_a(): 5 | return 'A' 6 | 7 | def func_b(): 8 | return 'B' 9 | 10 | return_value = menu(a=func_a, b=func_b) 11 | 12 | print(f'Return value is {return_value}') 13 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-08-Modules-and-packages/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-38-Ice-cream-scoop/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-38-Ice-cream-scoop/scoop.py: -------------------------------------------------------------------------------- 1 | 2 | class Scoop: 3 | def __init__(self, flavor): 4 | self.flavor = flavor 5 | 6 | s1 = Scoop('chocolate') 7 | s2 = Scoop('vanilla') 8 | s3 = Scoop('persimmon') 9 | 10 | for one_scoop in [s1, s2, s3]: 11 | print(one_scoop.flavor) 12 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-38-Ice-cream-scoop/scoop_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a Beverage class whose instances will represent beverages. Each beverage 4 | should have two attributes: a name (describing the beverage) and a temperature. 5 | 6 | Create several beverages and check that their names and temperatures are all 7 | handled correctly. 8 | ''' 9 | 10 | class Beverage(): 11 | def __init__(self, name, temp): 12 | self.name = name 13 | self.temp = temp 14 | 15 | b1 = Beverage('coffee', 'hot') 16 | b2 = Beverage('ice tea', 'cold') 17 | b3 = Beverage('water', 'normal') 18 | 19 | for item in [b1, b2, b3]: 20 | print('The beverage {} is {}.'.format(item.name, item.temp)) 21 | 22 | 23 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-38-Ice-cream-scoop/scoop_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Modify the Beverage class, such that you can create a new instance specifying the name, 4 | and not the temperature. If you do this, then the temperature should have a default value 5 | of 75 degrees Celsius. Create several beverages and double-check that the temperature has 6 | this default when not specified. 7 | ''' 8 | 9 | class Beverage(): 10 | def __init__(self, name, temp=75): 11 | self.name = name 12 | self.temp = temp 13 | 14 | b1 = Beverage('coffee', 90) 15 | b2 = Beverage('ice tea', 5) 16 | b3 = Beverage('water') 17 | 18 | for item in [b1, b2, b3]: 19 | print('The beverage {} is {}.'.format(item.name, item.temp)) 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-38-Ice-cream-scoop/scoop_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Create a new LogFile class that expects to be initialized with a filename. Inside of __init__, 4 | open the file for writing and assign it to an attribute, file, that sits on the instance. 5 | Check that it’s possible to write to the file via the file attribute. 6 | ''' 7 | 8 | class LogFile(): 9 | def __init__(self, fname): 10 | self.file = open(fname, 'w') 11 | 12 | f1 = LogFile('text1.txt') 13 | f2 = LogFile('text2.txt') 14 | f3 = LogFile('text3.txt') 15 | 16 | 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-39-Ice-cream-bowl/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-39-Ice-cream-bowl/ice_cream_bowl.py: -------------------------------------------------------------------------------- 1 | 2 | class Scoop: 3 | def __init__(self, flavor): 4 | self.flavor = flavor 5 | 6 | class Bowl(): 7 | def __init__(self): 8 | self.scoops = [] 9 | 10 | def add_scoops(self, *new_scoops): 11 | for one_scoop in new_scoops: 12 | self.scoops.append(one_scoop) 13 | 14 | def __repr__(self): 15 | return '\n'.join(s.flavor for s in self.scoops) 16 | 17 | s1 = Scoop('chocolate') 18 | s2 = Scoop('vanilla') 19 | s3 = Scoop('persimmon') 20 | s4 = Scoop('flavor 4') 21 | s5 = Scoop('flavor 5') 22 | 23 | b = Bowl() 24 | b.add_scoops(s1, s2) 25 | b.add_scoops(s3, s4) 26 | b.add_scoops(s5) 27 | 28 | print(b) -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-39-Ice-cream-bowl/ice_cream_bowl_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Modify your Book class such that it adds another attribute, width. Then add 3 | a width attribute to each instance of Shelf. When add_book tries to add books 4 | whose combined widths will be too much for the shelf, raise an exception. 5 | ''' 6 | 7 | class Book(): 8 | def __init__(self, title, author, price, width): 9 | self.title = title 10 | self.author = author 11 | self.price = price 12 | self.width = width 13 | 14 | 15 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-40-Ice-cream-bowl-with-limits/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-40-Ice-cream-bowl-with-limits/ice_cream_bowl_with_limits.py: -------------------------------------------------------------------------------- 1 | 2 | class Scoop: 3 | def __init__(self, flavor): 4 | self.flavor = flavor 5 | 6 | class Bowl: 7 | max_scoops = 3 8 | 9 | def __init__(self): 10 | self.scoops = [] 11 | 12 | def add_scoops(self, *new_scoops): 13 | for one_scoop in new_scoops: 14 | if len(self.scoops) >= Bowl.max_scoops: 15 | break 16 | self.scoops.append(one_scoop) 17 | 18 | def __repr__(self): 19 | return '\n'.join(s.flavor for s in self.scoops) 20 | 21 | s1 = Scoop('chocolate') 22 | s2 = Scoop('vanilla') 23 | s3 = Scoop('persimmon') 24 | 25 | s4 = Scoop('flavor 4') 26 | s5 = Scoop('flavor 5') 27 | 28 | b = Bowl() 29 | b.add_scoops(s1, s2, s3) 30 | b.add_scoops(s4, s5) 31 | print(b) -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-40-Ice-cream-bowl-with-limits/ice_cream_bowl_with_limits_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Define a Person class, and a population class attribute that increases each time 4 | you create a new instance of Person. Double-check that after you’ve created five 5 | instances, named p1 through p5, Person.population and p1.population are both equal to 5. 6 | ''' 7 | 8 | class Person: 9 | population = 0 10 | def __init__(self, name): 11 | self.name = name 12 | Person.population += 1 13 | 14 | p1 = Person('James') 15 | p2 = Person('John') 16 | p3 = Person('Robert') 17 | p4 = Person('Michael') 18 | p5 = Person('William') 19 | 20 | print(Person.population) 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-40-Ice-cream-bowl-with-limits/ice_cream_bowl_with_limits_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Define a Transaction class, in which each instance represents either a deposit 4 | or a withdrawal from a bank account. When creating a new instance of Transaction, 5 | you’ll need to specify an amount—positive for a deposit and negative for a withdrawal. 6 | Use a class attribute to keep track of the current balance, which should be equal 7 | to the sum of the amounts in all instances created to date. 8 | ''' 9 | 10 | class Transaction: 11 | balance = 0 12 | def __init__(self, amount): 13 | self.amount = amount 14 | Transaction.balance += amount 15 | 16 | def __repr__(self): 17 | return str(Transaction.balance) 18 | 19 | t = Transaction(70) 20 | t = Transaction(-20) 21 | 22 | print(t) 23 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-41-A-bigger-bowl/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-41-A-bigger-bowl/person_class.py: -------------------------------------------------------------------------------- 1 | 2 | class Person(): 3 | def __init__(self, name): 4 | self.name = name 5 | 6 | def greet(self): 7 | return f'Hello, {self.name}' 8 | 9 | class Employee(Person): 10 | def __init__(self, name, id_number): 11 | super().__init__(name) 12 | self.id_number = id_number 13 | 14 | e = Employee('empname', 1) 15 | 16 | print(e.greet()) 17 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-42-FlexibleDict/FlexibleDict.py: -------------------------------------------------------------------------------- 1 | 2 | class FlexibleDict(dict): 3 | def __getitem__(self, key): 4 | try: 5 | if key in self: 6 | pass 7 | elif str(key) in self: 8 | key = str(key) 9 | elif int(key) in self: 10 | key = int(key) 11 | except ValueError: 12 | pass 13 | 14 | return dict.__getitem__(self, key) 15 | 16 | 17 | fd = FlexibleDict() 18 | 19 | fd['a'] = 100 20 | print(fd['a']) 21 | 22 | fd[5] = 500 23 | print(fd[5]) 24 | 25 | fd[1] = 100 26 | print(fd['1']) 27 | 28 | fd['1'] = 100 29 | print(fd[1]) 30 | 31 | 32 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-42-FlexibleDict/FlexibleDict_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | With FlexibleDict, we allowed the user to use any key, but were then 3 | flexible with the retrieval. Implement StringKeyDict, which converts 4 | its keys into strings as part of the assignment. Thus, immediately 5 | after saying skd[1] = 10, you would be able to then say skd['1'] and 6 | get the value of 10 returned. This can come in handy if you’ll be reading 7 | keys from a file and won’t be able to distinguish between strings and integers. 8 | ''' 9 | 10 | class StringKeyDict(dict): 11 | def __setitem__(self, key, value): 12 | dict.__setitem__(self, str(key), value) 13 | 14 | skd = StringKeyDict() 15 | 16 | skd[1] = 10 17 | print(skd['1']) 18 | print(type(skd.keys())) 19 | 20 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-42-FlexibleDict/FlexibleDict_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The FlatList class inherits from list and overrides the append method. 3 | If append is passed an iterable, then it should add each element of the 4 | iterable separately. This means that fl.append([10, 20, 30]) would not 5 | add the list [10, 20, 30] to fl, but would rather add the individual 6 | integers 10, 20, and 30. You might want to use the built-in iter 7 | function (http://mng.bz/Qy2G) to determine whether the passed argument 8 | is indeed iterable. 9 | ''' 10 | 11 | class FlatList(list): 12 | def append(self, new_value): 13 | try: 14 | for one_item in new_value: 15 | list.append(self, one_item) 16 | except TypeError: 17 | list.append(self, new_value) 18 | 19 | fl = FlatList([10, 20, 30]) 20 | print(fl) 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-42-FlexibleDict/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-43-Animals/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-44-Cage/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/Exer-45-Zoo/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-09-Objects/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-46-MyEnumerate/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-46-MyEnumerate/louditerator_class.py: -------------------------------------------------------------------------------- 1 | class LoudIterator(): 2 | def __init__(self, data): 3 | print('\tNow in __init__') 4 | self.data = data 5 | self.index = 0 6 | 7 | def __iter__(self): 8 | print('\tNow in __iter__') 9 | return self 10 | 11 | def __next__(self): 12 | print('\tNow in __next__') 13 | if self.index >= len(self.data): 14 | print(f'\tself.index ({self.index}) is too big; exiting') 15 | raise StopIteration 16 | 17 | value = self.data[self.index] 18 | self.index += 1 19 | print('\tGot value {value}, incremented index to {self.index}') 20 | return value 21 | 22 | 23 | for one_item in LoudIterator("abc"): 24 | print(one_item) 25 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-46-MyEnumerate/myenumerate.py: -------------------------------------------------------------------------------- 1 | class MyEnumerate(): 2 | def __init__(self, data): 3 | self.data = data 4 | self.index = 0 5 | 6 | def __iter__(self): 7 | return self 8 | 9 | def __next__(self): 10 | if self.index >= len(self.data): 11 | raise StopIteration 12 | value = (self.index, self.data[self.index]) 13 | self.index += 1 14 | return value 15 | 16 | for index, letter in MyEnumerate('abc'): 17 | print(f'{index} : {letter}') -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-46-MyEnumerate/myenumerate_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Redefine MyEnumerate as a generator function, rather than as a class. 4 | ''' 5 | 6 | def my_enumerate(data, start=0): 7 | index = start 8 | 9 | for one_item in data: 10 | yield (index, one_item) 11 | index += 1 12 | 13 | print(my_enumerate('abcd')) 14 | print(*my_enumerate('abcd', 1)) -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-47-Circle/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-47-Circle/circle_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Implement Circle as a generator function, rather than as a class. 4 | ''' 5 | 6 | def circle(data, max_times): 7 | for index in range(max_times): 8 | yield data[index % len(data)] 9 | 10 | c = circle("abcd", 7) 11 | 12 | print('** A **') 13 | for one_item in c: 14 | print(one_item) 15 | 16 | print('** B **') 17 | for one_item in c: 18 | print(one_item) -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-48-All-lines-all-files/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-48-All-lines-all-files/all_lines.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write an iterator (as a generator function) that returns each line 3 | from each file in a named directory. 4 | 5 | Any file that cannot be opened, for whatever reason, is ignored. 6 | ''' 7 | import os 8 | def all_lines(path): 9 | for filename in os.listdir(path): 10 | full_filename = os.path.join(path, filename) 11 | try: 12 | for line in open(full_filename): 13 | yield line 14 | except OSError: 15 | pass 16 | 17 | for one_line in all_lines('Files'): 18 | print(one_line) 19 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-49-Elapsed-since/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-49-Elapsed-since/elapsed_since.py: -------------------------------------------------------------------------------- 1 | ''' 2 | A generator that takes an iterable as input. 3 | 4 | With each iteration, it yields a tuple containing the data and the time 5 | since the previous iteration. 6 | ''' 7 | import time 8 | import random 9 | 10 | def elapsed_since(data): 11 | last_time = None 12 | for one_item in data: 13 | current_time = time.perf_counter() 14 | delta = current_time - (last_time or current_time) 15 | last_time = time.perf_counter() 16 | yield (delta, one_item) 17 | 18 | for t in elapsed_since('abcd'): 19 | time.sleep(random.randint(0, 2)) 20 | print(t) 21 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-49-Elapsed-since/elapsed_since_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a generator function that takes two elements: an iterable and 4 | a function. With each iteration, the function is invoked on the current 5 | element. If the result is True, then the element is returned as is. 6 | Otherwise, the next element is tested, until the function returns True. 7 | Alternative: implement this as a regular function that returns a generator expression. 8 | ''' 9 | 10 | from curses.ascii import isalpha 11 | 12 | 13 | def yield_filter(data, func): 14 | for one_item in data: 15 | if func(one_item): 16 | yield one_item 17 | 18 | def is_alpha(item): 19 | return item.isalpha() 20 | 21 | for item in yield_filter('+abcd23@', isalpha): 22 | print(item) 23 | 24 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-50-MyChain/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/Exer-50-MyChain/mychain.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Generator that takes any number of iterables as arguments. It yields, one at 3 | a time, each of the elements of each iterable. 4 | 5 | It is similar to itertools.chain 6 | ''' 7 | 8 | def mychain(*args): 9 | for one_item in args: 10 | for one_element in one_item: 11 | yield one_element 12 | 13 | for one_item in mychain('abc', [10, 20, 30, 40, 50], (100, 200, 300), [2, 4, 6]): 14 | print(one_item) -------------------------------------------------------------------------------- /2nd-Loop/CHPT-10-Iterators-and-generators/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2nd-Loop/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-01-Number-guessing-game/Number-guessing-game.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def guessing_game(): 4 | answer = random.randint(0, 100) 5 | 6 | while True: 7 | user_guess = int(input('What is your guess? ')) 8 | 9 | if user_guess == answer: 10 | print(f'Right! The answer is {user_guess}') 11 | break 12 | 13 | if user_guess < answer: 14 | print(f'Your guess of {user_guess} is too low!') 15 | 16 | else: 17 | print(f'Your guess of {user_guess} is too high!') 18 | 19 | guessing_game() 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-01-Number-guessing-game/Number-guessing-game_BTE_1.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def guessing_game(): 4 | answer = random.randint(0, 100) 5 | guess_num = 0 6 | 7 | while guess_num < 3: 8 | user_guess = int(input('What is your guess? ')) 9 | guess_num += 1 10 | 11 | if user_guess == answer: 12 | print(f'Right! The answer is {user_guess}') 13 | break 14 | 15 | if user_guess < answer: 16 | print(f'Your guess of {user_guess} is too low!') 17 | 18 | else: 19 | print(f'Your guess of {user_guess} is too high!') 20 | 21 | guessing_game() 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-01-Number-guessing-game/Number-guessing-game_BTE_3.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def guessing_game(): 4 | mylist = ["apple", "banana", "cherry"] 5 | answer = random.choice(mylist) 6 | guess_num = 0 7 | 8 | while guess_num < 3: 9 | user_guess = str(input('Pick a fruit. What is your guess? ')) 10 | guess_num += 1 11 | 12 | if user_guess == answer: 13 | print(f'Right! The answer is {user_guess}') 14 | break 15 | 16 | if user_guess < answer: 17 | print(f'Your guess {user_guess} is not correct!') 18 | 19 | else: 20 | print(f'Your guess {user_guess} is not correct!') 21 | 22 | guessing_game() 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-02-Summing-numbers/summing-numbers.py: -------------------------------------------------------------------------------- 1 | def mysum(*numbers): 2 | output = 0 3 | for number in numbers: 4 | output += number 5 | return output 6 | 7 | print(mysum(10, 20, 30, 40)) 8 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-02-Summing-numbers/summing-numbers_BTE_1.py: -------------------------------------------------------------------------------- 1 | def mysum(li, num = 0): 2 | output = 0 3 | for item in li: 4 | output += item 5 | return output + num 6 | 7 | print(mysum([1, 2, 3], 4)) 8 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-02-Summing-numbers/summing-numbers_BTE_2.py: -------------------------------------------------------------------------------- 1 | def mysum(li): 2 | output = 0 3 | len_li = len(li) 4 | for item in li: 5 | output += item 6 | avg_num = output // len_li 7 | return avg_num 8 | 9 | print(mysum([10, 20, 30, 40])) 10 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-02-Summing-numbers/summing-numbers_BTE_4.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that takes a list of Python objects. Sum the objects 3 | that either are integers or can be turned into integers, ignoring the others. 4 | ''' 5 | 6 | def sum_int(li): 7 | val = 0 8 | for item in li: 9 | try: 10 | val += int(item) 11 | except ValueError: 12 | pass 13 | return val 14 | 15 | 16 | mylist = [1, 2, 3, 6.5, '4', 'A', 'B'] 17 | 18 | print(sum_int(mylist)) 19 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-03-Run-timing/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-03-Run-timing/run-timing-BTE-1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that takes a float and two integers (before and after). 3 | The function should return a float consisting of before digits 4 | before the decimal point and after digits after. Thus, if we call 5 | the function with 1234.5678, 2 and 3, the return value should be 34.567. 6 | ''' 7 | 8 | def cropNumber(fl_num, bef_int_num, aft_int_num): 9 | # Digits before decimal point 10 | str_bef = str(int(fl_num)) 11 | str_bef = str_bef[-bef_int_num:] 12 | str_fl = float(str_bef) 13 | 14 | # Digits after decimal point 15 | num_dec = fl_num - int(fl_num) 16 | num_dec = str(num_dec) 17 | num_dec = num_dec[0:aft_int_num + 2] 18 | 19 | return str_fl + float(num_dec) 20 | 21 | 22 | print(cropNumber(1234.5678, 2, 3)) 23 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-03-Run-timing/run-timing-BTE-2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Explore the Decimal class (http://mng.bz/oPVr), which has an alternative floating-point 3 | representation that’s as accurate as any decimal number can be. Write a function 4 | that takes two strings from the user, turns them into decimal instances, 5 | and then prints the floating-point sum of the user’s two inputs. 6 | In other words, make it possible for the user to enter 0.1 and 0.2, and for us to get 0.3 back. 7 | ''' 8 | 9 | def add_flo(val1, val2): 10 | sum_of_flo = float(val1 + val2) 11 | return f"{sum_of_flo:.1f}" 12 | 13 | print(add_flo(0.1, 0.2)) 14 | 15 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-03-Run-timing/run-timing.py: -------------------------------------------------------------------------------- 1 | def run_timing(): 2 | """Asks the user repeatedly for numeric input. Prints the average time 3 | an d number of runs.""" 4 | 5 | number_of_runs = 0 6 | total_time = 0 7 | 8 | while True: 9 | one_run = input('Enter 10 km run time: ') 10 | 11 | if one_run == '0': 12 | break 13 | 14 | if not one_run: 15 | break 16 | 17 | number_of_runs += 1 18 | total_time += float(one_run) 19 | 20 | average_time = total_time / number_of_runs 21 | 22 | print(f'Average of {average_time}, over {number_of_runs} runs') 23 | 24 | run_timing() 25 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-04-Hexadecimal-output/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-04-Hexadecimal-output/hexadecimal-output.py: -------------------------------------------------------------------------------- 1 | def hex_output(): 2 | decnum = 0 3 | hexnum = input('Enter a hex number to convert: ') 4 | for power, digit in enumerate(reversed(hexnum)): 5 | decnum += int(digit, 16) * (16 ** power) 6 | print(decnum) 7 | 8 | hex_output() 9 | -------------------------------------------------------------------------------- /CHPT-01-Numeric-Types/Exer-04-Hexadecimal-output/hexadecimal-output_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a program that asks the user for their name and then produces a “name triangle”: 3 | the first letter of their name, then the first two letters, then the first three, 4 | and so forth, until the entire name is written on the final line. 5 | ''' 6 | 7 | n = input('Your name? ') 8 | n_l = '' 9 | for ch in n: 10 | n_l += ch 11 | print(n_l) 12 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-05-Pig-Latin/C5-Handle-capitalized-words.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Handle capitalized words—If a word is capitalized (i.e., the first letter is capitalized, 3 | but the rest of the word isn’t), then the Pig Latin translation should be similarly capitalized. 4 | ''' 5 | 6 | def pig_latin(word): 7 | final_string = '' 8 | if word[0] in 'aeiou': 9 | final_string = word + 'way' 10 | return final_string.capitalize() 11 | else: 12 | final_string = word[1:] + word[:1] + 'ay' 13 | return final_string.capitalize() 14 | 15 | print(pig_latin('python')) 16 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-05-Pig-Latin/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-05-Pig-Latin/pig_latin.py: -------------------------------------------------------------------------------- 1 | def pig_latin(word): 2 | if word[0] in 'aeiou': 3 | return f'{word}way' 4 | else: 5 | return f'{word[1:]}{word[:1]}ay' 6 | 7 | print(pig_latin('computer')) 8 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-06-Pig-Latin-sentence/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-06-Pig-Latin-sentence/pig-latin-sentence-BTE-1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Take a text file, creating (and printing) a nonsensical sentence from the nth 4 | word on each of the first 10 lines, where n is the line number. 5 | ''' 6 | 7 | N = int(input("Take a number between 0 - 5: ")) 8 | 9 | st_nouns = "puppy car rabbit girl monkey" 10 | st_verbs = "runs hits jumps drives barfs" 11 | st_adv = "crazily dutifully foolishly merrily occasionally" 12 | st_adj = "adorable clueless dirty odd stupid" 13 | 14 | nouns_tup = tuple(st_nouns.split(' ')) 15 | verbs_tup = tuple(st_verbs.split(' ')) 16 | adv_tup = tuple(st_adv.split(' ')) 17 | adj_tup = tuple(st_adj.split(' ')) 18 | 19 | print(nouns_tup[N].capitalize() + ' ' + verbs_tup[N] + ' ' + adv_tup[N] + ' ' + adj_tup[N] + '.') 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-06-Pig-Latin-sentence/pig-latin-sentence-BTE-2-alternative-solution-2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that transposes a list of strings, in which each string contains 4 | multiple words separated by whitespace. Specifically, it should perform in such a way 5 | that if you were to pass the list ['abc def ghi', 'jkl mno pqr', 'stu vwx yz'] to the function, 6 | it would return ['abc jkl stu', 'def mno vwx', 'ghi pqr yz']. 7 | ''' 8 | 9 | old_list = ['abc def ghi', 'jkl mno pqr', 'stu vwx yz'] 10 | 11 | 12 | def li_change(li): 13 | new_li = [] 14 | for i in range(len(li)): 15 | li[i] = li[i].split() 16 | for i in range(len(li)): 17 | new_li += [' '.join([nested_li[i] for nested_li in li])] 18 | return new_li 19 | 20 | result = li_change(old_list) 21 | 22 | print(result) 23 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-06-Pig-Latin-sentence/pig-latin-sentence-BTE-2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that transposes a list of strings, in which each string contains 4 | multiple words separated by whitespace. Specifically, it should perform in such a way 5 | that if you were to pass the list ['abc def ghi', 'jkl mno pqr', 'stu vwx yz'] to the function, 6 | it would return ['abc jkl stu', 'def mno vwx', 'ghi pqr yz']. 7 | ''' 8 | 9 | old_list = ['abc def ghi', 'jkl mno pqr', 'stu vwx yz'] 10 | 11 | lists = [x.split() for x in old_list] 12 | 13 | print([" ".join(x) for x in zip(*lists)]) 14 | 15 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-06-Pig-Latin-sentence/pig-latin-sentence.py: -------------------------------------------------------------------------------- 1 | 2 | def pl_sentence(sentence): 3 | output = [] 4 | for word in sentence.split(): 5 | if word[0] in 'aeiou': 6 | output.append(f'{word}way') 7 | else: 8 | output.append(f'{word[1:]}{word[0]}ay') 9 | 10 | return ' '.join(output) 11 | 12 | print(pl_sentence('this is a test')) 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-07-Ubbi-Dubbi/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-07-Ubbi-Dubbi/ubbi-dubbi-BTE-1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Handle capitalized words—If a word is capitalized (i.e., the first letter is capitalized, 4 | but the rest of the word isn’t), then the Ubbi Dubbi translation should be similarly capitalized. 5 | ''' 6 | 7 | def ubbi_dubbi(word): 8 | output = [] 9 | for letter in word: 10 | if letter in 'aeiou': 11 | output.append(f'ub{letter}') 12 | if word.isupper(): 13 | word.isupper() 14 | else: 15 | output.append(letter) 16 | 17 | return ''.join(output) 18 | 19 | print(ubbi_dubbi('python')) 20 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-07-Ubbi-Dubbi/ubbi-dubbi.py: -------------------------------------------------------------------------------- 1 | 2 | def ubbi_dubbi(word): 3 | output = [] 4 | for letter in word: 5 | if letter in 'aeiou': 6 | output.append(f'ub{letter}') 7 | else: 8 | output.append(letter) 9 | 10 | return ''.join(output) 11 | 12 | print(ubbi_dubbi('python')) 13 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-08-Sorting-a-string/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-08-Sorting-a-string/my_text.txt: -------------------------------------------------------------------------------- 1 | Python is an interpreted high-level general-purpose programming language. Its design philosophy emphasizes code readability with its use of significant indentation. Its language constructs as well as its object-oriented approach aim to help programmers write clear, logical code for small and large-scale projects. Python is dynamically-typed and garbage-collected. It supports multiple programming paradigms, including structured (particularly, procedural), object-oriented and functional programming. It is often described as a "batteries included" language due to its comprehensive standard library. -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-08-Sorting-a-string/sorting-a-string-BTE-1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Given the string “Tom Dick Harry,” break it into individual words, 4 | and then sort those words alphabetically. Once they’re sorted, print them 5 | with commas (,) between the names. 6 | ''' 7 | 8 | s = "Tom Dick Harry" 9 | 10 | splitted_and_sorted = sorted(s.split()) 11 | 12 | result = ', '.join(splitted_and_sorted) 13 | 14 | print(result) 15 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-08-Sorting-a-string/sorting-a-string-BTE-2.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Which is the longest word in a text file? 4 | """ 5 | 6 | def find_longest(fname): 7 | lo_wo = '' 8 | with open(fname,'r') as f: 9 | for li in f: 10 | t = '' 11 | for c in li: 12 | if c.isalnum() or c ==' ': t += c 13 | lgt = sorted(t.split(), key=len)[-1] 14 | if len(lo_wo) < len(lgt): lo_wo = lgt 15 | return lo_wo, len(lo_wo) 16 | 17 | print(find_longest('my_text.txt')) 18 | 19 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-08-Sorting-a-string/sorting-a-string-BTE-3.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Which is the last word, alphabetically, in a text file? 4 | """ 5 | 6 | def find_last(fname): 7 | la_wo = '' 8 | with open(fname,'r') as f: 9 | for l in f: 10 | t = '' 11 | for c in l: 12 | if c.isalnum() or c ==' ': 13 | t += c 14 | final = sorted(t.split())[-1] 15 | if la_wo < final: 16 | la_wo = final 17 | return la_wo 18 | 19 | 20 | print(find_last('my_text.txt')) 21 | 22 | -------------------------------------------------------------------------------- /CHPT-02-Strings/Exer-08-Sorting-a-string/sorting-a-string.py: -------------------------------------------------------------------------------- 1 | 2 | def strsort(a_string): 3 | return ''.join(sorted(a_string)) 4 | 5 | print(strsort('cbjeaf')) 6 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-09-First-last/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that takes a list or tuple of numbers. Return a two-element list, 4 | containing (respectively) the sum of the even-indexed numbers and the sum of the odd-indexed numbers. 5 | So calling the function as even_odd_sums([10, 20, 30, 40, 50, 60]), you’ll get back [90, 120]. 6 | ''' 7 | 8 | def even_odd_sums(sequence): 9 | even_sum = 0 10 | odd_sum = 0 11 | for i, item in enumerate(sequence): 12 | if i % 2 == 0: 13 | even_sum += item 14 | else: 15 | odd_sum += item 16 | return even_sum, odd_sum 17 | 18 | print(even_odd_sums([10, 20, 30, 40, 50, 60])) 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that takes a list or tuple of numbers. Return a two-element list, 4 | containing (respectively) the sum of the even-indexed numbers and the sum of the odd-indexed numbers. 5 | So calling the function as even_odd_sums([10, 20, 30, 40, 50, 60]), you’ll get back [90, 120]. 6 | 7 | Alternative Solution-I 8 | ''' 9 | 10 | 11 | def even_odd_sums(iter): 12 | return [sum(iter[::2]), sum(iter[1::2])] 13 | 14 | print(even_odd_sums([10, 20, 30, 40, 50, 60])) 15 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that takes a list or tuple of numbers. Return a two-element list, 4 | containing (respectively) the sum of the even-indexed numbers and the sum of the odd-indexed numbers. 5 | So calling the function as even_odd_sums([10, 20, 30, 40, 50, 60]), you’ll get back [90, 120]. 6 | 7 | Alternative Solution-II: 8 | ''' 9 | 10 | 11 | def even_odd_sums(seq): 12 | 13 | sum_even = sum(seq[0::2]) 14 | sum_odd = sum(seq[1::2]) 15 | return [sum_even, sum_odd] 16 | 17 | print(even_odd_sums([10, 20, 30, 40, 50, 60])) 18 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-4.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that takes a list or tuple of numbers. Return the result of alternately adding and subtracting numbers 3 | from each other. So calling the function as plus_minus([10, 20, 30, 40, 50, 60]), 4 | you’ll get back the result of 10+20-30+40-50+60, or 50. 5 | ''' 6 | 7 | def plus_minus(iter): 8 | str_acc = f'{iter[0]}' 9 | num_sum = iter[0] 10 | for i in range(1, len(iter)): 11 | if not (i % 2): 12 | str_acc += f'-{iter[i]}' 13 | num_sum -= iter[i] 14 | else: 15 | str_acc += f'+{iter[i]}' 16 | num_sum += iter[i] 17 | return str_acc, num_sum 18 | 19 | 20 | print(plus_minus([10, 20, 30, 40, 50, 60])) 21 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-5.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that takes a list or tuple of numbers. Return the result of alternately adding and subtracting numbers 3 | from each other. So calling the function as plus_minus([10, 20, 30, 40, 50, 60]), 4 | you’ll get back the result of 10+20-30+40-50+60, or 50. 5 | 6 | Alternative solution: 7 | ''' 8 | 9 | def plus_minus(seq): 10 | 11 | return seq[0] + sum(seq[1::2]) - sum(seq[2::2]) 12 | 13 | 14 | print(plus_minus([10, 20, 30, 40, 50, 60])) 15 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast-BTE-6.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that partly emulates the built-in zip function (http://mng.bz/ Jyzv), 4 | taking any number of iterables and returning a list of tuples. Each tuple will contain 5 | one element from each of the iterables passed to the function. Thus, if I call 6 | myzip([10, 20,30], 'abc'), the result will be [(10, 'a'), (20, 'b'), (30, 'c')]. You can return 7 | a list (not an iterator) and can assume that all of the iterables are of the same length. 8 | ''' 9 | 10 | def myzip(iterable): 11 | new_iter = [[(elem[x]) for elem in iterable] for x in range(len(iterable[0]))] 12 | return [tuple(elem) for elem in new_iter] 13 | 14 | 15 | print(myzip([[10, 20,30], 'abc'])) 16 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-09-First-last/firstlast.py: -------------------------------------------------------------------------------- 1 | 2 | def firstlast(sequence): 3 | return sequence[:1] + sequence[-1:] 4 | 5 | test_str = 'abc' 6 | test_lst = [1, 2, 3, 4] 7 | 8 | print(firstlast(test_str)) 9 | print(firstlast(test_lst)) 10 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-10-Summing-anything/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-10-Summing-anything/mysum.py: -------------------------------------------------------------------------------- 1 | 2 | def mysum(*items): 3 | if not items: 4 | return items 5 | output = items[0] 6 | for item in items[1:]: 7 | output += item 8 | return output 9 | 10 | #print(mysum()) 11 | #print(mysum(10, 20, 30, 40)) 12 | #print(mysum('a', 'b', 'c', 'd')) 13 | print(mysum([10, 20, 30], [40, 50, 60], [70, 80])) 14 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-10-Summing-anything/mysum_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that takes a list of dicts and returns a single dict that combines 3 | all of the keys and values. If a key appears in more than one argument, the value should 4 | be a list containing all of the values from the arguments. 5 | ''' 6 | 7 | def sum_dict(li_dict): 8 | fin_dict = {} 9 | for item in li_dict: 10 | for k in item: 11 | if k in fin_dict: 12 | fin_dict[k] = list(fin_dict[k]) + [item[k]] 13 | else: 14 | fin_dict[k] = item[k] 15 | return fin_dict 16 | 17 | 18 | print(sum_dict([ {1: 'a', 2: 'b'}, {1: 'c', 3: 'd'}, {1: 'a', 2: 'b', 4: 'f'} ])) 19 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names.py: -------------------------------------------------------------------------------- 1 | 2 | import operator 3 | 4 | PEOPLE = [{'first': 'Reuven', 'last': 'Lerner', 5 | 'email': 'reuven@lerner.co.il'}, 6 | {'first': 'Donald', 'last': 'Trump', 7 | 'email': 'president@whitehouse.gov'}, 8 | {'first': 'Vladimir', 'last': 'Putin', 9 | 'email': 'president@kremvax.ru'} 10 | ] 11 | 12 | def alphabetize_names(list_of_dicts): 13 | return sorted(list_of_dicts, 14 | key=operator.itemgetter('last', 'first')) 15 | 16 | print(alphabetize_names(PEOPLE)) 17 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a sequence of positive and negative numbers, sort them by absolute value. 3 | ''' 4 | 5 | def sorting_numbers(iter): 6 | return sorted(iter, key=abs) 7 | 8 | print(sorting_numbers([7, 15, 20, 1])) 9 | 10 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of strings, sort them according to how many vowels they contain. 3 | ''' 4 | 5 | 6 | def vowel_sort(iter): 7 | VOWELS = ['a', 'e', 'i', 'o', 'u'] 8 | return sorted(iter, key=lambda x: sum([x.count(c) for c in VOWELS])) 9 | 10 | str_lst = ['eyewitness', 'Robot', 'abbreviation'] 11 | 12 | print(vowel_sort(str_lst)) 13 | 14 | 15 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_2_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of strings, sort them according to how many vowels they contain. 3 | ''' 4 | 5 | 6 | def vowel_sort(iter): 7 | 8 | return sorted(iter, key=lambda x: x.count('a') + x.count('e') + x.count('u') + 9 | x.count('i') + x.count('o')) 10 | 11 | 12 | 13 | str_lst = ['eyewitness', 'Robot', 'abbreviation'] 14 | 15 | print(vowel_sort(str_lst)) 16 | 17 | 18 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_2_alternative_solution_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of strings, sort them according to how many vowels they contain. 3 | ''' 4 | 5 | def vowel_cnt(word): 6 | cnt = 0 7 | for ch in word.lower(): 8 | if ch in 'aeiou': 9 | cnt += 1 10 | return cnt 11 | 12 | 13 | def vowel_sort(iter): 14 | return sorted(iter, key=vowel_cnt) 15 | 16 | 17 | str_lst = ['eyewitness', 'Robot', 'abbreviation'] 18 | 19 | print(vowel_sort(str_lst)) 20 | 21 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-11-Alphabetizing-names/alphabetize_names_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of lists, with each list containing zero or more numbers, 3 | sort by the sum of each inner list’s numbers. 4 | ''' 5 | 6 | my_list = [[0, 1, 2], [3, 4], []] 7 | 8 | 9 | def sort_lst(iter): 10 | return sorted(iter, key=sum) 11 | 12 | print(sort_lst(my_list)) 13 | 14 | 15 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/most_repeating_word.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from collections import Counter 4 | import operator 5 | 6 | WORDS = ['this', 'is', 'an', 'elementary', 'test', 'example'] 7 | 8 | def most_repeating_letter_count(word): 9 | return Counter(word).most_common(1)[0][1] 10 | 11 | 12 | def most_repeating_word(words): 13 | return max(words, 14 | key=most_repeating_letter_count) 15 | 16 | print(most_repeating_word(WORDS)) 17 | 18 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/most_repeating_word_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Instead of finding the word with the greatest number of repeated letters, 4 | find the word with the greatest number of repeated vowels. 5 | ''' 6 | 7 | from collections import Counter 8 | 9 | WORDS = ['this', 'is', 'an', 'elementary', 'test', 'example'] 10 | 11 | def vow_word(wo): 12 | vwl = ('a', 'e', 'i', 'o', 'u') 13 | c = Counter(wo) 14 | return max([c[v] for v in vwl]) 15 | 16 | 17 | def most_rep_vwl(wos): 18 | return max(wos,key=vow_word) 19 | 20 | print(most_rep_vwl(WORDS)) 21 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/most_repeating_word_BTE_1_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Instead of finding the word with the greatest number of repeated letters, 4 | find the word with the greatest number of repeated vowels. 5 | ''' 6 | 7 | from collections import Counter 8 | 9 | WORDS = ['this', 'is', 'an', 'elementary', 'test', 'example'] 10 | 11 | 12 | 13 | def vow_word(wo): 14 | vwl = '' 15 | for ch in wo.lower(): 16 | if ch in 'aeiou': 17 | vwl += ch 18 | 19 | return Counter(vwl).most_common(1)[0][1] 20 | 21 | def most_rep_vwl(wos): 22 | return max(wos, key=vow_word) 23 | 24 | print(most_rep_vwl(WORDS)) 25 | 26 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-12-Word-with-most-repeated-letters/most_repeating_word_BTE_1_alternative_solution_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Instead of finding the word with the greatest number of repeated letters, 4 | find the word with the greatest number of repeated vowels. 5 | ''' 6 | 7 | from collections import Counter 8 | import operator 9 | 10 | WORDS = ['this', 'is', 'an', 'elementary', 'test', 'example'] 11 | 12 | def most_rep(wo): 13 | return operator.getitem(operator.getitem(Counter(wo).most_common(), 0), 1) 14 | 15 | def vwl_cnt(wo): 16 | vwl = 'aeuio' 17 | filter(lambda x: x in vwl, wo) 18 | return most_rep(wo) 19 | 20 | def most_repeating_vwl(wos): 21 | return max(wos, key=vwl_cnt) 22 | 23 | print(most_repeating_vwl(WORDS)) 24 | 25 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-13-Printing-tuple-records/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-03-Lists-and-tuples/Exer-13-Printing-tuple-records/format_sort_records.py: -------------------------------------------------------------------------------- 1 | 2 | from operator import itemgetter 3 | 4 | PEOPLE = [('Donald', 'Trump', 7.85), 5 | ('Vladimir', 'Putin', 3.626), 6 | ('Jinping', 'Xi', 10.603)] 7 | 8 | def format_sort_records(list_of_tuples): 9 | output = [] 10 | template = '{1:10} {0:10} {2:5.2f}' 11 | 12 | for one_person in sorted(list_of_tuples, key=itemgetter(1, 0)): 13 | output.append(template.format(*one_person)) 14 | 15 | return output 16 | 17 | print('\n'.join(format_sort_records(PEOPLE))) 18 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-14-Restaurant/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-14-Restaurant/restaurant.py: -------------------------------------------------------------------------------- 1 | 2 | MENU = {'sandwich':10, 'tea':7, 'salad':9} 3 | 4 | def restaurant(): 5 | 6 | total = 0 7 | while True: 8 | order = input("Enter your order: ").strip() 9 | 10 | if not order: 11 | break 12 | 13 | if order in MENU: 14 | price = MENU[order] 15 | total += int(price) 16 | print(f'{order} costs {price}, total is now {total}') 17 | 18 | else: 19 | print(f'We are fresh out of {order} today.') 20 | 21 | print(f'Your total is {total}') 22 | 23 | restaurant() 24 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/rainfall.py: -------------------------------------------------------------------------------- 1 | 2 | def get_rainfall(): 3 | rainfall = {} 4 | 5 | while True: 6 | city_name = input("Enter city name: ").strip() 7 | 8 | if not city_name: 9 | break 10 | 11 | mm_rain = input("Enter mm rain: ") 12 | rainfall[city_name] = rainfall.get(city_name, 0) + int(mm_rain) 13 | 14 | for key, value in rainfall.items(): 15 | print(f'{key}: {value}') 16 | 17 | get_rainfall() 18 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/rainfall_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Open a log file from a Unix/Linux system—for example, one from the Apache 3 | server. For each response code (i.e., three-digit code indicating the HTTP 4 | request’s success or failure), store a list of IP addresses that generated 5 | that code. 6 | ''' 7 | 8 | def log_chq(fname): 9 | 10 | rsp_code = {} 11 | with open(fname, 'r') as f: 12 | for l in f: 13 | l = l.split() 14 | print(l) 15 | rsp_code[l[8]] = rsp_code.get(l[8], []) + l[:1] 16 | return rsp_code 17 | 18 | print(log_chq('log_file.txt')) 19 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/rainfall_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Read through a text file on disk. Use a dict to track how many words 3 | of each length are in the file—that is, how many three-letter words, 4 | four-letter words, five-letter words, and so on. Display your results. 5 | ''' 6 | 7 | def file_chq(fname): 8 | sym = ['.',',','?','!','\n'] 9 | wo_li = {} 10 | with open(fname, 'r') as f: 11 | for l in f: 12 | for c in sym: 13 | l = l.replace(c,'') 14 | l = l.split() 15 | for wo in l: 16 | wo_li[len(wo)] = wo_li.get(len(wo), 0) + 1 17 | 18 | for nr in wo_li: 19 | print(f'The file contains {wo_li[nr]} words with {nr} letters.') 20 | 21 | 22 | 23 | file_chq('txt_file.txt') 24 | 25 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-15-Rainfall/rainfall_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | def get_rainfall(): 3 | rainfall = {} 4 | 5 | while True: 6 | cname = input("Enter the city: ") 7 | if not cname: 8 | print("No entry. Displaying the results:") 9 | break 10 | rain_val = input("Enter in mm:") 11 | rainfall[cname] = rainfall.get(cname, 0) + int(rain_val) 12 | 13 | for k, v in rainfall.items(): 14 | print("{0:5} : {1:5}".format(k, v)) 15 | 16 | get_rainfall() 17 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/dictdiff.py: -------------------------------------------------------------------------------- 1 | d1 = {'a':1, 'b':2, 'c':3} 2 | d2 = {'a':1, 'b':2, 'd':4} 3 | d3 = {'a':1, 'b':3, 'd':5} 4 | 5 | 6 | def dictdiff(first, second): 7 | output = {} 8 | all_keys = first.keys() | second.keys() 9 | 10 | for key in all_keys: 11 | if first.get(key) != second.get(key): 12 | output[key] = [first.get(key), second.get(key)] 13 | return output 14 | 15 | 16 | print(dictdiff(d1, d2)) 17 | 18 | print(dictdiff(d2, d3)) 19 | 20 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/dictdiff_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The dict.update method merges two dicts. Write a function that takes any number 3 | of dicts and returns a dict that reflects the combination of all of them. 4 | If the same key appears in more than one dict, then the most recently merged 5 | dict’s value should appear in the output. 6 | ''' 7 | 8 | 9 | def mult_di(*args): 10 | 11 | fin_di = {} 12 | for di in args: 13 | fin_di.update(di) 14 | return fin_di 15 | 16 | 17 | d1 = {'a':1, 'b':2, 'c':3} 18 | d2 = {'a':1, 'b':2, 'd':4} 19 | d3 = {'a':1, 'b':3, 'd':5} 20 | 21 | print(mult_di(d1, d2, d3)) 22 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/dictdiff_BTE_1_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The dict.update method merges two dicts. Write a function that takes any number 3 | of dicts and returns a dict that reflects the combination of all of them. 4 | If the same key appears in more than one dict, then the most recently merged 5 | dict’s value should appear in the output. 6 | ''' 7 | 8 | 9 | def mult_di(*args): 10 | 11 | fin_di = {} 12 | 13 | for di in args: 14 | fin_di = {**fin_di, **di} 15 | return fin_di 16 | 17 | d1 = {'a':1, 'b':2, 'c':3} 18 | d2 = {'a':1, 'b':2, 'd':4} 19 | d3 = {'a':1, 'b':3, 'd':5} 20 | 21 | print(mult_di(d1, d2, d3)) 22 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-16-Dictdiff/dictdiff_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function that takes any even number of arguments and returns a dict 4 | based on them. The even-indexed arguments become the dict keys, while the odd- 5 | numbered arguments become the dict values. Thus, calling the function with the 6 | arguments ('a', 1, 'b', 2) will result in the dict {'a':1, 'b':2} being returned. 7 | ''' 8 | 9 | def even_ind_di(*elem): 10 | return {k:v for k,v in zip(elem[::2], elem[1::2])} 11 | 12 | print(even_ind_di('0', 1, '2', 3, 'a', 4, '5', 'b', '6', 7, 'c')) 13 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/how_many_different_numbers.py: -------------------------------------------------------------------------------- 1 | 2 | def how_many_different_numbers(numbers): 3 | return len(set(numbers)) 4 | 5 | print(how_many_different_numbers([10, 20, 30])) 6 | print(how_many_different_numbers([10, 20, 30, 10, 20, 30])) 7 | 8 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/how_many_different_numbers_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Read through a server (e.g., Apache or nginx) log file. What were the different 4 | IP addresses that tried to access your server? 5 | ''' 6 | 7 | 8 | def log_chq(fname): 9 | ip_s = set() 10 | with open(fname, 'r') as f: 11 | for l in f: 12 | ip_s.add(l.partition(' ')[0]) 13 | return ip_s 14 | 15 | print(log_chq('log_file.txt')) 16 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/how_many_different_numbers_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Reading from that same server log, what response codes were returned to users? 3 | The 200 code represents “OK,” but there are also 403, 404, and 500 errors. 4 | (Regular expressions aren’t required here but will probably help.) 5 | ''' 6 | 7 | def log_chq_2(fname): 8 | 9 | er_set = set() 10 | 11 | with open(fname,'r') as f: 12 | for l in f: 13 | er_set.add(l.split(' ')[8]) 14 | return er_set 15 | 16 | 17 | print(log_chq_2('log_file.txt')) 18 | -------------------------------------------------------------------------------- /CHPT-04-Dictionaries-and-sets/Exer-17-How-many-different-numbers/how_many_different_numbers_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Use os.listdir (http://mng.bz/YreB) to get the names of files in the current directory. 3 | What file extensions (i.e., suffixes following the final . character) appear in that directory? 4 | It’ll probably be helpful to use os.path.splitext (http://mng.bz/GV4v). 5 | ''' 6 | 7 | import os 8 | 9 | def file_chq(path): 10 | return set([f.partition('.')[-1] for f in os.listdir(path)]) 11 | 12 | 13 | print(file_chq('/Users/TheUser/Documents/')) 14 | 15 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/get_final_line.py: -------------------------------------------------------------------------------- 1 | 2 | # Given a filename, return the final line in that file. 3 | 4 | def get_final_line(fname): 5 | fin_li = '' 6 | for cur_li in open(fname): 7 | fin_li = cur_li 8 | return fin_li 9 | 10 | print(get_final_line('sonnet_126.txt')) 11 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/get_final_line_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Iterate over the lines of a text file. Find all of the words (i.e., non-whitespace 3 | surrounded by whitespace) that contain only integers, and sum them. 4 | ''' 5 | 6 | def find_num(fname): 7 | with open(fname) as f: 8 | n_sum = 0 9 | for l in f: 10 | n_sum += sum([int(w) for w in l.split() if w.isdigit()]) 11 | return n_sum 12 | 13 | print(find_num('sonnet_126.txt')) 14 | 15 | 16 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/get_final_line_BTE_1_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Iterate over the lines of a text file. Find all of the words (i.e., non-whitespace 3 | surrounded by whitespace) that contain only integers, and sum them. 4 | ''' 5 | 6 | def find_num(fname): 7 | with open(fname) as f: 8 | n_sum = 0 9 | for l in f: 10 | for w in l.split(): 11 | if w.isdigit(): 12 | n_sum += int(w) 13 | return n_sum 14 | 15 | print(find_num('sonnet_126.txt')) 16 | 17 | 18 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/get_final_line_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Read through a text file, line by line. Use a dict to keep track of how many times 3 | each vowel (a, e, i, o, and u) appears in the file. Print the resulting tabulation. 4 | ''' 5 | 6 | from collections import Counter 7 | 8 | def vwl_cnt(fname): 9 | vwl_di = {'a': 0, 'e':0, 'i':0, 'o':0, 'u':0} 10 | with open(fname) as f: 11 | for l in f: 12 | c = Counter(l) 13 | for k in vwl_di: 14 | vwl_di[k] += c.get(k, 0) 15 | 16 | for x, y in vwl_di.items(): 17 | print(x, y) 18 | 19 | 20 | print(vwl_cnt('sonnet_126.txt')) 21 | 22 | 23 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/get_final_line_BTE_3_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Read through a text file, line by line. Use a dict to keep track of how many times 3 | each vowel (a, e, i, o, and u) appears in the file. Print the resulting tabulation. 4 | ''' 5 | 6 | def vwl_cnt(fname): 7 | vwl_di = {'a': 0, 'e':0, 'i':0, 'o':0, 'u':0} 8 | with open(fname) as f: 9 | c = ' ' 10 | while c: 11 | c = f.read(1) 12 | if not (c in vwl_di): 13 | continue 14 | vwl_di[c] += 1 15 | for x, y in vwl_di.items(): 16 | print(x, y) 17 | 18 | 19 | print(vwl_cnt('sonnet_126.txt')) 20 | 21 | 22 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/get_final_line_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | # Given a filename, return the final line in that file. 3 | 4 | def get_final_line(fname): 5 | 6 | with open(fname, 'rb+') as f: 7 | f.seek(-2, 2) 8 | s = f.read(1) 9 | ch = s 10 | 11 | while True: 12 | f.seek(-2, 1) 13 | ch = f.read(1) 14 | if ch == b'\n': 15 | break 16 | s += ch 17 | 18 | print(str(s[::-1],'utf-8')) 19 | 20 | get_final_line('sonnet_126.txt') 21 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/get_final_line_alternative_solution_2.py: -------------------------------------------------------------------------------- 1 | 2 | # Given a filename, return the final line in that file. 3 | 4 | def get_final_line(fname): 5 | 6 | with open(fname, 'r') as f: 7 | print(f.readlines()[-1]) 8 | 9 | 10 | get_final_line('sonnet_126.txt') 11 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/num_file.txt: -------------------------------------------------------------------------------- 1 | 2, 3 2 | 5, 6 3 | 9 4 | 7, 3 5 | 5 6 | 2,1 7 | 8 | 4,9 9 | 9, 1 10 | 8 11 | 3,3 12 | 3 13 | 7, 5 14 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-18-Final-line/sonnet_126.txt: -------------------------------------------------------------------------------- 1 | O thou, my 1 lovely boy, who in thy power 2 | Dost hold Time’s fickle 2 glass, his sickle, hour; 3 | Who hast by 3 waning grown, and therein show’st 4 | Thy lovers 4 withering as thy sweet self grow’st; 5 | If Nature, 5 sovereign mistress over wrack, 6 | As thou goest 6 onwards, still will pluck thee back, 7 | She keeps thee to 7 this purpose, that her skill 8 | May time disgrace and 8 wretched minutes kill. 9 | Yet fear her, O thou minion 9 of her pleasure! 10 | She may detain, but not still 10 keep, her treasure: 11 | Her audit, though delay’d, answer’d 11 must be 12 | And her quietus is to render 12 thee. -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-19-etc-passwd-to-dict/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-19-etc-passwd-to-dict/passwd_to_dict.py: -------------------------------------------------------------------------------- 1 | 2 | def passwd_to_dict(fname): 3 | return { 4 | one_line.split(':')[0] : int(one_line.split(':')[2]) 5 | for one_line in open(fname) 6 | if not one_line.startswith(('#', '\n')) 7 | } 8 | 9 | print(passwd_to_dict('passwd.txt')) 10 | 11 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-19-etc-passwd-to-dict/passwd_to_dict_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | def passwd_to_dict(fname): 3 | 4 | users = {} 5 | 6 | with open(fname) as passwd: 7 | for line in passwd: 8 | if not line.startswith(('#', '\n')): 9 | user_info = line.split(':') 10 | users[user_info[0]] = int(user_info[2]) 11 | return users 12 | 13 | print(passwd_to_dict('passwd.txt')) 14 | 15 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-20-Word-count/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-20-Word-count/wcount_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Ask the user to enter the name of a text file and then (on one line, 3 | separated by spaces) words whose frequencies should be counted in that file. 4 | Count how many times those words appear in a dict, using the user-entered 5 | words as the keys and the counts as the values. 6 | ''' 7 | 8 | from os import path 9 | 10 | def cnt_wrd(): 11 | 12 | val = input('> ').split() 13 | fname = val[0] 14 | 15 | wrd_cnt_di = {k: 0 for k in val[1:]} 16 | with open(fname) as f: 17 | for l in f: 18 | wrds = l.strip().split() 19 | for wrd in wrds: 20 | if wrd in wrd_cnt_di: 21 | wrd_cnt_di[wrd] += 1 22 | print(wrd_cnt_di) 23 | 24 | cnt_wrd() 25 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-20-Word-count/wcount_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a dict in which the keys are the names of files on your system and the 3 | values are the sizes of those files. To calculate the size, you can use os.stat 4 | (http://mng.bz/dyyo). 5 | ''' 6 | 7 | import os 8 | 9 | def fl_sz(pth): 10 | 11 | fl_di = {} 12 | for fl in os.listdir(pth): 13 | fl_di[fl] = os.stat(fl).st_size 14 | print(fl_di) 15 | 16 | print(fl_sz('my_directory')) 17 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-20-Word-count/wcount_BTE_2_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a dict in which the keys are the names of files on your system and the 3 | values are the sizes of those files. To calculate the size, you can use os.stat 4 | (http://mng.bz/dyyo). 5 | ''' 6 | 7 | import os 8 | 9 | def fl_sz(pth): 10 | 11 | fl_di = {} 12 | for fl in os.scandir(pth): 13 | fl_di[fl.name] = fl.stat().st_size 14 | print(fl_di) 15 | 16 | 17 | print(fl_sz('my_directory')) 18 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-20-Word-count/wcount_BTE_2_alternative_solution_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a dict in which the keys are the names of files on your system and the 3 | values are the sizes of those files. To calculate the size, you can use os.stat 4 | (http://mng.bz/dyyo). 5 | ''' 6 | 7 | from pathlib import Path 8 | 9 | def fl_sz(pth): 10 | 11 | fl_di = {} 12 | for fl in Path(pth).iterdir(): 13 | if fl.is_dir(): 14 | continue 15 | fl_di[fl.name] = fl.stat().st_size 16 | print(fl_di) 17 | 18 | 19 | print(fl_sz('my_directory')) 20 | 21 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-20-Word-count/wcountfile.txt: -------------------------------------------------------------------------------- 1 | This is a test file. 2 | 3 | It contains 28 words and 20 different words. 4 | 5 | It also contains 165 characters. 6 | 7 | It also contains 11 lines. 8 | 9 | It is also self-referential. 10 | 11 | Wow! -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-21-Longest-word-per-file/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-21-Longest-word-per-file/longest_word.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | def find_longest_word(filename): 5 | longest_word = '' 6 | try: 7 | for one_line in open(filename): 8 | for one_word in one_line.split(): 9 | if len(one_word) > len(longest_word): 10 | longest_word = one_word 11 | except (OSError, UnicodeDecodeError) as e: 12 | print(f'Ignoring {filename}: {e}') 13 | return longest_word 14 | 15 | def find_all_longest_words(dirname): 16 | return {filename: find_longest_word(os.path.join(dirname, filename)) 17 | for filename in os.listdir(dirname) 18 | if os.path.isfile(os.path.join(dirname, filename))} 19 | 20 | print(find_all_longest_words('.')) 21 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-21-Longest-word-per-file/longest_word_BTE_3.py: -------------------------------------------------------------------------------- 1 | """ 2 | Open an HTTP server’s log file. (If you lack one, then you can read one from 3 | me at http://mng.bz/vxxM.) Summarize how many requests resulted in numeric 4 | response codes—202, 304, and so on. 5 | """ 6 | 7 | def log_chq(fname): 8 | 9 | cnt_di = {} 10 | with open(fname) as f: 11 | for l in f: 12 | l = l.split() 13 | cnt_di[l[8]] = cnt_di.get(l[8], 0) + 1 14 | return cnt_di 15 | 16 | print(log_chq('mini-access-log.txt')) 17 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-22-Reading-and-writing-CSV/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-22-Reading-and-writing-CSV/passwd_to_csv.py: -------------------------------------------------------------------------------- 1 | import csv 2 | 3 | def passwd_to_csv(passwd_filename, csv_filename): 4 | with open(passwd_filename) as passwd, open(csv_filename, 'w') as output: 5 | infile = csv.reader(passwd, delimiter=':') 6 | outfile = csv.writer(output, delimiter='\t') 7 | 8 | for one_record in infile: 9 | if len(one_record) > 1: 10 | outfile.writerow((one_record[0], one_record[2])) 11 | 12 | passwd_to_csv('linux-etc-passwd.txt', 'passwd.csv') 13 | 14 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-22-Reading-and-writing-CSV/passwd_to_csv_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that writes a dict to a CSV file. Each line in the CSV file 3 | should contain three fields: (1) the key, which we’ll assume to be a string, 4 | (2) the value, and (3) the type of the value (e.g., str or int). 5 | ''' 6 | 7 | import csv 8 | 9 | def csv_from_di(res_file='di_val_typ.csv'): 10 | di_val = { 'first': '1', 'second': 2, 'three': [3, 4, '5'], 'fourth': True, 'fifth': (6, 7) } 11 | with open(res_file, 'w') as csv_wr: 12 | wr = csv.writer(csv_wr) 13 | for k in di_val: 14 | wr.writerow([k, di_val[k], type(di_val[k])]) 15 | 16 | 17 | 18 | csv_from_di() 19 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-23-JSON/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-23-JSON/print_scores_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Convert /etc/passwd from a CSV-style file into a JSON-formatted file. The 4 | JSON file will contain the equivalent of a list of Python tuples, with each tuple 5 | representing one line from the file. 6 | """ 7 | 8 | import csv 9 | import json 10 | 11 | def csv_json(fname): 12 | di_tp = {} 13 | cnt = 0 14 | 15 | with open(fname) as csv_rd, open('outfl_di.json', 'w') as outfl_json: 16 | for l in csv.reader(csv_rd, delimiter=":"): 17 | if not l[0].startswith("#"): 18 | di_tp[cnt] = l 19 | cnt += 1 20 | json.dump(di_tp, outfl_json, indent=4) 21 | 22 | 23 | csv_json('linux-etc-passwd.txt') 24 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-23-JSON/print_scores_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | For a slightly different challenge, turn each line in the file into a Python dict. 4 | This will require identifying each field with a unique column or key name. If you’re 5 | not sure what each field in /etc/passwd does, you can give it an arbitrary name. 6 | """ 7 | 8 | import csv 9 | import json 10 | 11 | def csv_di_json(fname): 12 | di_tp = {} 13 | cnt = 0 14 | with open(fname) as csv_rd, open('outfl_di_2.json', 'w') as outfl_json: 15 | for l in csv.reader(csv_rd, delimiter=':'): 16 | if not l[0].startswith('#'): 17 | di_tp[cnt] = { i:v for i, v in enumerate(l)} 18 | cnt += 1 19 | json.dump(di_tp, outfl_json, indent=4) 20 | 21 | 22 | csv_di_json('linux-etc-passwd.txt') 23 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-23-JSON/scores/10a.json: -------------------------------------------------------------------------------- 1 | [{"math" : 90, "literature" : 98, "science" : 97}, 2 | {"math" : 65, "literature" : 79, "science" : 85}, 3 | {"math" : 78, "literature" : 83, "science" : 75}, 4 | {"math" : 92, "literature" : 78, "science" : 85}, 5 | {"math" : 100, "literature" : 80, "science" : 90} 6 | ] 7 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-23-JSON/scores/9a.json: -------------------------------------------------------------------------------- 1 | [{"math" : 10, "literature" : 98, "science" : 97}, 2 | {"math" : 65, "literature" : 74, "science" : 85}, 3 | {"math" : 78, "literature" : 83, "science" : 75}, 4 | {"math" : 92, "literature" : 76, "science" : 85}, 5 | {"math" : 100, "literature" : 66, "science" : 50} 6 | ] 7 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-23-JSON/scores/9b.json: -------------------------------------------------------------------------------- 1 | [{"math" : 10, "literature" : 98, "science" : 97}, 2 | {"math" : 45, "literature" : 79, "science" : 85}, 3 | {"math" : 68, "literature" : 83, "science" : 75}, 4 | {"math" : 91, "literature" : 18, "science" : 85}, 5 | {"math" : 20, "literature" : 80, "science" : 90} 6 | ] 7 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-23-JSON/scores/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-24-Reverse-lines/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-24-Reverse-lines/data_vwl.txt: -------------------------------------------------------------------------------- 1 | abc def 2 | ghi jkl -------------------------------------------------------------------------------- /CHPT-05-Files/Exer-24-Reverse-lines/reverse_lines.py: -------------------------------------------------------------------------------- 1 | 2 | def reverse_lines(infname, outfname): 3 | with open(infname) as inf, open(outfname, 'w') as outf: 4 | for one_line in inf: 5 | outf.write(f'{one_line.rstrip()[::-1]}\n') 6 | 7 | 8 | reverse_lines('input_text.txt', 'output_text.txt') 9 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-25-XML-generator/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-25-XML-generator/myxml.py: -------------------------------------------------------------------------------- 1 | 2 | def myxml(tagname, content='', **kwargs): 3 | attributes = ''.join(f' {key}="{value}"' for key, value in kwargs.items()) 4 | 5 | return f'<{tagname}{attributes}>{content}' 6 | 7 | print(myxml('foo')) 8 | print(myxml('foo', 'text')) 9 | print(myxml('foo', 'bar', a=1, b=2, c=3) ) 10 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-25-XML-generator/myxml_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a “factorial” function that takes any number of numeric arguments and 3 | returns the result of multiplying them all by one another. 4 | ''' 5 | 6 | def fact_fun(*args): 7 | if len(args) == 1: 8 | return args[0] 9 | return args[0] * fact_fun(*args[1:]) 10 | 11 | print(fact_fun(2)) 12 | 13 | print(fact_fun(2, 3, 4)) 14 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-25-XML-generator/myxml_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write an anyjoin function that works similarly to str.join, except that the first 3 | argument is a sequence of any types (not just of strings), and the second argument 4 | is the “glue” that we put between elements, defaulting to " " (a space). 5 | 6 | So anyjoin([1,2,3]) will return 1 2 3, 7 | and anyjoin('abc', pass:'**') will return pass:a**b**c. 8 | ''' 9 | 10 | def anyjoin(iter, glue=' '): 11 | return glue.join([str(x) for x in iter]) 12 | 13 | 14 | print(anyjoin([1,2,3])) 15 | 16 | print(anyjoin('abc', glue='**')) 17 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-25-XML-generator/myxml_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | def myxml(*args, **kwargs): 3 | tag, content = " ".join(args[:1]), ". ".join(args[1:]) 4 | attr_di = [f'{k}="{v}"' for k, v in kwargs.items()] 5 | attr_di.insert(0, tag) 6 | return f'<{" ".join(attr_di)}>{content}' 7 | 8 | 9 | print(myxml('foo')) 10 | print(myxml('foo', 'text')) 11 | print(myxml('foo', 'bar', a=1, b=2, c=3) ) 12 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-25-XML-generator/sonnet_126.txt: -------------------------------------------------------------------------------- 1 | O thou, my 1 lovely boy, who in thy power 2 | Dost hold Time’s fickle 2 glass, his sickle, hour; 3 | Who hast by 3 waning grown, and therein show’st 4 | Thy lovers 4 withering as thy sweet self grow’st; 5 | If Nature, 5 sovereign mistress over wrack, 6 | As thou goest 6 onwards, still will pluck thee back, 7 | She keeps thee to 7 this purpose, that her skill 8 | May time disgrace and 8 wretched minutes kill. 9 | Yet fear her, O thou minion 9 of her pleasure! 10 | She may detain, but not still 10 keep, her treasure: 11 | Her audit, though delay’d, answer’d 11 must be 12 | And her quietus is to render 12 thee. -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-26-Prefix-notation-calculator/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-26-Prefix-notation-calculator/calc.py: -------------------------------------------------------------------------------- 1 | 2 | import operator 3 | 4 | def calc(to_solve): 5 | operations = {'+': operator.add, 6 | '-': operator.sub, 7 | '*': operator.mul, 8 | '/': operator.truediv, 9 | '**': operator.pow, 10 | '%': operator.mod} 11 | op, first_s, second_s = to_solve.split() 12 | first = int(first_s) 13 | second = int(second_s) 14 | 15 | return operations[op](first, second) 16 | 17 | print(calc('+ 2 3')) 18 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-26-Prefix-notation-calculator/calc_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function, apply_to_each, that takes two arguments: a function that takes a single argument, 3 | and an iterable. Return a list whose values are the result of applying the function to each element 4 | in the iterable. 5 | ''' 6 | 7 | def double(num): 8 | return num * 2 9 | 10 | def apply_to_each(fun, my_iter): 11 | return [fun(item) for item in my_iter] 12 | 13 | print(apply_to_each( double, [4, 5, 6] )) 14 | 15 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-26-Prefix-notation-calculator/calc_BTE_2_alternative_solution.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function, apply_to_each, that takes two arguments: a function that takes a single argument, 3 | and an iterable. Return a list whose values are the result of applying the function to each element 4 | in the iterable. 5 | ''' 6 | 7 | def apply_to_each(fun, my_iter): 8 | return [fun(item) for item in my_iter] 9 | 10 | print(apply_to_each( (lambda x: x * 2), [4, 5, 6] )) 11 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-26-Prefix-notation-calculator/calc_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function, transform_lines, that takes three arguments: a function 4 | that takes a single argument, the name of an input file, and the name of 5 | an output file. Calling the function will run the function on each line 6 | of the input file, with the results written to the output file. 7 | 8 | (Hint: the previous exercise and this one are closely related.) 9 | ''' 10 | 11 | def to_lower(txt): 12 | return txt.lower() 13 | 14 | def transform_lines(fun, f_in, f_out): 15 | with open(f_in) as f_rd, open(f_out, 'w') as f_wr: 16 | for l in f_rd: 17 | f_wr.write(fun(l)) 18 | 19 | transform_lines(to_lower, 'sonnet_126.txt', 'output.txt') 20 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-26-Prefix-notation-calculator/calc_BTE_3_alternative_solution.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a function, transform_lines, that takes three arguments: a function 4 | that takes a single argument, the name of an input file, and the name of 5 | an output file. Calling the function will run the function on each line 6 | of the input file, with the results written to the output file. 7 | 8 | (Hint: the previous exercise and this one are closely related.) 9 | ''' 10 | 11 | def transform_lines(fun, f_in, f_out): 12 | with open(f_in) as f_rd, open(f_out, 'w') as f_wr: 13 | for l in f_rd: 14 | f_wr.write(fun(l)) 15 | 16 | transform_lines((lambda x: x.lower()), 'sonnet_126.txt', 'output_2.txt') 17 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-26-Prefix-notation-calculator/sonnet_126.txt: -------------------------------------------------------------------------------- 1 | O thou, my 1 lovely boy, who in thy power 2 | Dost hold Time’s fickle 2 glass, his sickle, hour; 3 | Who hast by 3 waning grown, and therein show’st 4 | Thy lovers 4 withering as thy sweet self grow’st; 5 | If Nature, 5 sovereign mistress over wrack, 6 | As thou goest 6 onwards, still will pluck thee back, 7 | She keeps thee to 7 this purpose, that her skill 8 | May time disgrace and 8 wretched minutes kill. 9 | Yet fear her, O thou minion 9 of her pleasure! 10 | She may detain, but not still 10 keep, her treasure: 11 | Her audit, though delay’d, answer’d 11 must be 12 | And her quietus is to render 12 thee. -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-27-Password-generator/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-27-Password-generator/create_password_generator.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def create_p_gen(chars): 4 | 5 | def create_p(length): 6 | output = [] 7 | 8 | for i in range(length): 9 | output.append(random.choice(chars)) 10 | 11 | return ''.join(output) 12 | 13 | return create_p 14 | 15 | f = create_p_gen('abcdefghij!@#$%') 16 | 17 | print(f(10)) 18 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-27-Password-generator/create_password_generator_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function, getitem, that takes a single argument and returns a function f. 3 | The returned f can then be invoked on any data structure whose elements can be 4 | selected via square brackets, and then returns that item. So if I invoke f = getitem('a'), 5 | and if I have a dict d = {'a':1, 'b':2}, then f(d) will return 1. 6 | (This is very similar to operator.itemgetter, a very useful function in many circumstances.) 7 | ''' 8 | 9 | def get_item(item): 10 | def fun(iter): 11 | return iter[item] 12 | return fun 13 | 14 | 15 | f = get_item(1) 16 | 17 | print(f('asd')) 18 | -------------------------------------------------------------------------------- /CHPT-06-Functions/Exer-27-Password-generator/create_password_generator_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function, doboth, that takes two functions as arguments (f1 and f2) 3 | and returns a single function, g. Invoking g(x) should return the same result 4 | as invoking f2(f1(x)). 5 | ''' 6 | 7 | def doboth(fun1, fun2): 8 | def g(x): 9 | return fun2(fun1(x)) 10 | return g 11 | 12 | 13 | f1 = lambda x: x.rstrip('\nxyz') 14 | f2 = lambda x: x.lstrip(' 246') 15 | 16 | strip_string_from_sides = doboth(f1,f2) 17 | 18 | print(strip_string_from_sides(' 24444.Final String.\nzzyyx')) 19 | print(f2(f1(' 24444.Final String.\nzzyyx'))) 20 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/join_numbers.py: -------------------------------------------------------------------------------- 1 | 2 | mylist = [10, 20, 30] 3 | 4 | def join_numbers(numbers): 5 | return ','.join(str(x) 6 | for x in numbers) 7 | 8 | print(join_numbers(mylist)) 9 | 10 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/join_numbers_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | As in the exercise, take a list of integers and turn them into strings. However, 4 | you’ll only want to produce strings for integers between 0 and 10. Doing this 5 | will require understanding the if statement in list comprehensions as well. 6 | ''' 7 | 8 | def int_to_str(*args): 9 | return [str(x) for x in args if x >= 0 and x <= 10] 10 | 11 | print(int_to_str(*[21,2,4,9,10,33,66])) 12 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/join_numbers_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Given a list of strings containing hexadecimal numbers, sum the numbers together. 4 | ''' 5 | 6 | def hex_sum(hex_lst): 7 | return sum(int(x, base=16) for x in hex_lst) 8 | 9 | print(hex_sum([hex(4), hex(9), hex(-4), hex(11)])) 10 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/join_numbers_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Use a list comprehension to reverse the word order of lines in a text file. 4 | That is, if the first line is 5 | abc def 6 | and the second line is 7 | ghi jkl, 8 | then you should return the list 9 | ['def abc', 'jkl ghi']. 10 | ''' 11 | 12 | def rev_wrd_ordr(fname='text.txt'): 13 | res = [] 14 | with open(fname) as f: 15 | res = [' '.join(line.rstrip().split()[::-1]) for line in f] 16 | return res 17 | 18 | print(rev_wrd_ordr()) 19 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-28-Join-numbers/text.txt: -------------------------------------------------------------------------------- 1 | abc def 2 | ghi jkl 3 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-29-Add-numbers/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-29-Add-numbers/add_numbers.py: -------------------------------------------------------------------------------- 1 | 2 | def sum_numbers(numbers): 3 | return sum(int(number) 4 | for number in numbers.split() 5 | if number.isdigit()) 6 | 7 | print(sum_numbers('1 2 3 a b c 4')) 8 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-29-Add-numbers/add_numbers_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Show the lines of a text file that contain at least one vowel and contain 4 | more than 20 characters. 5 | ''' 6 | 7 | def show_lines(fname='text.txt'): 8 | res = [] 9 | with open(fname) as f: 10 | f_lines = filter(lambda x: len(x) > 20, (li for li in f)) 11 | for li in f_lines: 12 | for c in li: 13 | if c.lower() in 'aeiuo': 14 | print(li.rstrip()) 15 | break 16 | 17 | show_lines() 18 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-29-Add-numbers/text.txt: -------------------------------------------------------------------------------- 1 | Rhythmrhythmrhythmm 2 | compartmentalization 3 | Strawberry 4 | semiautobiographical 5 | Friendship 6 | internationalization 7 | Everything 8 | compartmentalisation 9 | Appreciate 10 | electrogalvanization 11 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-30-Flatten-a-list/Figure_7_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihathalici/Python-Workout-50-Ten-minute-Exercises/f8d8901d6bec44032440c6903a998fc956fc9b0b/CHPT-07-Functional-programming-with-comprehensions/Exer-30-Flatten-a-list/Figure_7_1.PNG -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-30-Flatten-a-list/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-30-Flatten-a-list/flatten.py: -------------------------------------------------------------------------------- 1 | 2 | mylist = [[10, 20, 30], [40, 50, 60], [70, 80, 90, 100]] 3 | 4 | def flatten(the_list): 5 | return [one_item 6 | for one_sublist in the_list 7 | for one_item in one_sublist] 8 | 9 | print(flatten(mylist)) 10 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-30-Flatten-a-list/flatten_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Define a dict that represents the children and grandchildren in a family. 4 | (See figure 7.1 for a graphic representation.) Each key will be a child’s name, 5 | and each value will be a list of strings representing their children 6 | (i.e., the family’s grandchildren). Thus the dict 7 | {'A':['B', 'C', 'D'], 'E':['F', 'G']} means 8 | that A and E are siblings; A’s children are B, C, and D; 9 | and E’s children are F and G. Use a list comprehension to create a list 10 | of the grandchildren’s names. 11 | ''' 12 | 13 | my_fml_tr = {'A':['B','C','D'], 'E':['F','G']} 14 | 15 | def fml_di(fml_tr): 16 | return [item 17 | for k in fml_tr 18 | for item in fml_tr[k]] 19 | 20 | print( fml_di(my_fml_tr) ) 21 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-30-Flatten-a-list/flatten_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Redo this exercise, but replace each grandchild’s name (currently a string) 4 | with a dict. Each dict will contain two name-value pairs, name and age. Produce 5 | a list of the grandchildren’s names, sorted by age, from eldest to youngest. 6 | ''' 7 | 8 | my_fml_tr = {'A':{'B':12,'C':7,'D':13}, 'E':{'F':14,'G':1}} 9 | 10 | def sort_by_age(fml_tr): 11 | 12 | grandch = {in_k:fml_tr[k][in_k] 13 | for k in fml_tr 14 | for in_k in fml_tr[k]} 15 | print(grandch) 16 | return sorted(grandch, key=lambda x: grandch[x]) 17 | 18 | print(sort_by_age(my_fml_tr)) 19 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-31-Pig-Latin-translation-of-a-file/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-31-Pig-Latin-translation-of-a-file/plfile.py: -------------------------------------------------------------------------------- 1 | 2 | def plword(word): 3 | if word[0] in 'aeiou': 4 | return word + 'way' 5 | return word[1:] + word[0] + 'ay' 6 | 7 | def plfile(fname): 8 | return ' '.join(plword(one_word) 9 | for one_line in open(fname) 10 | for one_word in one_line.split()) 11 | 12 | print(plfile('sonnet_126.txt')) 13 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-31-Pig-Latin-translation-of-a-file/plfile_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Use a nested list comprehension to transform a list of dicts into a list 4 | of two- element (name-value) tuples, each of which represents one of the 5 | name-value pairs in one of the dicts. If more than one dict has the same 6 | name-value pair, then the tuple should appear twice. 7 | ''' 8 | 9 | 10 | def nested_lst(di_lst): 11 | tpl_lst = [ (k, item[k]) for item in di_lst for k in item] 12 | tpl = [tpl_lst.remove(item) for item in tpl_lst if tpl_lst.count(item) > 2] 13 | return tpl_lst 14 | 15 | print(nested_lst([{'a':1},{'a':1,'b':2},{'c':1,'b':2,'a':1,'d':3}])) 16 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/flipped_dict.py: -------------------------------------------------------------------------------- 1 | 2 | my_dict = {'a':1, 'b':2, 'c':3, 'd':3} 3 | 4 | def flipped_dict(a_dict): 5 | return { 6 | value : key 7 | for key, value in a_dict.items() 8 | } 9 | 10 | print(flipped_dict(my_dict)) 11 | 12 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/flipped_dict_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Given a string containing several (space-separated) words, create a dict 4 | in which the keys are the words, and the values are the number of vowels 5 | in each word. If the string is “this is an easy test,” then the resulting 6 | dict would be {'this':1, 'is':1, 'an':1, 'easy':2, 'test':1}. 7 | ''' 8 | 9 | def vwls_cnt_dict(a_str): 10 | vwls = 'aeuoi' 11 | return {word:sum([1 if c.lower() in vwls else 0 for c in word]) 12 | for word in a_str.split()} 13 | 14 | 15 | print(vwls_cnt_dict('this is an easy test,')) 16 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/flipped_dict_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Create a dict whose keys are filenames and whose values are the lengths of the 4 | files. The input can be a list of files from os.listdir (http://mng.bz/YreB) 5 | or glob.glob (http://mng.bz/044N). 6 | ''' 7 | 8 | from pathlib import Path 9 | 10 | def cnt_fl_di(cnt_pth): 11 | fl_di = {} 12 | my_path = Path(cnt_pth) 13 | fl_di = {fl.name:fl.stat().st_size for fl in my_path.iterdir() if fl.is_file()} 14 | return fl_di 15 | 16 | print(cnt_fl_di('my_data_dir')) 17 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/flipped_dict_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Find a configuration file in which the lines look like "name=value." 4 | Use a dict comprehension to read from the file, turning each line 5 | into a key-value pair. 6 | ''' 7 | 8 | def di_frm_fl(fname): 9 | with open(fname) as f: 10 | return {l.split(':')[0]:l.split(':')[1] for l in f} 11 | 12 | print(di_frm_fl('my_data_dir/config_file')) 13 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/my_data_dir/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/my_data_dir/sonnet_1.txt: -------------------------------------------------------------------------------- 1 | O thou, my 1 lovely boy, who in thy power 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/my_data_dir/sonnet_2.txt: -------------------------------------------------------------------------------- 1 | Dost hold Time’s fickle 2 glass, his sickle, hour; 2 | Who hast by 3 waning grown, and therein show’st 3 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/my_data_dir/sonnet_3.txt: -------------------------------------------------------------------------------- 1 | Thy lovers 4 withering as thy sweet self grow’st; 2 | If Nature, 5 sovereign mistress over wrack, 3 | As thou goest 6 onwards, still will pluck thee back, 4 | She keeps thee to 7 this purpose, that her skill 5 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-32-Flip-a-dict/my_data_dir/sonnet_4.txt: -------------------------------------------------------------------------------- 1 | O thou, my 1 lovely boy, who in thy power 2 | Dost hold Time’s fickle 2 glass, his sickle, hour; 3 | Who hast by 3 waning grown, and therein show’st 4 | Thy lovers 4 withering as thy sweet self grow’st; 5 | If Nature, 5 sovereign mistress over wrack, 6 | As thou goest 6 onwards, still will pluck thee back, 7 | She keeps thee to 7 this purpose, that her skill 8 | May time disgrace and 8 wretched minutes kill. 9 | Yet fear her, O thou minion 9 of her pleasure! 10 | She may detain, but not still 10 keep, her treasure: 11 | Her audit, though delay’d, answer’d 11 must be 12 | And her quietus is to render 12 thee. 13 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-33-Transform-values/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-33-Transform-values/transform_values.py: -------------------------------------------------------------------------------- 1 | d = {'a':1, 'b':2, 'c':3} 2 | 3 | def transform_values(func, a_dict): 4 | return { key : func(value) 5 | for key, value in a_dict.items() } 6 | 7 | def square(x): 8 | return x ** 2 9 | 10 | print(transform_values(square, d)) 11 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/get_sv.py: -------------------------------------------------------------------------------- 1 | def get_sv(fname): 2 | vwls = {'a', 'e', 'i', 'o', 'u'} 3 | 4 | return {word 5 | for word in open(fname) 6 | if vwls <= set( word.lower() ) } 7 | 8 | print(get_sv('words.txt')) 9 | 10 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/get_sv_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | In the /etc/passwd file you used earlier, what different shells (i.e., command interpreters, 3 | named in the final field on each line) are assigned to users? Use a set comprehension to gather them. 4 | ''' 5 | 6 | def shell_chq(sh_file): 7 | return { l.split(':')[-1].strip() 8 | for l in open(sh_file) 9 | if not l.startswith('#') } 10 | 11 | print(shell_chq('user_db_with_com.txt')) 12 | 13 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/get_sv_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a text file, what are the lengths of the different words? 3 | Return a set of different word lengths in the file. 4 | ''' 5 | 6 | def wo_lngth(a_file): 7 | return {len(wrd.strip()) 8 | for wrd in open(a_file)} 9 | 10 | print(wo_lngth('words.txt')) 11 | 12 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-34-Almost-supervocalic-words/get_sv_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Create a list whose elements are strings—the names of people in your family. 4 | Now use a set comprehension (and, better yet, a nested set comprehension) to 5 | find which letters are used in your family members’ names. 6 | """ 7 | 8 | # Author's solution 9 | 10 | import string 11 | 12 | def letters_in_names(list_of_names): 13 | return {one_letter 14 | for one_letter in ''.join(list_of_names) 15 | if one_letter in string.ascii_letters} 16 | 17 | my_lst_names = ['Iris', 'Angel', 'Carlos', 'Mariate', 'Miguel'] 18 | print(letters_in_names(my_lst_names)) 19 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-A-Gematria-Part-1/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-A-Gematria-Part-1/config.txt: -------------------------------------------------------------------------------- 1 | a=1 2 | b=2 3 | c=3 4 | d=/etc/passwd 5 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-A-Gematria-Part-1/gematria_dict.py: -------------------------------------------------------------------------------- 1 | 2 | import string 3 | 4 | def gematria_dict(): 5 | return { 6 | char : index 7 | for index, char in enumerate(string.ascii_lowercase, 1) 8 | } 9 | 10 | print(gematria_dict()) 11 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-A-Gematria-Part-1/gematria_dict_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Many programs’ functionality is modified via configuration files, which are often set using 4 | name-value pairs. That is, each line of the file contains text in the form of name=value, 5 | where the = sign separates the name from the value. I’ve prepared one such sample config file 6 | at http://mng.bz/rryD. Download this file, and then use a dict comprehension to read its contents 7 | from disk, turning it into a dict describing a user’s preferences. Note that all of the values 8 | will be strings. 9 | ''' 10 | 11 | def crt_dct(a_file): 12 | return { l.split('=')[0].strip():l.split('=')[-1].strip() 13 | for l in open(a_file) 14 | } 15 | 16 | print(crt_dct('config.txt')) 17 | 18 | 19 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-A-Gematria-Part-1/gematria_dict_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Create a dict based on the config file, as in the previous exercise, but this time, all of the 4 | values should be integers. This means that you’ll need to filter out (and ignore) those values 5 | that can’t be turned into integers. 6 | ''' 7 | 8 | def crt_dct_int(a_file): 9 | return { l.split('=')[0].strip():int(l.split('=')[-1].strip()) 10 | for l in open(a_file) 11 | if l.split('=')[-1].strip().isdigit() 12 | } 13 | 14 | print(crt_dct_int('config.txt')) 15 | 16 | 17 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/gematria_equal_words.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | def gematria_dict(): 4 | return {char: index 5 | for index, char 6 | in enumerate(string.ascii_lowercase, 1)} 7 | 8 | GEMATRIA = gematria_dict() 9 | 10 | def gematria_for(word): 11 | return sum(GEMATRIA.get(one_char, 0) 12 | for one_char in word) 13 | 14 | 15 | def gematria_equal_words(input_word): 16 | our_score = gematria_for(input_word.lower()) 17 | 18 | return [ one_word.strip() 19 | for one_word in open('words.txt') 20 | if gematria_for( one_word.lower() ) == our_score ] 21 | 22 | print(gematria_equal_words('xylophone')) 23 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/gematria_equal_words_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a dict whose keys are city names, and whose values are temperatures in 3 | Fahrenheit. Now use a dict comprehension to transform this dict into a new one, 4 | keeping the old keys but turning the values into the temperature in degrees Celsius. 5 | ''' 6 | 7 | fahr_temp_di = {'Lisbon, Portugal':69, 'Stockholm, Sweden':36, 8 | 'Warsaw, Poland':41, 'Germany, Berlin':46} 9 | 10 | def conv_to_cels(): 11 | return { key:round( (val - 32) * (5/9) ) 12 | for key, val in fahr_temp_di.items() } 13 | 14 | print(conv_to_cels()) 15 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/gematria_equal_words_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a list of tuples in which each tuple contains three elements: (1) the author’s 3 | first and last names, (2) the book’s title, and (3) the book’s price in U.S. dollars. 4 | 5 | Use a dict comprehension to turn this into a dict whose keys are the book’s titles, 6 | with the values being another (sub-) dict, with keys for (a) the author’s first name, 7 | (b) the author’s last name, and (c) the book’s price in U.S. dollars. 8 | ''' 9 | 10 | tpl_lst = [ ('Isaac Asimov','Foundation', 9), ('Frank Herbert','Dune', 12), (' George Orwell', 'Nineteen Eighty-Four', 15) ] 11 | 12 | 13 | def tpl_li_dct(): 14 | return {tt:{nm:pr} 15 | for nm, tt, pr in tpl_lst} 16 | 17 | print(tpl_li_dct()) 18 | -------------------------------------------------------------------------------- /CHPT-07-Functional-programming-with-comprehensions/Exer-35-B-Gematria-Part-2/gematria_equal_words_BTE_3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Create a dict whose keys are currency names and whose values are the price of that currency 3 | in U.S. dollars. Write a function that asks the user what currency they use, then returns 4 | the dict from the previous exercise as before, but with its prices converted into the requested currency. 5 | ''' 6 | 7 | 8 | def con_val(): 9 | d = {'lt':0.28, 'us':0.83} 10 | value = input('Enter price and currency, to translate it to euros: ') 11 | cur_name = value.lower().strip().split()[-1] 12 | cur_price = value.strip().split()[0] 13 | return round( int(cur_price) * d.get(cur_name, 2)) if d.get(cur_name, 0) else 'Currency unknown' 14 | 15 | 16 | print(con_val()) 17 | 18 | -------------------------------------------------------------------------------- /CHPT-08-Modules-and-packages/Exer-36-Sales-tax/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-08-Modules-and-packages/Exer-36-Sales-tax/freedonia.py: -------------------------------------------------------------------------------- 1 | 2 | RATES = { 3 | 'Chico': 0.5, 4 | 'Groucho': 0.7, 5 | 'Harpo': 0.5, 6 | 'Zeppo': 0.4 7 | } 8 | 9 | def time_percentage(hour): 10 | return hour / 24 11 | 12 | def calculate_tax(amount, state, hour): 13 | return amount + (amount * RATES[state] * time_percentage(hour)) 14 | 15 | #print(calculate_tax(500, 'Harpo', 12)) 16 | -------------------------------------------------------------------------------- /CHPT-08-Modules-and-packages/Exer-36-Sales-tax/sales_tax_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a module providing a function that, given a string, returns a dict 4 | indicating how many characters provide a True result to each of the following 5 | functions: str.isdigit, str.isalpha, and str.isspace. 6 | The keys should be isdigit, isalpha, and isspace. 7 | ''' 8 | 9 | def analyze_string(s): 10 | 11 | output = {'isdigit': 0, 12 | 'isalpha': 0, 13 | 'isspace': 0} 14 | 15 | for one_character in s: 16 | for methodname in output: 17 | if getattr(one_character, methodname)(): 18 | output[methodname] += 1 19 | 20 | return output 21 | 22 | print(analyze_string('root:*:0:0::0:0:System Administrator:/var/root:/bin/sh')) 23 | 24 | -------------------------------------------------------------------------------- /CHPT-08-Modules-and-packages/Exer-36-Sales-tax/sales_tax_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | The dict.fromkeys method (http://mng.bz/1zrV) makes it easy to create a new dict. 4 | For example, dict.fromkeys('abc') will create the dict {'a':None, 'b':None, 'c':None}. 5 | You can also pass a value that will be assigned to each key, as in 6 | dict.fromkeys('abc', 5), resulting in the dict {'a':5, 'b':5, 'c':5}. Implement a function 7 | that does the same thing as dict.keys but whose second argument is a function. The value 8 | associated with the key will be the result of invoking f(key). 9 | ''' 10 | 11 | def fromkeys_func(s, func): 12 | 13 | output = {} 14 | 15 | for one_item in s: 16 | output[one_item] = func(one_item) 17 | 18 | return output 19 | 20 | -------------------------------------------------------------------------------- /CHPT-08-Modules-and-packages/Exer-36-Sales-tax/using_freedonia_as_module.py: -------------------------------------------------------------------------------- 1 | 2 | from freedonia import calculate_tax 3 | 4 | tax_at_12noon = calculate_tax(100, 'Harpo', 12) 5 | tax_at_9pm = calculate_tax(100, 'Harpo', 21) 6 | 7 | print(f'You owe a total of: {tax_at_12noon}') 8 | print(f'You owe a total of: {tax_at_9pm}') 9 | -------------------------------------------------------------------------------- /CHPT-08-Modules-and-packages/Exer-37-Menu/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-08-Modules-and-packages/Exer-37-Menu/menu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Function that takes keyword arguments. The value 4 | associated with each key is a function taking zero arguments. 5 | The user is asked to enter input. 6 | If the input matches a keyword, then the associated function 7 | is invoked, and its return value is returned to the user. 8 | If the input doesn't match a keywork, the user is asked to 9 | try again. 10 | """ 11 | 12 | 13 | def menu(**options): 14 | 15 | while True: 16 | option_string = '/'.join(sorted(options)) 17 | choice = input(f'Enter an option ({option_string}): ') 18 | if choice in options: 19 | return options[choice]() 20 | 21 | print('Not a valid option') 22 | 23 | 24 | -------------------------------------------------------------------------------- /CHPT-08-Modules-and-packages/Exer-37-Menu/using_menu_as _module.py: -------------------------------------------------------------------------------- 1 | 2 | from menu import menu 3 | 4 | def func_a(): 5 | return 'A' 6 | 7 | def func_b(): 8 | return 'B' 9 | 10 | return_value = menu(a=func_a, b=func_b) 11 | 12 | print(f'Return value is {return_value}') 13 | -------------------------------------------------------------------------------- /CHPT-08-Modules-and-packages/README.md: -------------------------------------------------------------------------------- 1 | # Python Workout: 50 Ten-minute Exercises 2 | # CHAPTER-08 | Modules and packages 3 | 4 | * **[Exercise 36: Sales tax](https://github.com/nihathalici/Python-Workout-50-Ten-minute-Exercises/tree/main/CHPT-08-Modules-and-packages/Exer-36-Sales-tax)** - 5 exercises 5 | * **[Exercise 37: Menu](https://github.com/nihathalici/Python-Workout-50-Ten-minute-Exercises/tree/main/CHPT-08-Modules-and-packages/Exer-37-Menu)** - 3 exercises 6 | 7 | Links and Appendix 8 | ======================================================== 9 | 10 | - Get the book: https://www.amazon.de/Python-Workout-50-Essential-Exercises/dp/1617295507 11 | - About Reuven M. Lerner and his works: https://lerner.co.il/ 12 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-38-Ice-cream-scoop/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-38-Ice-cream-scoop/scoop.py: -------------------------------------------------------------------------------- 1 | class Scoop: 2 | def __init__(self, flavor): 3 | self.flavor = flavor 4 | 5 | s1 = Scoop('chocolate') 6 | s2 = Scoop('vanilla') 7 | s3 = Scoop('persimmon') 8 | 9 | for one_scoop in [s1, s2, s3]: 10 | print(one_scoop.flavor) 11 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-38-Ice-cream-scoop/scoop_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a Beverage class whose instances will represent beverages. Each beverage 3 | should have two attributes: a name (describing the beverage) and a temperature. 4 | 5 | Create several beverages and check that their names and temperatures are all 6 | handled correctly. 7 | ''' 8 | 9 | class Beverage(): 10 | def __init__(self, name, temp): 11 | self.name = name 12 | self.temp = temp 13 | 14 | b1 = Beverage('coffee', 'hot') 15 | b2 = Beverage('ice tea', 'cold') 16 | b3 = Beverage('water', 'normal') 17 | 18 | for item in [b1, b2, b3]: 19 | print('The beverage {} is {}.'.format(item.name, item.temp)) 20 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-38-Ice-cream-scoop/scoop_BTE_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Modify the Beverage class, such that you can create a new instance specifying the name, 3 | and not the temperature. If you do this, then the temperature should have a default value 4 | of 75 degrees Celsius. Create several beverages and double-check that the temperature has 5 | this default when not specified. 6 | ''' 7 | 8 | class Beverage(): 9 | def __init__(self, name, temp=75): 10 | self.name = name 11 | self.temp = temp 12 | 13 | b1 = Beverage('coffee', 90) 14 | b2 = Beverage('ice tea', 5) 15 | b3 = Beverage('water') 16 | 17 | for item in [b1, b2, b3]: 18 | print('The beverage {} is {}.'.format(item.name, item.temp)) 19 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-38-Ice-cream-scoop/scoop_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Create a new LogFile class that expects to be initialized with a filename. Inside of __init__, 4 | open the file for writing and assign it to an attribute, file, that sits on the instance. 5 | Check that it’s possible to write to the file via the file attribute. 6 | ''' 7 | 8 | class LogFile(): 9 | def __init__(self, fname): 10 | self.file = open(fname, 'w') 11 | 12 | f1 = LogFile('text1.txt') 13 | f2 = LogFile('text2.txt') 14 | f3 = LogFile('text3.txt') 15 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-39-Ice-cream-bowl/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-39-Ice-cream-bowl/ice_cream_bowl.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Scoop: 4 | def __init__(self, flavor): 5 | self.flavor = flavor 6 | 7 | class Bowl(): 8 | def __init__(self): 9 | self.scoops = [] 10 | 11 | def add_scoops(self, *new_scoops): 12 | for one_scoop in new_scoops: 13 | self.scoops.append(one_scoop) 14 | 15 | def __repr__(self): 16 | return '\n'.join(s.flavor for s in self.scoops) 17 | 18 | 19 | s1 = Scoop('chocolate') 20 | s2 = Scoop('vanilla') 21 | s3 = Scoop('persimmon') 22 | 23 | b = Bowl() 24 | b.add_scoops(s1, s2) 25 | b.add_scoops(s3) 26 | 27 | print(b) 28 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-40-Ice-cream-bowl-with-limits/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-40-Ice-cream-bowl-with-limits/ice_cream_bowl_with_limits_BTE_1.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Define a Person class, and a population class attribute that increases each time 4 | you create a new instance of Person. Double-check that after you’ve created five 5 | instances, named p1 through p5, Person.population and p1.population are both equal to 5. 6 | ''' 7 | 8 | class Person: 9 | population = 0 10 | 11 | def __init__(self, name): 12 | self.name = name 13 | Person.population += 1 14 | 15 | 16 | 17 | p1 = Person('James') 18 | p2 = Person('John') 19 | p3 = Person('Robert') 20 | p4 = Person('Michael') 21 | p5 = Person('William') 22 | 23 | print(Person.population) 24 | 25 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-41-A-bigger-bowl/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-41-A-bigger-bowl/person_class.py: -------------------------------------------------------------------------------- 1 | 2 | class Person(): 3 | def __init__(self, name): 4 | self.name = name 5 | 6 | def greet(self): 7 | return f'Hello, {self.name}' 8 | 9 | class Employee(Person): 10 | def __init__(self, name, id_number): 11 | super().__init__(name) 12 | self.id_number = id_number 13 | 14 | e = Employee('empname', 1) 15 | 16 | print(e.greet()) 17 | 18 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-42-FlexibleDict/FlexibleDict.py: -------------------------------------------------------------------------------- 1 | class FlexibleDict(dict): 2 | def __getitem__(self, key): 3 | try: 4 | if key in self: 5 | pass 6 | elif str(key) in self: 7 | key = str(key) 8 | elif int(key) in self: 9 | key = int(key) 10 | except ValueError: 11 | pass 12 | 13 | return dict.__getitem__(self, key) 14 | 15 | fd = FlexibleDict() 16 | 17 | fd['a'] = 100 18 | print(fd['a']) 19 | 20 | fd[5] = 500 21 | print(fd[5]) 22 | 23 | fd[1] = 100 24 | print(fd['1']) 25 | 26 | fd['1'] = 100 27 | print(fd[1]) 28 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-42-FlexibleDict/FlexibleDict_BTE_1.py: -------------------------------------------------------------------------------- 1 | ''' 2 | With FlexibleDict, we allowed the user to use any key, but were then 3 | flexible with the retrieval. Implement StringKeyDict, which converts 4 | its keys into strings as part of the assignment. Thus, immediately 5 | after saying skd[1] = 10, you would be able to then say skd['1'] and 6 | get the value of 10 returned. This can come in handy if you’ll be reading 7 | keys from a file and won’t be able to distinguish between strings and integers. 8 | ''' 9 | 10 | 11 | class StringKeyDict(dict): 12 | def __setitem__(self, key, value): 13 | dict.__setitem__(self, str(key), value) 14 | 15 | skd = StringKeyDict() 16 | 17 | skd[1] = 10 18 | print(skd['1']) 19 | print(type(skd.keys())) 20 | 21 | 22 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-42-FlexibleDict/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-43-Animals/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-44-Cage/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-09-Objects/Exer-45-Zoo/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-46-MyEnumerate/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-46-MyEnumerate/myenumerate.py: -------------------------------------------------------------------------------- 1 | 2 | class MyEnumerate(): 3 | def __init__(self, data): 4 | self.data = data 5 | self.index = 0 6 | 7 | def __iter__(self): 8 | return self 9 | 10 | def __next__(self): 11 | if self.index >= len(self.data): 12 | raise StopIteration 13 | value = (self.index, self.data[self.index]) 14 | self.index += 1 15 | return value 16 | 17 | for index, letter in MyEnumerate('abc'): 18 | print(f'{index} : {letter}') 19 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-46-MyEnumerate/myenumerate_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Redefine MyEnumerate as a generator function, rather than as a class. 4 | ''' 5 | 6 | def my_enumerate(data, start=0): 7 | index = start 8 | 9 | for one_item in data: 10 | yield (index, one_item) 11 | index += 1 12 | 13 | print(my_enumerate('abcd')) # creates a generator object 14 | print(*my_enumerate('abcd', 1)) # prints the tuples: (1, 'a') (2, 'b') (3, 'c') (4, 'd') 15 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-47-Circle/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-47-Circle/circle_BTE_2.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Implement Circle as a generator function, rather than as a class. 4 | ''' 5 | 6 | def circle(data, max_times): 7 | for index in range(max_times): 8 | yield data[index % len(data)] 9 | 10 | 11 | c = circle('abcd', 7) 12 | 13 | 14 | # abcdabc 15 | #print('** A **') 16 | for one_item in c: 17 | print(one_item) 18 | 19 | #print('** B **') 20 | #for one_item in c: 21 | # print(one_item) 22 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-48-All-lines-all-files/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-48-All-lines-all-files/all_lines.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write an iterator (as a generator function) that returns each line 3 | from each file in a named directory. 4 | 5 | Any file that cannot be opened, for whatever reason, is ignored. 6 | ''' 7 | 8 | import os 9 | 10 | def all_lines(path): 11 | for filename in os.listdir(path): 12 | full_filename = os.path.join(path, filename) 13 | try: 14 | for line in open(full_filename): 15 | yield line 16 | except OSError: 17 | pass 18 | 19 | for one_line in all_lines('txt_files'): 20 | print(one_line) 21 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-49-Elapsed-since/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-49-Elapsed-since/elapsed_since.py: -------------------------------------------------------------------------------- 1 | ''' 2 | A generator that takes an iterable as input. 3 | 4 | With each iteration, it yields a tuple containing the data and the time 5 | since the previous iteration. 6 | ''' 7 | 8 | import time 9 | import random 10 | 11 | def elapsed_since(data): 12 | last_time = None 13 | for one_item in data: 14 | current_time = time.perf_counter() 15 | delta = current_time - (last_time or current_time) 16 | last_time = time.perf_counter() 17 | yield (delta, one_item) 18 | 19 | for t in elapsed_since('abcd'): 20 | time.sleep(random.randint(0, 2)) 21 | print(t) 22 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-49-Elapsed-since/elapsed_since_BTE_3.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | Write a generator function that takes two elements: an iterable and 4 | a function. With each iteration, the function is invoked on the current 5 | element. If the result is True, then the element is returned as is. 6 | Otherwise, the next element is tested, until the function returns True. 7 | Alternative: implement this as a regular function that returns a generator expression. 8 | ''' 9 | 10 | 11 | def yield_filter(data, func): 12 | for one_item in data: 13 | if func(one_item): 14 | yield one_item 15 | 16 | def is_alpha(item): 17 | return item.isalpha() 18 | 19 | for item in yield_filter('+abcd23@', is_alpha): 20 | print(item) 21 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-50-MyChain/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CHPT-10-Iterators-and-generators/Exer-50-MyChain/mychain.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Generator that takes any number of iterables as arguments. It yields, one at 3 | a time, each of the elements of each iterable. 4 | 5 | It is similar to itertools.chain 6 | ''' 7 | 8 | def mychain(*args): 9 | for one_item in args: 10 | for one_element in one_item: 11 | yield one_element 12 | 13 | for one_item in mychain('abc', [10, 20, 30, 40, 50], (100, 200, 300), [2, 4, 6]): 14 | print(one_item) 15 | --------------------------------------------------------------------------------