Blossom Project

An __iter__ method, if defined, conveys to the Python interpreter how to iterate through an instance of the class that contains that method. Here’s that method for the LinkedList class:

  def __iter__(self):
    current_node = self.head_node
    while(current_node):
      yield current_node.get_value()
      current_node = current_node.get_next_node()

With that method’s having been defined, the Python interpreter uses it to iterate through a LinkedList when we request that process via a for loop.

We start out with current_node referring to the head node. The for loop iterates as long as current_node has not yet become None. With each iteration, this yield statement hands out the value that is at current_node, which appears to us as the next item in the list:

      yield current_node.get_value()

Then we advance to the next Node in preparation for the next iteration:

      current_node = current_node.get_next_node()

That keeps happening until current_node gets to None, meaning we have reached the end of the LinkedList.

Edited on January 20, 2019 to add the following example:

Here is a basic example of how the potential for iteration can be included in a class:

class RocketLauncher:
    def __init__(self):
        self.count = 10
    def __iter__(self):
        while self.count > 0:
            # the next item
            yield "{:2d}!".format(self.count)
            self.count -= 1
        # the final item
        yield "Blast off!!!"

launcher = RocketLauncher()
for exclamation in launcher:
    print(exclamation)

Output:

10!
 9!
 8!
 7!
 6!
 5!
 4!
 3!
 2!
 1!
Blast off!!!
1 Like

Hi, thanks. By the way, how did you find it?

Find what exactly? This was a while ago, so you may need to fill me in a little about what you are asking.

Thanks for the helpful responses.

Any idea why

print(blossom.retrieve('morning glory'))

returns “None” in the following code?

from linked_list import Node, LinkedList
from blossom_lib import flower_definitions

class HashMap:
  
  def __init__(self, size):
    self.array_size = size
    self.array = [LinkedList() for number in range(size)]

  def hash(self, key):
    return sum(key.encode())
    
  def compress(self, hash_code):
    return hash_code % self.array_size

  def assign(self, key, value):
    array_index = self.compress(self.hash(key))
    payload = Node([key, value])
    #self.array[array_index] = [key, value]
    list_at_array = self.array[array_index]
    for item in list_at_array:
      if item[0] is key:
        item[1] = value
        return
    list_at_array.insert(payload)

  def retrieve(self, key):
    array_index = self.compress(self.hash(key))
    list_at_index = self.array[array_index]
    for item in list_at_index:
      if item[0] is key:
        return item[1]
    return None

blossom = HashMap(len(flower_definitions))
for flower in flower_definitions:
  blossom.assign(flower[0], flower[1])

print(blossom.retrieve('daisy'))
print(blossom.retrieve('rose'))
print(blossom.retrieve('sunflower'))
print(blossom.retrieve('wisteria'))
print(blossom.retrieve('morning glory'))
print(blossom.retrieve('periwinkle'))

Is 'morning glory' included within the flower_definitions object provided by the blossom_lib.py file?

Edited on April 11, 2020 to add the following:

If 'morning glory' is indeed there, then consider why the following occurred during an interactive Python session:

>>> x = 'morning glory'
>>> y = 'morning glory'
>>> x is y
False

@appylpye Hi Glenn, yes, ‘morning glory’ is in the flower_definitions object provided by the blossom_lib.py file:

flower_definitions = [['begonia', 'cautiousness'], ['chrysanthemum', 'cheerfulness'], ['carnation', 'memories'], ['daisy', 'innocence'], ['hyacinth', 'playfulness'], ['lavender', 'devotion'], ['magnolia', 'dignity'], ['morning glory', 'unrequited love'], ['periwinkle', 'new friendship'], ['poppy', 'rest'], ['rose', 'love'], ['snapdragon', 'grace'], ['sunflower', 'longevity'], ['wisteria', 'good luck']]

I figure that what you mean by the x = " " and y = " ", but x != y example is that the original variable is somehow overwritten. I can’t see this in the code. “morning glory” is only referred to in the flower_definitions object. Did I understand you correctly?

