Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # ICS 31, Thursday 9 November 2017
- """
- Control structures alter the FLOW OF CONTROL
- Sequence
- Repetition: for while recursion (not ICS 31)
- Modularity/function call and return
- Short-circuiting the flow of control:
- break statement: Takes you out of the current loop (down to next statement after
- loop body)
- return statement (only from within a function): Ejector seat from the whole function,
- back immediately to the code that called the function.
- continue statement: Out of the current ITERATION. Skips to end of body but repeats
- the next iteration (next list item or whatever).
- for i in s:
- stmt 1
- stmt 2
- if whatever():
- continue # skip stmt3 and stmt4, then go check if you're done repeating.
- # If there are more repetitions left, do the next one.
- stmt 3
- stmt 4
- stmt 5 # We don't get here until we've processed the last i in s.
- # The continue statement is syntactic sugar for the following if statement:
- for i in s:
- stmt 1
- stmt 2
- if not whatever():
- stmt 3
- stmt 4
- stmt 5
- """
- ### RESTAURANTS PROGRAM -- ICS 31, FALL 2017 -- Version with external files.
- from collections import namedtuple
- Restaurant = namedtuple('Restaurant', 'name cuisine phone dish price')
- def restaurants():
- ''' Main program (controller): Create and maintain a database of restaurants '''
- print("Welcome to the Restaurants Program!")
- print()
- choice = """If you'd like to read restaurants from an existing file,
- type the name of that file; if not, just hit RETURN: """
- filename = input(choice)
- if filename == "":
- our_rests = Collection_new() # Gives us an empty list, respects the abstraction barrier
- else:
- our_rests = fill_collection_from_file(filename)
- our_rests = handle_commands(our_rests)
- write_file_from_collection(our_rests)
- print()
- print("Thank you. Good-bye.")
- return
- def handle_commands(L: 'list of Restaurant') -> 'list of Restaurant':
- pass ## Lets us build a PROGRAM STUB, to be filled in later.
- MENU = """
- Restaurant Collection Program --- Choose one
- a: Add a new restaurant to the collection
- r: Remove a restaurant from the collection
- s: Search the collection for selected restaurants
- p: Print all the restaurants
- q: Quit
- """
- # It's legal to have this second version of handle_commands() here
- # in the code, not commented out. As long as the last version is the
- # version we want, it's the version we get; later definitions just
- # supersede the previous ones. (We keep the versions here so you can
- # see how they developed. This is fine in class notes. Nobody would
- # do it in commercial software, although there are "version control"
- # tools that let you save historical information.)
- # Next version: Read command and just echo it
- ## In the final version of handle_commands, we made a couple
- ## of changes that are just for clarity or showing alternatives:
- ## -- We changed the parameter name in handle_commands from L to
- ## # RC (for Restaurant Collection). Nothing outside of handle_commands
- ## needed to change.
- ## -- For 'list of Restaurant' as a type annotation, we substituted
- ## [Restaurant]. Either form is fine for us.
- def handle_commands(RC: [Restaurant]) -> [Restaurant]:
- ''' Handle the commands the user enters, affecting the collection. '''
- while True:
- command = input(MENU)
- if command == 'q':
- break # Bail out if user wants to quit
- elif command == 'a':
- # print("You want to add a new restaurant")
- new_rest = Restaurant_get_info()
- RC = Collection_add(RC, new_rest)
- elif command == 'r':
- # print("You want to remove a restaurant")
- name_to_remove = input("Please enter the name of the " +
- "restaurant to remove: ")
- RC = Collection_remove_by_name(RC, name_to_remove)
- elif command == 's':
- # print("You want to search for a restaurant")
- name_to_find = input("Please enter the name of the " +
- "restaurant to search for: ")
- print(Collection_to_str(Collection_search_by_name(RC, name_to_find)))
- # No change to RC itself
- elif command == 'p':
- # print("You want to print the restaurants")
- print(Collection_to_str(RC))
- else:
- print("You typed '", command, "'. ",
- "That isn't a valid command. ",
- "Please try again.", sep='')
- ## Note that the break statement takes us here, the statement after the loop.
- return RC
- ########################
- ## MODEL part of the program:
- ## -- Restaurant (built with namedtuple)
- ## -- Collection (built as a list of Restaurant objects)
- ########################
- ## RESTAURANTS
- # For testing:
- R1 = Restaurant('Taillevent', 'French', '00-11-22-33-44-55', 'Escargots', 23.50)
- #print(R1)
- R2 = Restaurant('Thai Dishes', 'Thai', '334-4433', 'Mee Krob', 8.95)
- R3 = Restaurant('Thai Touch', 'Thai', '444-3333', 'Larb Gai', 11.00)
- def Restaurant_print(R: Restaurant) -> None: # Just prints
- ''' Print a human-readable Restaurant '''
- print('Name: ', R.name)
- print('Cuisine: ', R.cuisine)
- print('Phone: ', R.phone)
- print('Dish: ', R.dish)
- print('Price: $', R.price)
- return
- # Restaurant_print(R1)
- # We can't use assert statements with a function that prints its output
- # rather than returning a value. When we call it, it prints; but that
- # means that we have to print to test it, and assert doesn't do anything
- # about printed output.
- # So here's what we'll do, both for added flexibility and to enable
- # using assert statements,we'll write a function to RETURN A STRING
- # containing the restaurant info. That gives to the person who CALLS
- # our function the choice of how to use that string.
- def Restaurant_to_str(R: Restaurant) -> str:
- ''' Create a string with the restaurant info in readable form '''
- return 'Name: ' + R.name + '\n' + \
- 'Cuisine: ' + R.cuisine + '\n' + \
- 'Phone: ' + R.phone + '\n' + \
- 'Dish: ' + R.dish + '\n' + \
- 'Price: $' + str(R.price) + '\n\n'
- # The backslashes above tell Python there's more to this statement on the next line
- #print(Restaurant_to_str(R3))
- assert Restaurant_to_str(R3) == """Name: Thai Touch
- Cuisine: Thai
- Phone: 444-3333
- Dish: Larb Gai
- Price: $11.0
- """
- """
- We could write out restaurants in the form above and read them back in,
- stripping off the labels. But more compact and more common would be to use a
- TAB-DELIMITED string.
- """
- def Restaurant_to_tabbed_string(r: Restaurant) -> str:
- ''' Return a string containing the restaurant's fields,
- separated by tabs
- '''
- return r.name + "\t" + r.cuisine + "\t" + r.phone + "\t" + r.dish + "\t" + str(r.price)
- assert Restaurant_to_tabbed_string(R3) == "Thai Touch\tThai\t444-3333\tLarb Gai\t11.0"
- # If you try typing this assertion, you'll have to get every single space and
- # character perfect before the equality is true and the assertion passes.
- # We'll learn how to print dollars-and-cents amounts perfectly in a few weeks.
- # In Python you can continue a statement from one line to the next with backslashes,
- # as above. But you can omit the backslashes if you're typing something that's in
- # parentheses or square brackets or similar paired symbols, because Python "knows"
- # there's more to expect when it hasn't seen the matching (closing) symbol. The
- # version below works just the same way as the one above.
- def Restaurant_to_str(R: Restaurant) -> str:
- ''' Create a string with the restaurant info in readable form '''
- return ('Name: ' + R.name + '\n' +
- 'Cuisine: ' + R.cuisine + '\n' +
- 'Phone: ' + R.phone + '\n' +
- 'Dish: ' + R.dish + '\n' +
- 'Price: ' + f'${R.price:0.2f}' + '\n\n')
- #print(Restaurant_to_str(R3))
- assert Restaurant_to_str(R3) == """Name: Thai Touch
- Cuisine: Thai
- Phone: 444-3333
- Dish: Larb Gai
- Price: $11.00
- """
- def Restaurant_get_info() -> Restaurant:
- ''' Return a Restaurant created from the user's responses '''
- n = input("Please enter the restaurant's name: ")
- c = input("Please enter the kind of food served: ")
- ph = input("Please enter the phone number: ")
- d = input("Please enter the name of the best dish: ")
- p = input("Please enter the price of that dish: ")
- return Restaurant(n, c, ph, d, float(p))
- #R4 = Restaurant_get_info()
- #print(R4)
- #print(Restaurant_to_str(R4))
- ## COLLECTION
- # A collection of Restaurants is built as a list of Restaurant objects.
- # We might decide some day to build it differently, though. Real software
- # is often revised, possibly to reflect changed circumstances (like adding a
- # home page for each Restaurant) or to make the program more efficient.
- # One way of revising is to change the underlying data structure---using a
- # dictionary instead of a list, for example. We aren't yet ready to make
- # that kind of design decision, but we can write our code to facilitate it.
- # When we worked with graphics canvases using tkinter, the information we
- # had was the names of the functions we could call, the number and type of
- # each function's arguments, and an English description of what the function
- # does. We did NOT have the entire function definition. The author of tkinter
- # promises us that if we call the tkinter functions according to the information
- # provided, they will work as described, even if the author changes the internal
- # details. We don't need to know the details of the underlying code; we don't
- # want to have to think about it. The information the author gives us is called
- # an API (Application Programming Interface). It's a way of dividing up the
- # responsibility for a large program. Here we write an API for a Restaurant
- # Collection. That means we have a series of functions that manipulate
- # a collection. As long as they always behave the way we've said they will,
- # we can change the internal details (like using a list or something else).
- # That's why we describe everything in terms of a "collection"---that doesn't
- # limit us to one way of building it.
- TRC = [R1, R2, R3] # Test Restaurant Collection
- def Collection_new() -> 'list of Restaurants':
- ''' Create and return a new, empty collection (list) '''
- return [ ]
- assert Collection_new() == [ ]
- def Collection_add(C: 'list of Restaurant', r: Restaurant) -> 'list of Restaurant':
- ''' Return the colection with the new restaurant added '''
- C.append(r)
- return C
- # Alternative: return C + [r]
- assert Collection_add(Collection_new(), R1) == [R1]
- assert Collection_add([R2, R3], R1) == [R2, R3, R1]
- def Collection_to_str(C: 'list of Restaurant') -> str:
- ''' Return a string representing the whole collection '''
- result = ""
- for r in C:
- result = result + Restaurant_to_str(r)
- return result
- assert Collection_to_str(Collection_new()) == ""
- assert Collection_to_str(TRC) == \
- Restaurant_to_str(R1) + Restaurant_to_str(R2) + Restaurant_to_str(R3)
- def Collection_search_by_name(C: 'list of Restaurant', looking_for: str) \
- -> 'list of Restaurant':
- ''' Return a collection containing those restaurants in the first parameter
- that match the name you're looking for. '''
- result = [ ]
- for r in C:
- if r.name == looking_for:
- result.append(r)
- return result
- assert Collection_search_by_name(TRC, "Taillevent") == [R1]
- assert Collection_search_by_name(TRC, "McDonald's") == [ ]
- assert Collection_search_by_name([R2, R3, R2, R1], "Thai Dishes") == [R2, R2]
- def Collection_remove_by_name(C: 'list of Restaurant', to_remove: str) \
- -> 'list of Restaurant':
- ''' Return collection with the named restaurant(s) deleted. '''
- result = [ ]
- for r in C:
- if r.name != to_remove:
- result.append(r) # Save the ones we *don't* want to remove
- return result
- ## Many combinations to test
- # Remove from the empty list [still empty]
- assert Collection_remove_by_name([], "Taillevent") == [ ]
- # Remove item not on list at all
- assert Collection_remove_by_name(TRC, "McDonald's") == TRC
- # Remmove item from list, result empty
- assert Collection_remove_by_name([R3], R3.name) == [ ]
- # Remove first item from list
- assert Collection_remove_by_name(TRC, "Taillevent") == [R2, R3]
- # Remove last item on list
- assert Collection_remove_by_name(TRC, "Thai Touch") == [R1, R2]
- # Remove from middle of list
- assert Collection_remove_by_name(TRC, "Thai Dishes") == [R1, R3]
- # Remove multiple occurrences of name
- assert Collection_remove_by_name([R3, R2, R3, R1, R3],
- "Thai Touch") == [R2, R1]
- def write_file_from_collection(C: 'list of Restaurant') -> None: # Side effect: write a file
- ''' Write a file called restaurants.txt, tab-delimited
- '''
- outfile = open('restaurants.txt', 'w')
- for r in C:
- outfile.write(Restaurant_to_tabbed_string(r) + "\n")
- outfile.close()
- return
- def fill_collection_from_file(filename:str) -> 'list of Restaurant':
- ''' Read restaurant info from file; return collection.
- File has one line for each restaurant, with fields delimited by tabs.
- '''
- result = []
- infile = open(filename, 'r')
- for line in infile:
- field_list = line.split("\t")
- new_rest = Restaurant(field_list[0], field_list[1], field_list[2],
- field_list[3], float(field_list[4]))
- result.append(new_rest)
- return result
- ## Now we go back to create the final version of handle_commands()
- ## At the very bottom, we get everything started:
- restaurants()
- # ICS 31, Thursday 30 November 2017
- """
- Today: One more basic data structure built in to Python: the SET
- A set is a collection with no duplicates, where the order doesn't matter.
- Sets, like any data structure, fit some problems very well.
- E.g., the set of econ majors.
- """
- s = {1, 2, 3, 4, 5} # same as {1, 2, 5, 3, 4}
- print(s)
- empty_dict = {}
- empty_set = {}
- print(type(empty_dict))
- print(type(empty_set))
- empty_set = set()
- print(type(empty_set))
- t = {2, 4, 6, 8, 10}
- print(s, t)
- L = {2,3,4,1,2,3,3,5,2,4,2,2,3,4,5,1,2,3,4,1,2,3,1}
- print(L, L == s)
- q = {'apple', 23, ('p','q')}
- print(q)
- from collections import namedtuple
- Restaurant = namedtuple('Restaurant', 'name cuisine phone dish price')
- R = Restaurant('Noma', 'Modern Danish', '334-4433', 'Anchovy Abelskiver', 34.50)
- r = {2345, R, (1,2,3)}
- print(r)
- LL = [2,3,4,1,2,3,3,5,2,4,2,2,3,4,5,1,2,3,4,1,2,3,1]
- print(LL)
- unique = set(LL)
- print(unique)
- # Bulletproof assertion for remove_duplicats,
- # recognizing that the order may be shuffled:
- # assert sorted(duplicates_removed(LL)) == [1,2,3,4,5]
- # ICS 31, Tuesday 5 December 2017
- from collections import namedtuple
- Restaurant = namedtuple('Restaurant', 'name cuisine phone dish price')
- # Restaurant attributes: name, kind of food served, phone number,
- # best dish, price of that dish
- R1 = Restaurant("Taillevent", "French", "343-3434", "Escargots", 24.50)
- R2 = Restaurant("La Tour D'Argent", "French", "343-3344", "Ris de Veau", 48.50)
- R3 = Restaurant("Pascal", "French", "333-4444", "Bouillabaisse", 32.00)
- R4 = Restaurant("Thai Touch", "Thai", "444-3333", "Mee Krob", 10.95)
- R5 = Restaurant("Thai Dishes", "Thai", "333-4433", "Paht Woon Sen", 8.50)
- R6 = Restaurant("Thai Spoon", "Thai", "334-3344", "Mussamun", 9.00)
- R7 = Restaurant("McDonald's", "Burgers", "333-4443", "Big Mac", 3.95)
- R8 = Restaurant("Burger King", "Burgers", "444-3344", "Whopper", 3.75)
- R9 = Restaurant("Wahoo's", "Fish Tacos", "443-4443", "Mahi Mahi Burrito", 7.50)
- R10 = Restaurant("In-N-Out Burger", "Burgers", "434-3344", "Cheeseburger", 2.50)
- R11 = Restaurant("The Shack", "Burgers", "333-3334", "Hot Link Burger", 4.50)
- R12 = Restaurant("Gina's", "Pizza", "334-4433", "Combo Pizza", 12.95)
- R13 = Restaurant("Peacock, Room", "Indian", "333-4443", "Rogan Josh", 12.50)
- R14 = Restaurant("Gaylord", "Indian", "333-3433", "Tandoori Chicken", 13.50)
- R15 = Restaurant("Mr. Chow", "Chinese", "222-3333", "Peking Duck", 24.50)
- R16 = Restaurant("Chez Panisse", "California", "222-3322", "Grilled Duck Breast", 25.00)
- R17 = Restaurant("Spago", "California", "333-2222", "Striped Bass", 24.50)
- R18 = Restaurant("Sriped Bass", "Seafood", "333-2233", "Cedar Plank Salmon", 21.50)
- R19 = Restaurant("Golden Pagoda", "Chinese", "232-3232", "Egg Foo Young", 8.50)
- R20 = Restaurant("Langer's", "Delicatessen", "333-2223", "Pastrami Sandwich", 11.50)
- R21 = Restaurant("Nobu", "Japanese", "335-4433", "Natto Temaki", 5.50)
- R22 = Restaurant("Nonna", "Italian", "355-4433", "Stracotto", 25.50)
- R23 = Restaurant("Jitlada", "Thai", "324-4433", "Paht Woon Sen", 15.50)
- R24 = Restaurant("Nola", "New Orleans", "336-4433", "Jambalaya", 5.50)
- R25 = Restaurant("Noma", "Modern Danish", "337-4433", "Birch Sap", 35.50)
- R26 = Restaurant("Addis Ababa", "Ethiopian", "337-4453", "Yesiga Tibs", 10.50)
- RL = [R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16,
- R17, R18, R19, R20, R21, R22, R23, R24, R25, R26]
- """
- DUPLICATE CODE IS BAD!
- Too long, cluttered, error-prone/inconsistent
- PLs give us a variety of ways to capture commonalities.
- Sometimes called "refactoring".
- """
- def is_Thai(R: Restaurant) -> bool:
- ''' Return True if R's cuisine is Thai'''
- return R.cuisine == "Thai"
- assert is_Thai(R4)
- assert not is_Thai(R26)
- """
- This function returns a boolean. We call functions that return booleans PREDICATES.
- So is_Thai() is a predicate that operates on Restaurants.
- """
- def is_French(R: Restaurant) -> bool:
- ''' Return True of R's cuisine is French'''
- return R.cuisine == "French"
- assert is_French(R1)
- assert not is_French(R26)
- ## How do we capture what's in common here? Use a parameter.
- def matches_cuisine(R: Restaurant, c: str) -> bool:
- ''' Return True if R's cuisine matches c '''
- return R.cuisine == c
- assert matches_cuisine(R26, 'Ethiopian')
- assert matches_cuisine(R1, 'French')
- assert not matches_cuisine(R26, 'Japanese')
- def is_cheap(R: Restaurant) -> bool:
- ''' Return True if R's price is $10 or less '''
- return R.price <= 10
- assert is_cheap(R5)
- assert is_cheap(Restaurant("","","","",10.00))
- assert not is_cheap(R1)
- def all_Thai(L: 'list of Restaurant') -> 'list of Restaurant':
- ''' Return a list of those restaurants in L that serve Thai food '''
- result = []
- for R in L:
- if is_Thai(R):
- result.append(R)
- return result
- assert all_Thai(RL) == [R4, R5, R6, R23]
- assert all_Thai([]) == []
- assert all_Thai([R19, R20, R21, R22]) == []
- assert all_Thai([R19, R20, R23, R21, R22]) == [R23]
- def all_cheap(L: 'list of Restaurant') -> 'list of Restaurant':
- ''' Return a list of those restaurants in L that are cheap '''
- result = []
- for R in L:
- if is_cheap(R):
- result.append(R)
- return result
- assert all_cheap(RL) == [R5, R6, R7, R8, R9, R10, R11, R19, R21, R24]
- assert all_cheap([]) == []
- assert all_cheap([R1, R2, R3, R4]) == []
- assert all_cheap([R5, R6, R7, R8, R12, R13]) == [R5, R6, R7, R8]
- """
- all_Thai and all_cheap are nearly identical,
- except for the predicate function they use to examine each restaurant.
- When you find yourself in real life copying, pasting, and tweaking code,
- look for an opportunity to refactor.
- """
- def is_Peruvian(R: Restaurant) -> bool:
- ''' Return True of R's cuisine is Peruvian'''
- return R.cuisine == "Peruvian"
- assert is_Peruvian(Restaurant("x", "Peruvian", "x", "x", 0))
- assert not is_Peruvian(R26)
- def all_matches(L: 'list of Restaurant', test: 'func restaurant -> bool') -> 'list of Restaurant':
- ''' Return a list of all the Restaurants in L that pass the test '''
- result = []
- for R in L:
- if test(R):
- result.append(R)
- return result
- assert all_matches(RL, is_cheap) == [R5, R6, R7, R8, R9, R10, R11, R19, R21, R24]
- assert all_matches(RL, is_Thai) == [R4, R5, R6, R23]
- assert all_matches([], is_Thai) == []
- assert all_matches(RL, is_Peruvian) == []
- ## With all_matches, we no longer need specific all_Thai, all_cheap, all_whatever.
- ## We do still need is_cheap, is_French, ... so far.
- """
- This pattern of selecting some items from a list is called FILTERING.
- Suppose we want the NAMES of all the Thai restaurants
- (not the whole Restaurant object, which is what all_matches gives us)
- """
- def extract_names(L: 'list of Restaurant') -> 'list of str':
- ''' Return a list of the names of each restaurant in L '''
- result = []
- for R in L:
- result.append(R.name)
- return result
- assert extract_names([]) == []
- assert extract_names(all_matches(RL, is_Peruvian)) == []
- assert extract_names(all_matches(RL, is_French)) == ['Taillevent', "La Tour D'Argent", 'Pascal']
- ## Now let's extract (name, phone) tuples
- def extract_names_and_phones(L: 'list of Restaurant') -> 'list of (name,phone) tuples':
- ''' Return a list of tuples containing the name and phone of each restaurant in L '''
- result = []
- for R in L:
- result.append((R.name, R.phone))
- return result
- assert extract_names_and_phones([]) == []
- assert extract_names_and_phones(all_matches(RL, is_Peruvian)) == []
- assert extract_names_and_phones(all_matches(RL, is_French)) == \
- [('Taillevent', '343-3434'),
- ("La Tour D'Argent", '343-3344'),
- ('Pascal','333-4444')]
- def name_phone(R: Restaurant) -> '(name,phone) tuple':
- ''' Return a tuple (name, phone) from R '''
- return (R.name, R.phone)
- def transform_each(L: 'list of Restaurant', op: 'func Restaurant -> X') -> 'list of X':
- ''' Return a list of items produced by applying op to each iteim in L'''
- result = []
- for R in L:
- result.append(op(R))
- return result
- assert transform_each(all_matches(RL, is_French), name_phone) == \
- [('Taillevent', '343-3434'),
- ("La Tour D'Argent", '343-3344'),
- ('Pascal','333-4444')]
- """
- The all_matches() function does FILTERING
- The transform_each() function does MAPPING
- In fact, Python gives us a predefined function filter()
- and one called map() to perform these tasks. (They return
- special objects that we can turn into lists, as we did with
- the dict methods keys(), values(), and items().)
- """
- print('Cheap restaurants:', list(filter(is_cheap, RL)))
- print('Names and phones of cheap restaurants:',
- list(map(name_phone,list(filter(is_cheap, RL)))))
- # Filter (select) the cheap restaurants, then transform each into a name-phone tuple
- """
- What lets us do this is that Python treats functions as data/objects,
- passing them to other functions.
- We call this using HIGHER-ORDER FUNCTIONS, functions that take or return other functions.
- We say that functions are FIRST-CLASS OBJECTS in Python.
- We've had to define a lot of little functions to use just once (is_cheap, is_French, ...).
- Wouldn't it be nice to define these little fuctions on the fly,
- right where we need them, instead of doing the whole 'def' thing?
- We can say
- x = 2 + 2
- print(x)
- but if we're never going to use x again, we can also say
- print(2+2)
- We can do this same thing with functions.
- We do it using LAMBDA EXPRESSIONS. The value of a lambda expression is a function.
- [Lambda is a letter in the Greek allphabet. It's here because a branch
- of mathematical logic called the "lambda calculus" operates on functions.
- The lambda calculus was invented by Alonzo Church. The first programming
- language to use lambda expressions was LISP, invented by John McCarthy in
- 1958. Current dialects of LISP are Racket, Scheme, and Common Lisp.
- """
- def double0(n: int) -> int:
- return 2 * n
- # Defines the name double0 to mean 'a function that returns 2 * its int argument'
- # The following is exactly equivalent for the name double:
- double = lambda n: n*2
- print(double0(13))
- print(double(13))
- print((lambda n: 2*n)(17))
- """
- The value of (lambda n: 2*n) is "a function that returns 2 * its argument"
- The value of double is "a function that returns 2 * its argument"
- The value of double0 is "a function that returns 2 * its argument"
- They're interchangeable.
- """
- Ethiopian_rests = all_matches(RL, lambda R: R.cuisine=='Ethiopian')
- print(Ethiopian_rests)
- # We don't need to define is_Ethiopian if we want to describe its
- # operation just here in this one place.
- # We call this "using ANONYMOUS LAMBDA", a lambda expression without a name.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement