My Finished The Boredless Tourist Project

Hey! I just completed the Python project, The Boredless Tourist! I elaborated on the code after I finished it, so I thought I’d show you! (I may have gone a smidge overboard, but I had such fun!) Here it is:

destinations = ["Paris, France", "Shanghai, China", "Los Angeles, USA", "São Paulo, Brazil", "Cairo, Egypt", "London, England", "Cardiff, Wales", "Tokyo, Japan", "San Juan, Puerto Rico"]

def get_destination_index(destination):
  destination_index = destinations.index(destination)
  return destination_index

def get_traveller_location(traveller):
  traveller_destination = traveller[1]
  traveller_destination_index = get_destination_index(traveller_destination)
  return traveller_destination_index

attractions = [[], [], [], [], [], [], [], [], []]

def add_attraction(destination, attraction):
  destination_index = get_destination_index(destination)
  try:
    attractions_for_destination = attractions[destination_index]
    attractions_for_destination.append(attraction)
    return attractions_for_destination
  except ValueError:
    return

add_attraction("Los Angeles, USA", ["Venice Beach", ["beach"]])
add_attraction("Paris, France", ["the Louvre", ["art", "museum"]])
add_attraction("Paris, France", ["Arc de Triomphe", ["history", "monument"]])
add_attraction("Shanghai, China", ["Yu Garden", ["garden", "history"]])
add_attraction("Shanghai, China", ["Yuz Museum", ["art", "museum"]])
add_attraction("Shanghai, China", ["Oriental Pearl Tower", ["skyscraper", "viewing deck"]])
add_attraction("Los Angeles, USA", ["LACMA", ["art", "museum"]])
add_attraction("São Paulo, Brazil", ["São Paulo Zoo", ["zoo"]])
add_attraction("São Paulo, Brazil", ["Pátio do Colégio", ["history"]])
add_attraction("Cairo, Egypt", ["Pyramids of Giza", ["monument", "history"]])
add_attraction("Cairo, Egypt", ["Egyptian Museum", ["museum"]])
add_attraction("London, England", ["Science Museum", ["science", "museum"]])
add_attraction("London, England", ["Big Ben", ["clock tower", "history"]])
add_attraction("London, England", ["Shard", ["skyscraper", "viewing deck"]])
add_attraction("London, England", ["London Eye", ["observation wheel"]])
add_attraction("London, England", ["Victoria and Albert Museum", ["art", "museum"]])
add_attraction("London, England", ["Tower of London", ["history"]])
add_attraction("London, England", ["Sherlock Holmes Museum", ["museum", "literature"]])
add_attraction("London, England", ["Westminster Abbey", ["church", "history"]])
add_attraction("London, England", ["National Theatre", ["theatre"]])
add_attraction("London, England", ["Harrod's", ["department store"]])
add_attraction("London, England", ["Selfridges", ["department store"]])
add_attraction("London, England", ["St. Paul's Cathedral", ["church", "history"]])
add_attraction("London, England", ["Tate Modern", ["art", "museum"]])
add_attraction("London, England", ["Tate Britain", ["art", "museum"]])
add_attraction("London, England", ["National Gallery", ["art", "museum"]])
add_attraction("London, England", ["Greenwich Royal Observatory", ["science", "observatory"]])
add_attraction("London, England", ["British Museum", ["museum", "history"]])
add_attraction("London, England", ["Kensington Palace", ["palace", "history"]])
add_attraction("London, England", ["Hyde Park", ["park", "garden"]])
add_attraction("London, England", ["Churchill War Rooms", ["history"]])
add_attraction("London, England", ["Globe Theatre", ["theatre", "history"]])
add_attraction("London, England", ["West End", ["theatre"]])
add_attraction("London, England", ["Warner Bros. Studio Tour", ["cinema"]])
add_attraction("Los Angeles, USA", ["Griffith Observatory", ["science", "observatory"]])
add_attraction("Los Angeles, USA", ["Huntington Library, Art Collections, and Botanical Gardens", ["literature", "art", "garden"]])
add_attraction("Los Angeles, USA", ["Walt Disney Concert Hall", ["theatre", "garden"]])
add_attraction("Los Angeles, USA", ["Hollywood Walk of Fame", ["cinema"]])
add_attraction("Los Angeles, USA", ["Grauman's Chinese Theatre", ["cinema"]])
add_attraction("Paris, France", ["Eiffel Tower", ["viewing deck"]])
add_attraction("Paris, France", ["Notre Dame Cathedral", ["church", "literature", "history"]])
add_attraction("Paris, France", ["Musée d'Orsay", ["art", "museum"]])
add_attraction("Paris, France", ["Luxembourg Gardens", ["garden"]])
add_attraction("Shanghai, China", ["Shanghai Science and Technology Museum", ["science", "museum"]])
add_attraction("Shanghai, China", ["Shanghai Museum", ["art", "museum"]])
add_attraction("São Paulo, Brazil", ["Museu de Arte", ["art", "museum"]])
add_attraction("São Paulo, Brazil", ["Teatro Municipal", ["theatre"]])
add_attraction("São Paulo, Brazil", ["Ibirapuera Park", ["garden", "park"]])
add_attraction("Cairo, Egypt", ["Museum of Islamic Art", ["art", "museum"]])
add_attraction("Cairo, Egypt", ["Bab Zuweila", ["history", "viewing deck"]])
add_attraction("Cairo, Egypt", ["Manial Palace", ["palace", "museum", "art", "history"]])
add_attraction("Cardiff, Wales", ["Wales Millenium Centre", ["theatre"]])
add_attraction("Cardiff, Wales", ["National Museum Cardiff", ["history", "museum"]])
add_attraction("Cardiff, Wales", ["Roath Lock", ["TV studio"]])
add_attraction("Cardiff, Wales", ["Cardiff Castle", ["castle", "history"]])
add_attraction("Cardiff, Wales", ["Techniquest", ["science", "museum"]])
add_attraction("Tokyo, Japan", ["Imperial Palace", ["palace", "history"]])
add_attraction("Tokyo, Japan", ["Edo Castle", ["castle", "history"]])
add_attraction("Tokyo, Japan", ["National Museum of Nature and Science", ["science", "museum"]])
add_attraction("Tokyo, Japan", ["Ueno Park and Zoo", ["park", "zoo", "aquarium", "museum"]])
add_attraction("Tokyo, Japan", ["National Art Centre", ["art", "museum"]])
add_attraction("Tokyo, Japan", ["Science Museum", ["science", "museum"]])
add_attraction("San Juan, Puerto Rico", ["Ocean Park", ["beach"]])
add_attraction("San Juan, Puerto Rico", ["Museum of Puerto Rican Art", ["art", "museum", "theatre", "garden"]])
add_attraction("San Juan, Puerto Rico", ["Casa Blanca", ["history", "museum"]])
add_attraction("San Juan, Puerto Rico", ["Iglesia de San José", ["church", "history"]])

def find_attractions(destination, interests):
  destination_index = get_destination_index(destination)
  attractions_in_city = attractions[destination_index]
  attractions_with_interest = []
  for attraction in attractions_in_city:
    possible_attraction = attraction
    attraction_tags = attraction[1]
    for interest in interests:
      if interest in attraction_tags:
        attractions_with_interest.append(possible_attraction[0])
  return attractions_with_interest

la_arts = find_attractions("Los Angeles, USA", ["art"])

def get_attractions_for_traveller(traveller):
  traveller_destination = traveller[1]
  traveller_interests = traveller[2]
  traveller_attractions = find_attractions(traveller_destination, traveller_interests)
  interests_string = "Hi " + traveller[0] + ", we think you'll like these places around " + traveller_destination + ": "
  for i in range(len(traveller_attractions)):
    if traveller_attractions[-1] == traveller_attractions[i]:
      interests_string += "the " + traveller_attractions[i] + "."
    else:
      interests_string += "the " + traveller_attractions[i] + ", "
  return interests_string

travellers = [["Doctor", "Cardiff, Wales", ["musem"]], ["Matilda Wormwood", "London, England", ["literature"]], ["Fenton Crackshell-Cabrera", "Tokyo, Japan", ["science"]], ["Varian", "London", ["science"]], ["José Carioca", "São Paulo, Brazil", ["theatre", "museum"]], ["Scrooge McDuck", "Cairo, Egypt", ["history"]], ["Romana", "Paris, France", ["art"]], ["Rapunzel", "Shanghai, China", ["art"]], ["Amy Pond", "Los Angeles, USA", ["cinema"]], ["Mateo", "San Juan, Puerto Rico", ["history", "science"]]]
for traveller in travellers:
  print(traveller)
  print("\n")
    for interest in interests:
      if interest in attraction_tags:
        attractions_with_interest.append(possible_attraction[0])