OK, that’s good. To prepare to investigate the issue, we have made sure that ‘morning glory’ had not been mistakenly removed from the file, which is the original source of the data.

Now, we can move on to check whether the assign and retrieve methods are working correctly. Having confirmed that ‘morning glory’ is in the data, we can refine and test those methods, using that data.

There is an important difference between the is and == operators.

  • is checks for identity. For a True result, the two operands must not only have the same value. They must, in fact, be the same object. Two different objects can have the same value.
  • == checks for equivalence. For a True result, the operands need to have the same value, but might not be the same object.

Here, we assigned the same values to x and y:

>>> x = 'morning glory'
>>> y = 'morning glory'

However it turned out that they were two different objects, so the is test that followed in the earlier post came out False. If we had used == instead, the test would have come out True. That, in fact, is the test that we need in the assign and retrieve methods.

In actuality, we really only care whether the objects are equivalent here, not whether they are identical:

      if item[0] is key:

Accordingly, we should change the above to the following in both methods:

      if item[0] == key:

This is a helpful explanation. Thanks!

The thing I don’t understand is that if the

if item[0] is key: 

is the issue, then why does the code still work for the other items on the list?

print(blossom.retrieve('daisy'))
print(blossom.retrieve('rose'))
print(blossom.retrieve('sunflower'))
print(blossom.retrieve('wisteria'))
print(blossom.retrieve('morning glory'))
print(blossom.retrieve('periwinkle'))

In this list, only “morning glory” returns None.

The Python interpreter often, but not always, optimizes code by creating only one copy of a simple string when a program or interactive session includes several simple string literals that contain the exact same sequence of characters. When that occurs, the strings will pass both the == test and the is test. Here’s an example in an interactive session:

>>> a = "rose"
>>> b = "rose"
>>> c = "rose"
>>> a == b
True
>>> a is b
True
>>> b == c
True
>>> b is c
True

However, the Python interpreter does not guarantee that it will adhere to that strategy concerning the is test. It does, however, guarantee that two strings with the exact same sequence of characters will pass the == test.

Let’s try another string here:

>>> a = "morning glory"
>>> b = "morning glory"
>>> c = "morning glory"
>>> a == b
True
>>> a is b
False
>>> b == c
True
>>> b is c
False

For "morning glory", the Python interpreter chose to create three different equivalent strings. That might be because it is more complicated than "rose" in that it contains a space.

In conclusion, when we are interested in whether two strings contain the same sequence of characters, we should use the == operator.

1 Like

@appylpye Glenn, great explanation. Thanks for taking the time to give such a clear and concise answer. I understand now.

1 Like

Hi,
I am just curious if there is any way to see the content of blossom library class and the flower definition module. I have just completed this project and I am typing some flowers which are returning None. I know I can assign them meaning myself, but I also want to see what flowers are in the library.
Thanks.

Hi @java7724370697,

Note that you probably have this near the beginning of your program:

from blossom_lib import flower_definitions

You can see the flowers that are available by adding this line:

print(flower_definitions)

Also note the little envelope icon near the upper left corner of the editor pane. Click on the icon to see a list of files, then click on the name of a file to see its contents.

2 posts were split to a new topic: Blossom Project: NameError

Hi, I still don’t understand why the code is returning None for some flowers…

from linked_list import Node, LinkedList
from blossom_lib import flower_definitions

class HashMap:
def init(self, size):
self.array_size = size
self.array = [LinkedList() for item in range(self.array_size)]

def hash(self, key):
return sum(key.encode())

def compress(self, hash_code):
return hash_code % self.array_size

def assign(self, key, value):
array_index = self.compress(self.hash(key))
payload = Node([key, value])
list_at_array = self.array[array_index]
for item in list_at_array:
# item[0] is the key and item[1] is the value
if item[0] == key:
item[1] = value
return
list_at_array.insert(payload)

def retrieve(self, key):
array_index = self.compress(self.hash(key))
list_at_index = self.array[array_index]
for item in list_at_index:
if item[0] == key:
return item[1]
return None

blossom = HashMap(len(flower_definitions))

for flower in flower_definitions:
blossom.assign(flower[0], flower[1])

print(blossom.retrieve(‘daisy’))
print(blossom.retrieve(‘rose’))
print(blossom.retrieve(‘wisteria’))
print(blossom.retrieve(‘morning glory’))
print(blossom.retrieve(‘lavender’))
print(blossom.retrieve(‘carnation’))
print(blossom.retrieve(‘magnolia’))
print(blossom.retrieve(‘sunflower’))
print(blossom.retrieve(‘periwinkle’))

# innocence
# None
# None
# None
# devotion
# memories
# dignity
# longevity
# new friendship

Welcome to the forums!

Please format your code according to the guidelines in the following topic. Indentation is important in Python and we need to see your indentation in order to tell what went wrong.

Thanks, Victoria. Here’s the formatted code:

from linked_list import Node, LinkedList
from blossom_lib import flower_definitions

class HashMap:
  def __init__(self, size):
    self.array_size = size
    self.array = [LinkedList() for item in range(self.array_size)]

  def hash(self, key):
    return sum(key.encode())
  
  def compress(self, hash_code):
    return hash_code % self.array_size

  def assign(self, key, value):
    array_index = self.compress(self.hash(key))
    payload = Node([key, value])
    list_at_array = self.array[array_index]
    for item in list_at_array:
      # item[0] is the key and item[1] is the value
      if item[0] == key:
        item[1] = value
        return
    list_at_array.insert(payload)
    
  def retrieve(self, key):
    array_index = self.compress(self.hash(key))
    list_at_index = self.array[array_index]
    for item in list_at_index:
      if item[0] == key:
        return item[1]
      return None

blossom = HashMap(len(flower_definitions))

for flower in flower_definitions:
  blossom.assign(flower[0], flower[1])```

print(blossom.retrieve('daisy'))
print(blossom.retrieve('rose'))
print(blossom.retrieve('wisteria'))
print(blossom.retrieve('morning glory'))
print(blossom.retrieve('lavender'))
print(blossom.retrieve('carnation'))
print(blossom.retrieve('magnolia'))
print(blossom.retrieve('sunflower'))
print(blossom.retrieve('periwinkle'))

# innocence
# None
# None
# None
# devotion
# memories
# dignity
# longevity
# new friendship

Take a look at your retrieve function, and more specifically, your for loop. We want to return the value of the corresponding key in the linked list if the key exists. Otherwise, we want to return None. Make sure you are checking all of the keys in the linked list against the key passed to the function as an argument.

Hint

Since a function will be exited after a return statement is executed, your for loop causes the function to either return the correct value if it belongs to the head node of the linked list, or None if the value does not belong to the head node. The loop doesn’t check if the other nodes in the linked list have the same key as the one passed to the function as an argument since return None will be executed on the first iteration of the loop if return item[1] is not.

1 Like

Thanks again @victoria_dr. I corrected the indentation again and now it prints the values correctly:

# innocence
# love
# good luck
# unrequited love
# devotion
# memories
# dignity
# longevity
# new friendship

1 Like

Hi there,

In this blossom project, the additional linked_list script has a iter method:

class LinkedList:
  def __init__(self, head_node=None):
    self.head_node = head_node
  
  def insert(self, new_node):
    current_node = self.head_node

    if not current_node:
      self.head_node = new_node

    while(current_node):
      next_node = current_node.get_next_node()
      if not next_node:
        current_node.set_next_node(new_node)
      current_node = next_node

  def __iter__(self):
    current_node = self.head_node
    while(current_node):
      yield current_node.get_value()
      current_node = current_node.get_next_node()

I have some difficulties to understand the why and when this method is use and also the yield keyword. I checked over the internet to get some info, but I don’t really understand this situation. Could someone give me some explanations please?

######################################################################
my bad, I found my answer in a previous post from @appylpye . Great explanation, thanks so much.
######################################################################

click on the folder icon on the top left corner where you write the code in codecademy