The Boredless Tourist


above is captured image of code. below is the code
I encountered error when solving ‘the boredless tourist’ challenge. The console says the error is ‘IndexError: list index out of range.’ I am trying to grasp what that means in this situation.
I have a general idea of ‘list index out of range’ error. I have read some articles about it . But this time the problem does not seem related to those on the internet. Could someone clarify what my error in the coding is and explain it to me in relation to the ‘list index out of range’ error? I wish to be able to solve it myself in the future just by looking at the error message.

destinations = ["Paris, France", 
"Shanghai, China", "Los Angeles, USA", "Sao Paulo, Brazil", "Cairo, Egypt"]

test_traveler = ['Erin Wilkes', 'Shanghai, China', ['historical site', 'art']]

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

#traveler current destination
def get_traveler_location(traveler):
  traveler_destination = traveler[1]
  traveler_destination_index = get_destination_index(traveler_destination)
  return traveler_destination_index

#finding traveler current destination index
test_destination_index = get_traveler_location(test_traveler)

attractions = [[] for destination in destinations]

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

add_attraction("Los Angeles, USA", ['venice Beach' , ['beach']]) 

print(attractions)

You must select a tag to post in this category. Please find the tag relating to the section of the course you are on E.g. loops, learn-compatibility

When you ask a question, don’t forget to include a link to the exercise or project you’re dealing with!

If you want to have the best chances of getting a useful answer quickly, make sure you follow our guidelines about how to ask a good question. That way you’ll be helping everyone – helping people to answer your question and helping others who are stuck to find the question and answer! :slight_smile:

I have found the solution for the problem myself, I put ‘attraction[destination_index]’ when right form is ‘attractions[destination_index].’ But I still wonder, how could ‘IndexError: list index out of range’ occur? What is the relation of that error with the trouble I had?
Also, at the end of the function ‘def add_attraction(destination, attraction)’, ‘return’ alone is written not specifying what value it is returning. But it still returns the value stored in variable ‘attractions_for_destination.’ How could this be?
To put it differently, how I understand is ‘attractions_for_destination = attractions[destination_index]’ this code stores the value of ‘attractions[destination_index]’ in the newly made ‘attractions_for_destination’ variable. And 'attractions_for_destination.append(attraction) ’ this code adds a change to the newly made
variable. But in the end what is changed is ‘attractions’ variable.
In short, changes are added to ‘attractions_for_destination’ but I don’t understand how ‘attractions’ are also changed.
In all, I am asking two questions in one post.

1 Like

Glad to see you found and fixed your own problem. :+1: Debugging can be a tricky thing at times, but it’s something anyone who wants to code needs to master. :slight_smile:

The Traceback is showing you where your error is occuring: in your add_attraction function.

Inside that function, the only line which relies on an index is this one:

attractions_for_destination = attraction[destination_index]

If we take a look at your function definition, we can see that attraction is a parameter. When we later call the function, we’re doing this:

add_attraction("Los Angeles, USA", ["venice beach", ["beach"]])

We can see that our destination parameter is being given the value "Los Angeles, USA", and our attraction parameter a list value of ["venice beach", ["beach"]].

If we double back, inside the function we know we’re going to try this:

attractions_for_destination = attraction[destination_index]

destination_index gets the index for the destination, based on it’s position in our destinations list on the first line. For Los Angeles, USA, which is third in our list, destination_index = 2.

As a result, we then try to access the third location (index 2) of our attraction list:

attraction = ["venice beach", ["beach"]]

The problem with this is that attraction contains only two items: a string in the first position, and a list object in the second. There is no third object - nothing at index 2 - so Python correctly returns an IndexError.


It’s because your return statement is not the one doing the work in this case.

Your attractions variable is in the global scope of your program - meaning you can access it from anywhere, including inside functions.

Inside your add_attractions function, we (should) have these two lines (now you’ve found and fixed your issue):

  attractions_for_destination = attractions[destination_index]
  attractions_for_destination.append(attraction)

The first line retrieves the list object from the appropriate index of the attractions list, so attractions_for_destination contains the list object from that index.

What is important is that we are not creating a copy of the list. What we are doing is getting the reference to the list - that is, the unique identifier which Python uses to say “this is the object X” - and storing it in the variable attractions_for_destination.

At this point, continuing with our destination being LA, both attractions_for_destination and attractions[2] (the 2 coming from LA’s “destination index”, remember) refer to the same list in memory.

As a result, the add_attraction function doesn’t need to return anything because it has already appended the relevant attraction to the globally-scoped attractions list.

I’ve added two if branches to your code, below, to illustrate this:

destinations = ["Paris, France", 
"Shanghai, China", "Los Angeles, USA", "Sao Paulo, Brazil", "Cairo, Egypt"]

test_traveler = ['Erin Wilkes', 'Shanghai, China', ['historical site', 'art']]

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

#traveler current destination
def get_traveler_location(traveler):
  traveler_destination = traveler[1]
  traveler_destination_index = get_destination_index(traveler_destination)
  return traveler_destination_index

#finding traveler current destination index
test_destination_index = get_traveler_location(test_traveler)

attractions = [[] for destination in destinations]

def add_attraction(destination, attraction):
  try:
    destination_index = get_destination_index(destination)
  except ValueError:
    return 
  attractions_for_destination = attractions[destination_index]
  # Let's test whether they are the same
  if attractions_for_destination is attractions[destination_index]:
      print("Same object")
  else:
      print("Different object")
  attractions_for_destination.append(attraction)
  return

add_attraction("Los Angeles, USA", ['venice Beach' , ['beach']]) 

print(attractions)

# Let's test again whether these two list objects, with the same
# value, are the same object
if [] is []:
    print("Same object")
else:
    print("Different object")

The output I get?

Same object
[[], [], [['venice Beach', ['beach']]], [], []]
Different object
2 Likes

Since you mentioned pass by reference I looked it up on the internet. And I started to form a general idea of it.

How I understand it is, when ‘=’ is used, a newly made variable that is in front of ‘=’ sign references to the same memory as the variable behind ‘=’ sign. In short, they share the same memory. So when the value in the memory is altered through whichever variable, both variables bring the altered value when called.

Then I have another question, when is it that a new memory space is decided to be used in contrast to when simply an address is passed?
My intuition says a new memory space starts to be used when the value is altered. Like if I draw an example from my coding,

attractions_for_destination = attractions[destination_index]

above is passing an address, but if I add a change like,

attractions_for_destination = attractions[destination_index] + “the best attraction site”

I wonder if this forces variable ‘attractions_for_destination’ to create a new memory space.