you’d be adding the same attraction multiple times if there are multiple matching interests


this is super shady:

attractions = [[], [], [], [], [], [], [], [], []]

maybe you’d like to use a dict instead.


  except ValueError:
    return

you could potentially hide problems with that. maybe test for membership instead?


  destination_index = destinations.index(destination)
  return destination_index

don’t need a variable if you’re going to use it once

Oh, I noticed the first issue when I initially tried adding travellers with too many interests, like science, history, and museums.

You think the attractions = [[], [], [], [], [], [], [], [], []] line isn’t written very well? The lesson said it was a possible way of writing it.

Is the try…except code block to solve the first problem or the second problem?

I could have sworn the lesson recommended the destination_index variable too, though I could be wrong… What do you suggest instead?

Regardless of what’s said there, I disagree with it.

Then, this thing:

the_Doctor = get_attractions_for_traveller(
    ["Doctor", "Cardiff, Wales", ["museum"]]
)
print(the_Doctor)
print("\n")
matilda = get_attractions_for_traveller(
    ["Matilda Wormwood", "London, England", ["literature"]]
)
print(matilda)
print("\n")
fenton = get_attractions_for_traveller(
    ["Fenton Crackshell-Cabrera", "Tokyo, Japan", ["science"]]
)
print(fenton)
print("\n")
varian = get_attractions_for_traveller(
    ["Varian", "London, England", ["science"]]
)
print(varian)
print("\n")
josé = get_attractions_for_traveller(
    ["José Carioca", "São Paulo, Brazil", ["theatre", "museum"]]
)
print(josé)
print("\n")
scrooge = get_attractions_for_traveller(
    ["Scrooge McDuck", "Cairo, Egypt", ["history"]]
)
print(scrooge)
print("\n")
romana = get_attractions_for_traveller(["Romana", "Paris, France", ["art"]])
print(romana)
print("\n")
rapunzel = get_attractions_for_traveller(
    ["Rapunzel", "Shanghai, China", ["art"]]
)
print(rapunzel)
print("\n")
amelia_pond = get_attractions_for_traveller(
    ["Amy Pond", "Los Angeles, USA", ["cinema"]]
)
print(amelia_pond)
print("\n")
mateo = get_attractions_for_traveller(
    ["Mateo", "San Juan, Puerto Rico", ["history", "science"]]
)
print(mateo)

There’s a lot of repeated code in that, what’s unique is this:

["Doctor", "Cardiff, Wales", ["museum"]]
["Matilda Wormwood", "London, England", ["literature"]]
["Fenton Crackshell-Cabrera", "Tokyo, Japan", ["science"]]
["Varian", "London, England", ["science"]]
["José Carioca", "São Paulo, Brazil", ["theatre", "museum"]]
["Scrooge McDuck", "Cairo, Egypt", ["history"]]
["Romana", "Paris, France", ["art"]]
["Rapunzel", "Shanghai, China", ["art"]]
["Amy Pond", "Los Angeles, USA", ["cinema"]]
["Mateo", "San Juan, Puerto Rico", ["history", "science"]]

the repeated things can be done in a loop

I can create all these distinct travellers with a loop!? Pray tell.

well no. you’d put them in a list.
you’re doing something for each of them so

loop people:
   do thing
1 Like

How do I handle this issue?

Do you agree that this is a lookup table from country to locations?
And, a dict is a lookup table. so. yeah.

I last learned dicts in Python 2. Is the Python 3 syntax for them different?

Adding the location is something you want to do once.
Something you do once doesn’t go into a loop.

… pretty much, right? and then you can do that in a handful of different ways.

is there a matching interest? then add it. there’s a condition which involves iteration.

I’d want that function to read like this:

def find_attractions(destination, interests):
    interests = set(interests)
    return [a for a in attractions.get(destination, []) if set(a.tags) & interests]

& for set is intersection (determines what both have in common), if that turns out empty the condition isn’t met (empty is considered falsy, while non-empty is truthy)

I’m treating attractions as if it’s a dict.

having tags at index 1 is … ?? you could create a data type for it that has named attributes.

you can create such a data type like this:

from collections import namedtuple

Attraction = namedtuple('Attraction', ['name', 'tags'])
home = Attraction('home', ['tv', 'bed'])
print(home.name)
print(home.tags)
print(home)

It’s just a box with two named fields that you can fill in. Nicer than a list for bundling things up.


What that function does, its purpose, is to start out with some collection, and filter out non-interesting things.
If everything’s in suitable data structures then those operations become much simpler and brief

1 Like

I have just added your suggestion about making a travellers list!

Whereabouts in the program should my new Attraction tuple go?

It’s not a tuple. It’s a type. You’d use it instead of list for the attractions.

So it would replace attractions = [[], [], [], [], [], [], [], [], []]?

No that’d become

attractions = {}

and your get-index function would be removed

you would add these things to attractions:

{ "France": [Attraction("something", ["stuff", "bagels?"])]
}

which your add_attractions function is responsible for, so it would now look up the country, create an Attraction, add that Attraction to the list for that country

You could use defaultdict to make attractions default to empty list:

from collections import defaultdict
attractions = defaultdict(list)

or simply add an entry if it’s missing as needed

alongside Attraction you might want a Traveler type to represent them.

I presume the code here is a sample, as “tv” and “bed” aren’t relavant values. How do I incorporate the values I need, the name of the location, the name of the attraction, and the interests it suits? Strings probably wouldn’t work, since different locations have different values, so what do you propose? Should I declare some variables? Or are these merely the parameters for every time I call Attraction afterward, like in the second line of your code onward?

You’re already using strings, there’s no difference.

Functionally, there’s no difference.
At the moment you are representing an Attraction or Traveler as a list. You have to access their info by index, which is awkward. If you use namedtuple you can instead access those fields by name.

The sample code there shows all the operations for namedtuple you’d need - creating one, instantiating one, accessing fields

the data inside remains the same as you already put in lists

you go from this:

["Doctor", "Cardiff, Wales", ["museum"]]

to this:

Traveler("Doctor", "Cardiff, Wales", ["museum"])

and from this:

traveler[1]

to this:

traveler.destination

the ONLY thing it does is get rid of this:

[1]

but it’s quite horrible so, yes. it should be done

You have code like this:

    traveller_destination = traveller[1]
    traveller_interests = traveller[2]

which means you already think it’s a problem. you would instead use this directly:

traveler.destination
traveler.interests

so those two lines go poof by having a better representation

Do I still need the add_attractions function, should I just type the attractions inside the attractions dict, or is there a third alternative? Adding the attractions using the function takes such a lot of code, is there any way I could use a loop? Even adding them as part of the dict to begin with would save some characters.

If the attractions are to be hard-coded, then yeah, define it as a data structure directly instead.
However, a case can be made for having the capability to add attractions as part of the program. If you’re editing code you may as well edit the data structure, no point not to. But you could for example have them in a file and add each entry in the file, and for that you would need a capability to add.