Advertisement
Guest User

Untitled

a guest
Jul 18th, 2018
538
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # ICS 31, Thursday 9 November 2017
  2.  
  3. """
  4. Control structures alter the FLOW OF CONTROL
  5. Sequence
  6. Repetition: for while recursion (not ICS 31)
  7. Modularity/function call and return
  8.  
  9. Short-circuiting the flow of control:
  10. break statement: Takes you out of the current loop (down to next statement after
  11. loop body)
  12. return statement (only from within a function): Ejector seat from the whole function,
  13. back immediately to the code that called the function.
  14. continue statement: Out of the current ITERATION. Skips to end of body but repeats
  15. the next iteration (next list item or whatever).
  16.  
  17. for i in s:
  18. stmt 1
  19. stmt 2
  20. if whatever():
  21. continue # skip stmt3 and stmt4, then go check if you're done repeating.
  22. # If there are more repetitions left, do the next one.
  23. stmt 3
  24. stmt 4
  25. stmt 5 # We don't get here until we've processed the last i in s.
  26.  
  27. # The continue statement is syntactic sugar for the following if statement:
  28.  
  29. for i in s:
  30. stmt 1
  31. stmt 2
  32. if not whatever():
  33. stmt 3
  34. stmt 4
  35. stmt 5
  36.  
  37. """
  38.  
  39. ### RESTAURANTS PROGRAM -- ICS 31, FALL 2017 -- Version with external files.
  40.  
  41. from collections import namedtuple
  42.  
  43. Restaurant = namedtuple('Restaurant', 'name cuisine phone dish price')
  44.  
  45.  
  46. def restaurants():
  47. ''' Main program (controller): Create and maintain a database of restaurants '''
  48. print("Welcome to the Restaurants Program!")
  49. print()
  50. choice = """If you'd like to read restaurants from an existing file,
  51. type the name of that file; if not, just hit RETURN: """
  52. filename = input(choice)
  53. if filename == "":
  54. our_rests = Collection_new() # Gives us an empty list, respects the abstraction barrier
  55. else:
  56. our_rests = fill_collection_from_file(filename)
  57. our_rests = handle_commands(our_rests)
  58. write_file_from_collection(our_rests)
  59. print()
  60. print("Thank you. Good-bye.")
  61. return
  62.  
  63.  
  64. def handle_commands(L: 'list of Restaurant') -> 'list of Restaurant':
  65. pass ## Lets us build a PROGRAM STUB, to be filled in later.
  66.  
  67.  
  68. MENU = """
  69. Restaurant Collection Program --- Choose one
  70. a: Add a new restaurant to the collection
  71. r: Remove a restaurant from the collection
  72. s: Search the collection for selected restaurants
  73. p: Print all the restaurants
  74. q: Quit
  75. """
  76.  
  77. # It's legal to have this second version of handle_commands() here
  78. # in the code, not commented out. As long as the last version is the
  79. # version we want, it's the version we get; later definitions just
  80. # supersede the previous ones. (We keep the versions here so you can
  81. # see how they developed. This is fine in class notes. Nobody would
  82. # do it in commercial software, although there are "version control"
  83. # tools that let you save historical information.)
  84.  
  85. # Next version: Read command and just echo it
  86.  
  87.  
  88. ## In the final version of handle_commands, we made a couple
  89. ## of changes that are just for clarity or showing alternatives:
  90. ## -- We changed the parameter name in handle_commands from L to
  91. ## # RC (for Restaurant Collection). Nothing outside of handle_commands
  92. ## needed to change.
  93. ## -- For 'list of Restaurant' as a type annotation, we substituted
  94. ## [Restaurant]. Either form is fine for us.
  95.  
  96.  
  97. def handle_commands(RC: [Restaurant]) -> [Restaurant]:
  98. ''' Handle the commands the user enters, affecting the collection. '''
  99. while True:
  100. command = input(MENU)
  101. if command == 'q':
  102. break # Bail out if user wants to quit
  103. elif command == 'a':
  104. # print("You want to add a new restaurant")
  105. new_rest = Restaurant_get_info()
  106. RC = Collection_add(RC, new_rest)
  107. elif command == 'r':
  108. # print("You want to remove a restaurant")
  109. name_to_remove = input("Please enter the name of the " +
  110. "restaurant to remove: ")
  111. RC = Collection_remove_by_name(RC, name_to_remove)
  112. elif command == 's':
  113. # print("You want to search for a restaurant")
  114. name_to_find = input("Please enter the name of the " +
  115. "restaurant to search for: ")
  116. print(Collection_to_str(Collection_search_by_name(RC, name_to_find)))
  117. # No change to RC itself
  118. elif command == 'p':
  119. # print("You want to print the restaurants")
  120. print(Collection_to_str(RC))
  121. else:
  122. print("You typed '", command, "'. ",
  123. "That isn't a valid command. ",
  124. "Please try again.", sep='')
  125. ## Note that the break statement takes us here, the statement after the loop.
  126. return RC
  127.  
  128.  
  129. ########################
  130. ## MODEL part of the program:
  131. ## -- Restaurant (built with namedtuple)
  132. ## -- Collection (built as a list of Restaurant objects)
  133. ########################
  134.  
  135. ## RESTAURANTS
  136.  
  137. # For testing:
  138. R1 = Restaurant('Taillevent', 'French', '00-11-22-33-44-55', 'Escargots', 23.50)
  139. #print(R1)
  140. R2 = Restaurant('Thai Dishes', 'Thai', '334-4433', 'Mee Krob', 8.95)
  141. R3 = Restaurant('Thai Touch', 'Thai', '444-3333', 'Larb Gai', 11.00)
  142.  
  143. def Restaurant_print(R: Restaurant) -> None: # Just prints
  144. ''' Print a human-readable Restaurant '''
  145. print('Name: ', R.name)
  146. print('Cuisine: ', R.cuisine)
  147. print('Phone: ', R.phone)
  148. print('Dish: ', R.dish)
  149. print('Price: $', R.price)
  150. return
  151. # Restaurant_print(R1)
  152.  
  153. # We can't use assert statements with a function that prints its output
  154. # rather than returning a value. When we call it, it prints; but that
  155. # means that we have to print to test it, and assert doesn't do anything
  156. # about printed output.
  157. # So here's what we'll do, both for added flexibility and to enable
  158. # using assert statements,we'll write a function to RETURN A STRING
  159. # containing the restaurant info. That gives to the person who CALLS
  160. # our function the choice of how to use that string.
  161.  
  162. def Restaurant_to_str(R: Restaurant) -> str:
  163. ''' Create a string with the restaurant info in readable form '''
  164. return 'Name: ' + R.name + '\n' + \
  165. 'Cuisine: ' + R.cuisine + '\n' + \
  166. 'Phone: ' + R.phone + '\n' + \
  167. 'Dish: ' + R.dish + '\n' + \
  168. 'Price: $' + str(R.price) + '\n\n'
  169. # The backslashes above tell Python there's more to this statement on the next line
  170. #print(Restaurant_to_str(R3))
  171. assert Restaurant_to_str(R3) == """Name: Thai Touch
  172. Cuisine: Thai
  173. Phone: 444-3333
  174. Dish: Larb Gai
  175. Price: $11.0
  176.  
  177. """
  178.  
  179. """
  180. We could write out restaurants in the form above and read them back in,
  181. stripping off the labels. But more compact and more common would be to use a
  182. TAB-DELIMITED string.
  183. """
  184.  
  185. def Restaurant_to_tabbed_string(r: Restaurant) -> str:
  186. ''' Return a string containing the restaurant's fields,
  187. separated by tabs
  188. '''
  189. return r.name + "\t" + r.cuisine + "\t" + r.phone + "\t" + r.dish + "\t" + str(r.price)
  190. assert Restaurant_to_tabbed_string(R3) == "Thai Touch\tThai\t444-3333\tLarb Gai\t11.0"
  191.  
  192. # If you try typing this assertion, you'll have to get every single space and
  193. # character perfect before the equality is true and the assertion passes.
  194.  
  195. # We'll learn how to print dollars-and-cents amounts perfectly in a few weeks.
  196.  
  197. # In Python you can continue a statement from one line to the next with backslashes,
  198. # as above. But you can omit the backslashes if you're typing something that's in
  199. # parentheses or square brackets or similar paired symbols, because Python "knows"
  200. # there's more to expect when it hasn't seen the matching (closing) symbol. The
  201. # version below works just the same way as the one above.
  202.  
  203. def Restaurant_to_str(R: Restaurant) -> str:
  204. ''' Create a string with the restaurant info in readable form '''
  205. return ('Name: ' + R.name + '\n' +
  206. 'Cuisine: ' + R.cuisine + '\n' +
  207. 'Phone: ' + R.phone + '\n' +
  208. 'Dish: ' + R.dish + '\n' +
  209. 'Price: ' + f'${R.price:0.2f}' + '\n\n')
  210. #print(Restaurant_to_str(R3))
  211. assert Restaurant_to_str(R3) == """Name: Thai Touch
  212. Cuisine: Thai
  213. Phone: 444-3333
  214. Dish: Larb Gai
  215. Price: $11.00
  216.  
  217. """
  218.  
  219. def Restaurant_get_info() -> Restaurant:
  220. ''' Return a Restaurant created from the user's responses '''
  221. n = input("Please enter the restaurant's name: ")
  222. c = input("Please enter the kind of food served: ")
  223. ph = input("Please enter the phone number: ")
  224. d = input("Please enter the name of the best dish: ")
  225. p = input("Please enter the price of that dish: ")
  226. return Restaurant(n, c, ph, d, float(p))
  227. #R4 = Restaurant_get_info()
  228. #print(R4)
  229. #print(Restaurant_to_str(R4))
  230.  
  231.  
  232. ## COLLECTION
  233.  
  234. # A collection of Restaurants is built as a list of Restaurant objects.
  235.  
  236. # We might decide some day to build it differently, though. Real software
  237. # is often revised, possibly to reflect changed circumstances (like adding a
  238. # home page for each Restaurant) or to make the program more efficient.
  239. # One way of revising is to change the underlying data structure---using a
  240. # dictionary instead of a list, for example. We aren't yet ready to make
  241. # that kind of design decision, but we can write our code to facilitate it.
  242.  
  243. # When we worked with graphics canvases using tkinter, the information we
  244. # had was the names of the functions we could call, the number and type of
  245. # each function's arguments, and an English description of what the function
  246. # does. We did NOT have the entire function definition. The author of tkinter
  247. # promises us that if we call the tkinter functions according to the information
  248. # provided, they will work as described, even if the author changes the internal
  249. # details. We don't need to know the details of the underlying code; we don't
  250. # want to have to think about it. The information the author gives us is called
  251. # an API (Application Programming Interface). It's a way of dividing up the
  252. # responsibility for a large program. Here we write an API for a Restaurant
  253. # Collection. That means we have a series of functions that manipulate
  254. # a collection. As long as they always behave the way we've said they will,
  255. # we can change the internal details (like using a list or something else).
  256.  
  257. # That's why we describe everything in terms of a "collection"---that doesn't
  258. # limit us to one way of building it.
  259.  
  260. TRC = [R1, R2, R3] # Test Restaurant Collection
  261.  
  262. def Collection_new() -> 'list of Restaurants':
  263. ''' Create and return a new, empty collection (list) '''
  264. return [ ]
  265. assert Collection_new() == [ ]
  266.  
  267. def Collection_add(C: 'list of Restaurant', r: Restaurant) -> 'list of Restaurant':
  268. ''' Return the colection with the new restaurant added '''
  269. C.append(r)
  270. return C
  271. # Alternative: return C + [r]
  272. assert Collection_add(Collection_new(), R1) == [R1]
  273. assert Collection_add([R2, R3], R1) == [R2, R3, R1]
  274.  
  275. def Collection_to_str(C: 'list of Restaurant') -> str:
  276. ''' Return a string representing the whole collection '''
  277. result = ""
  278. for r in C:
  279. result = result + Restaurant_to_str(r)
  280. return result
  281. assert Collection_to_str(Collection_new()) == ""
  282. assert Collection_to_str(TRC) == \
  283. Restaurant_to_str(R1) + Restaurant_to_str(R2) + Restaurant_to_str(R3)
  284.  
  285. def Collection_search_by_name(C: 'list of Restaurant', looking_for: str) \
  286. -> 'list of Restaurant':
  287. ''' Return a collection containing those restaurants in the first parameter
  288. that match the name you're looking for. '''
  289. result = [ ]
  290. for r in C:
  291. if r.name == looking_for:
  292. result.append(r)
  293. return result
  294. assert Collection_search_by_name(TRC, "Taillevent") == [R1]
  295. assert Collection_search_by_name(TRC, "McDonald's") == [ ]
  296. assert Collection_search_by_name([R2, R3, R2, R1], "Thai Dishes") == [R2, R2]
  297.  
  298. def Collection_remove_by_name(C: 'list of Restaurant', to_remove: str) \
  299. -> 'list of Restaurant':
  300. ''' Return collection with the named restaurant(s) deleted. '''
  301. result = [ ]
  302. for r in C:
  303. if r.name != to_remove:
  304. result.append(r) # Save the ones we *don't* want to remove
  305. return result
  306. ## Many combinations to test
  307. # Remove from the empty list [still empty]
  308. assert Collection_remove_by_name([], "Taillevent") == [ ]
  309. # Remove item not on list at all
  310. assert Collection_remove_by_name(TRC, "McDonald's") == TRC
  311. # Remmove item from list, result empty
  312. assert Collection_remove_by_name([R3], R3.name) == [ ]
  313. # Remove first item from list
  314. assert Collection_remove_by_name(TRC, "Taillevent") == [R2, R3]
  315. # Remove last item on list
  316. assert Collection_remove_by_name(TRC, "Thai Touch") == [R1, R2]
  317. # Remove from middle of list
  318. assert Collection_remove_by_name(TRC, "Thai Dishes") == [R1, R3]
  319. # Remove multiple occurrences of name
  320. assert Collection_remove_by_name([R3, R2, R3, R1, R3],
  321. "Thai Touch") == [R2, R1]
  322.  
  323. def write_file_from_collection(C: 'list of Restaurant') -> None: # Side effect: write a file
  324. ''' Write a file called restaurants.txt, tab-delimited
  325. '''
  326. outfile = open('restaurants.txt', 'w')
  327. for r in C:
  328. outfile.write(Restaurant_to_tabbed_string(r) + "\n")
  329. outfile.close()
  330. return
  331.  
  332. def fill_collection_from_file(filename:str) -> 'list of Restaurant':
  333. ''' Read restaurant info from file; return collection.
  334. File has one line for each restaurant, with fields delimited by tabs.
  335. '''
  336. result = []
  337. infile = open(filename, 'r')
  338. for line in infile:
  339. field_list = line.split("\t")
  340. new_rest = Restaurant(field_list[0], field_list[1], field_list[2],
  341. field_list[3], float(field_list[4]))
  342. result.append(new_rest)
  343. return result
  344.  
  345. ## Now we go back to create the final version of handle_commands()
  346.  
  347. ## At the very bottom, we get everything started:
  348. restaurants()
  349.  
  350.  
  351.  
  352.  
  353.  
  354. # ICS 31, Thursday 30 November 2017
  355.  
  356. """
  357. Today: One more basic data structure built in to Python: the SET
  358. A set is a collection with no duplicates, where the order doesn't matter.
  359. Sets, like any data structure, fit some problems very well.
  360. E.g., the set of econ majors.
  361. """
  362. s = {1, 2, 3, 4, 5} # same as {1, 2, 5, 3, 4}
  363. print(s)
  364. empty_dict = {}
  365. empty_set = {}
  366. print(type(empty_dict))
  367. print(type(empty_set))
  368. empty_set = set()
  369. print(type(empty_set))
  370.  
  371. t = {2, 4, 6, 8, 10}
  372. print(s, t)
  373. L = {2,3,4,1,2,3,3,5,2,4,2,2,3,4,5,1,2,3,4,1,2,3,1}
  374. print(L, L == s)
  375.  
  376. q = {'apple', 23, ('p','q')}
  377. print(q)
  378. from collections import namedtuple
  379. Restaurant = namedtuple('Restaurant', 'name cuisine phone dish price')
  380. R = Restaurant('Noma', 'Modern Danish', '334-4433', 'Anchovy Abelskiver', 34.50)
  381. r = {2345, R, (1,2,3)}
  382. print(r)
  383.  
  384. LL = [2,3,4,1,2,3,3,5,2,4,2,2,3,4,5,1,2,3,4,1,2,3,1]
  385. print(LL)
  386. unique = set(LL)
  387. print(unique)
  388.  
  389. # Bulletproof assertion for remove_duplicats,
  390. # recognizing that the order may be shuffled:
  391. # assert sorted(duplicates_removed(LL)) == [1,2,3,4,5]
  392.  
  393.  
  394.  
  395.  
  396. # ICS 31, Tuesday 5 December 2017
  397.  
  398. from collections import namedtuple
  399.  
  400. Restaurant = namedtuple('Restaurant', 'name cuisine phone dish price')
  401. # Restaurant attributes: name, kind of food served, phone number,
  402. # best dish, price of that dish
  403.  
  404. R1 = Restaurant("Taillevent", "French", "343-3434", "Escargots", 24.50)
  405. R2 = Restaurant("La Tour D'Argent", "French", "343-3344", "Ris de Veau", 48.50)
  406. R3 = Restaurant("Pascal", "French", "333-4444", "Bouillabaisse", 32.00)
  407. R4 = Restaurant("Thai Touch", "Thai", "444-3333", "Mee Krob", 10.95)
  408. R5 = Restaurant("Thai Dishes", "Thai", "333-4433", "Paht Woon Sen", 8.50)
  409. R6 = Restaurant("Thai Spoon", "Thai", "334-3344", "Mussamun", 9.00)
  410. R7 = Restaurant("McDonald's", "Burgers", "333-4443", "Big Mac", 3.95)
  411. R8 = Restaurant("Burger King", "Burgers", "444-3344", "Whopper", 3.75)
  412. R9 = Restaurant("Wahoo's", "Fish Tacos", "443-4443", "Mahi Mahi Burrito", 7.50)
  413. R10 = Restaurant("In-N-Out Burger", "Burgers", "434-3344", "Cheeseburger", 2.50)
  414. R11 = Restaurant("The Shack", "Burgers", "333-3334", "Hot Link Burger", 4.50)
  415. R12 = Restaurant("Gina's", "Pizza", "334-4433", "Combo Pizza", 12.95)
  416. R13 = Restaurant("Peacock, Room", "Indian", "333-4443", "Rogan Josh", 12.50)
  417. R14 = Restaurant("Gaylord", "Indian", "333-3433", "Tandoori Chicken", 13.50)
  418. R15 = Restaurant("Mr. Chow", "Chinese", "222-3333", "Peking Duck", 24.50)
  419. R16 = Restaurant("Chez Panisse", "California", "222-3322", "Grilled Duck Breast", 25.00)
  420. R17 = Restaurant("Spago", "California", "333-2222", "Striped Bass", 24.50)
  421. R18 = Restaurant("Sriped Bass", "Seafood", "333-2233", "Cedar Plank Salmon", 21.50)
  422. R19 = Restaurant("Golden Pagoda", "Chinese", "232-3232", "Egg Foo Young", 8.50)
  423. R20 = Restaurant("Langer's", "Delicatessen", "333-2223", "Pastrami Sandwich", 11.50)
  424. R21 = Restaurant("Nobu", "Japanese", "335-4433", "Natto Temaki", 5.50)
  425. R22 = Restaurant("Nonna", "Italian", "355-4433", "Stracotto", 25.50)
  426. R23 = Restaurant("Jitlada", "Thai", "324-4433", "Paht Woon Sen", 15.50)
  427. R24 = Restaurant("Nola", "New Orleans", "336-4433", "Jambalaya", 5.50)
  428. R25 = Restaurant("Noma", "Modern Danish", "337-4433", "Birch Sap", 35.50)
  429. R26 = Restaurant("Addis Ababa", "Ethiopian", "337-4453", "Yesiga Tibs", 10.50)
  430.  
  431.  
  432. RL = [R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16,
  433. R17, R18, R19, R20, R21, R22, R23, R24, R25, R26]
  434.  
  435. """
  436. DUPLICATE CODE IS BAD!
  437. Too long, cluttered, error-prone/inconsistent
  438.  
  439. PLs give us a variety of ways to capture commonalities.
  440. Sometimes called "refactoring".
  441. """
  442.  
  443. def is_Thai(R: Restaurant) -> bool:
  444. ''' Return True if R's cuisine is Thai'''
  445. return R.cuisine == "Thai"
  446. assert is_Thai(R4)
  447. assert not is_Thai(R26)
  448.  
  449. """
  450. This function returns a boolean. We call functions that return booleans PREDICATES.
  451. So is_Thai() is a predicate that operates on Restaurants.
  452. """
  453.  
  454. def is_French(R: Restaurant) -> bool:
  455. ''' Return True of R's cuisine is French'''
  456. return R.cuisine == "French"
  457. assert is_French(R1)
  458. assert not is_French(R26)
  459.  
  460. ## How do we capture what's in common here? Use a parameter.
  461.  
  462. def matches_cuisine(R: Restaurant, c: str) -> bool:
  463. ''' Return True if R's cuisine matches c '''
  464. return R.cuisine == c
  465. assert matches_cuisine(R26, 'Ethiopian')
  466. assert matches_cuisine(R1, 'French')
  467. assert not matches_cuisine(R26, 'Japanese')
  468.  
  469. def is_cheap(R: Restaurant) -> bool:
  470. ''' Return True if R's price is $10 or less '''
  471. return R.price <= 10
  472. assert is_cheap(R5)
  473. assert is_cheap(Restaurant("","","","",10.00))
  474. assert not is_cheap(R1)
  475.  
  476. def all_Thai(L: 'list of Restaurant') -> 'list of Restaurant':
  477. ''' Return a list of those restaurants in L that serve Thai food '''
  478. result = []
  479. for R in L:
  480. if is_Thai(R):
  481. result.append(R)
  482. return result
  483. assert all_Thai(RL) == [R4, R5, R6, R23]
  484. assert all_Thai([]) == []
  485. assert all_Thai([R19, R20, R21, R22]) == []
  486. assert all_Thai([R19, R20, R23, R21, R22]) == [R23]
  487.  
  488. def all_cheap(L: 'list of Restaurant') -> 'list of Restaurant':
  489. ''' Return a list of those restaurants in L that are cheap '''
  490. result = []
  491. for R in L:
  492. if is_cheap(R):
  493. result.append(R)
  494. return result
  495. assert all_cheap(RL) == [R5, R6, R7, R8, R9, R10, R11, R19, R21, R24]
  496. assert all_cheap([]) == []
  497. assert all_cheap([R1, R2, R3, R4]) == []
  498. assert all_cheap([R5, R6, R7, R8, R12, R13]) == [R5, R6, R7, R8]
  499.  
  500. """
  501. all_Thai and all_cheap are nearly identical,
  502. except for the predicate function they use to examine each restaurant.
  503.  
  504. When you find yourself in real life copying, pasting, and tweaking code,
  505. look for an opportunity to refactor.
  506. """
  507. def is_Peruvian(R: Restaurant) -> bool:
  508. ''' Return True of R's cuisine is Peruvian'''
  509. return R.cuisine == "Peruvian"
  510. assert is_Peruvian(Restaurant("x", "Peruvian", "x", "x", 0))
  511. assert not is_Peruvian(R26)
  512.  
  513. def all_matches(L: 'list of Restaurant', test: 'func restaurant -> bool') -> 'list of Restaurant':
  514. ''' Return a list of all the Restaurants in L that pass the test '''
  515. result = []
  516. for R in L:
  517. if test(R):
  518. result.append(R)
  519. return result
  520.  
  521. assert all_matches(RL, is_cheap) == [R5, R6, R7, R8, R9, R10, R11, R19, R21, R24]
  522. assert all_matches(RL, is_Thai) == [R4, R5, R6, R23]
  523. assert all_matches([], is_Thai) == []
  524. assert all_matches(RL, is_Peruvian) == []
  525.  
  526. ## With all_matches, we no longer need specific all_Thai, all_cheap, all_whatever.
  527. ## We do still need is_cheap, is_French, ... so far.
  528.  
  529. """
  530. This pattern of selecting some items from a list is called FILTERING.
  531.  
  532. Suppose we want the NAMES of all the Thai restaurants
  533. (not the whole Restaurant object, which is what all_matches gives us)
  534. """
  535.  
  536. def extract_names(L: 'list of Restaurant') -> 'list of str':
  537. ''' Return a list of the names of each restaurant in L '''
  538. result = []
  539. for R in L:
  540. result.append(R.name)
  541. return result
  542. assert extract_names([]) == []
  543. assert extract_names(all_matches(RL, is_Peruvian)) == []
  544. assert extract_names(all_matches(RL, is_French)) == ['Taillevent', "La Tour D'Argent", 'Pascal']
  545.  
  546. ## Now let's extract (name, phone) tuples
  547.  
  548. def extract_names_and_phones(L: 'list of Restaurant') -> 'list of (name,phone) tuples':
  549. ''' Return a list of tuples containing the name and phone of each restaurant in L '''
  550. result = []
  551. for R in L:
  552. result.append((R.name, R.phone))
  553. return result
  554. assert extract_names_and_phones([]) == []
  555. assert extract_names_and_phones(all_matches(RL, is_Peruvian)) == []
  556. assert extract_names_and_phones(all_matches(RL, is_French)) == \
  557. [('Taillevent', '343-3434'),
  558. ("La Tour D'Argent", '343-3344'),
  559. ('Pascal','333-4444')]
  560.  
  561. def name_phone(R: Restaurant) -> '(name,phone) tuple':
  562. ''' Return a tuple (name, phone) from R '''
  563. return (R.name, R.phone)
  564.  
  565. def transform_each(L: 'list of Restaurant', op: 'func Restaurant -> X') -> 'list of X':
  566. ''' Return a list of items produced by applying op to each iteim in L'''
  567. result = []
  568. for R in L:
  569. result.append(op(R))
  570. return result
  571. assert transform_each(all_matches(RL, is_French), name_phone) == \
  572. [('Taillevent', '343-3434'),
  573. ("La Tour D'Argent", '343-3344'),
  574. ('Pascal','333-4444')]
  575.  
  576. """
  577. The all_matches() function does FILTERING
  578. The transform_each() function does MAPPING
  579.  
  580. In fact, Python gives us a predefined function filter()
  581. and one called map() to perform these tasks. (They return
  582. special objects that we can turn into lists, as we did with
  583. the dict methods keys(), values(), and items().)
  584. """
  585. print('Cheap restaurants:', list(filter(is_cheap, RL)))
  586. print('Names and phones of cheap restaurants:',
  587. list(map(name_phone,list(filter(is_cheap, RL)))))
  588. # Filter (select) the cheap restaurants, then transform each into a name-phone tuple
  589. """
  590. What lets us do this is that Python treats functions as data/objects,
  591. passing them to other functions.
  592. We call this using HIGHER-ORDER FUNCTIONS, functions that take or return other functions.
  593. We say that functions are FIRST-CLASS OBJECTS in Python.
  594.  
  595. We've had to define a lot of little functions to use just once (is_cheap, is_French, ...).
  596. Wouldn't it be nice to define these little fuctions on the fly,
  597. right where we need them, instead of doing the whole 'def' thing?
  598.  
  599. We can say
  600. x = 2 + 2
  601. print(x)
  602. but if we're never going to use x again, we can also say
  603. print(2+2)
  604. We can do this same thing with functions.
  605. We do it using LAMBDA EXPRESSIONS. The value of a lambda expression is a function.
  606.  
  607. [Lambda is a letter in the Greek allphabet. It's here because a branch
  608. of mathematical logic called the "lambda calculus" operates on functions.
  609. The lambda calculus was invented by Alonzo Church. The first programming
  610. language to use lambda expressions was LISP, invented by John McCarthy in
  611. 1958. Current dialects of LISP are Racket, Scheme, and Common Lisp.
  612. """
  613. def double0(n: int) -> int:
  614. return 2 * n
  615.  
  616. # Defines the name double0 to mean 'a function that returns 2 * its int argument'
  617.  
  618. # The following is exactly equivalent for the name double:
  619.  
  620. double = lambda n: n*2
  621.  
  622. print(double0(13))
  623. print(double(13))
  624.  
  625. print((lambda n: 2*n)(17))
  626. """
  627. The value of (lambda n: 2*n) is "a function that returns 2 * its argument"
  628. The value of double is "a function that returns 2 * its argument"
  629. The value of double0 is "a function that returns 2 * its argument"
  630. They're interchangeable.
  631.  
  632. """
  633. Ethiopian_rests = all_matches(RL, lambda R: R.cuisine=='Ethiopian')
  634. print(Ethiopian_rests)
  635. # We don't need to define is_Ethiopian if we want to describe its
  636. # operation just here in this one place.
  637. # We call this "using ANONYMOUS LAMBDA", a lambda expression without a name.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement