0

Below I have a text file with a list of guests and a generator function. I'm trying to add another guest using the .send() method to a generator. However, when I attempt to send "Jane, 35" it doesn't show up when I print. Also, when I print, the first 2 names that were originally in the guest_list.txt file do not show when printed. Why is this?

#guest_list.txt
   
    Tim,22
    Tonya,45
    Mary,12
    Ann,32
    Beth,20
    Sam,5
    Manny,76
    Kenton,15
    Kenny,27
    Dixie,46
    Mallory,32
    Julian,4
    Edward,71
    Rose,65




#generator_function
    guests = {}
    def read_guestlist(file_name):
        text_file = open(file_name,'r')
        while True:
            line_data = text_file.readline().strip().split(",")
            if len(line_data) < 2:
            # If no more lines, close file
                text_file.close()
                break
            name = line_data[0]
            age = int(line_data[1])
            
            guests[name] = age
            variable = yield name, age
            
    
    variable = read_guestlist('guest_list.txt')
    
    variable.send(None)
    variable.send("Jane, 35")
    for i in range (16):
     print(next(variable))
    
    ('Mary', 12)
    ('Ann', 32)
    ('Beth', 20)
    ('Sam', 5)
    ('Manny', 76)
    ('Kenton', 15)
    ('Kenny', 27)
    ('Dixie', 46)
    ('Mallory', 32)
    ('Julian', 4)
    ('Edward', 71)
    ('Rose', 65)
    Traceback (most recent call last):
      File "script.py", line 22, in <module>
        print(next(variable))
    StopIteration
Blenderinho
  • 103
  • 4
  • what is the point of adding to a dictionary and also `yield`ing the result? just iterate over the dictionary (you can also add the new entries to that dictionary) – Matiiss Oct 15 '21 at 11:28
  • The dictionary is required for another part of the project, this question is just one part of the project – Blenderinho Oct 15 '21 at 11:42
  • I think 'None' & "Jane, 35" are somehow replacing the original 2 names on the `guest_list.txt` file but not appearing when I print because I'm not handling the newly sent values correctly? – Blenderinho Oct 15 '21 at 11:44
  • Does this answer your question? [python generator "send" function purpose?](https://stackoverflow.com/questions/19302530/python-generator-send-function-purpose) – Matiiss Oct 15 '21 at 11:58

1 Answers1

0

I struggled for days with this question, which is part of a course project. In the question, you are asked to create a generator and to use 'send', hence using 'yield'. As Blenderinho says, the dictionary relates to another question in the project.

Someone very kindly gave me their solution to the whole project - which worked! - and I think I maybe now understand 'send' and 'yield' a bit better. I thought the best way to test my own understanding is to attempt an explanation of 'send' and 'yield' - below is my attempt. The code below is pared down to the minimum to try to make it clear what they do.

Input:

def addPerson():
    while True:
        newName = yield
        yield newName
            
g=addPerson()


print(next(g)) #1
print(g.send('Jane, 35')) #2
print(next(g)) #3
print(g.send('Liz, 50')) #4
print(next(g)) #5

Output:

None #1
Jane, 35 #2
None #3
Liz, 50 #4
None #5

#1 The value of 'next(g)' here is 'None' and the generator regards this as the current value of 'yield'. So, because newName is assigned yield's value via the line, 'newName = yield', the value of newName is now 'None'. The generator then reaches the line, 'yield newName'. Since the current value of newName is 'None', it yields 'None' and 'None' is the output.

#2 The value, 'Jane, 35' is 'sent' to the generator. This value becomes the value of 'yield'. So, because newName is assigned yield's value via the line, 'newName = yield', the value of newName is now 'Jane, 35'. The generator then reaches the line, 'yield newName'. Since the current value of newName is 'Jane, 35', it yields 'Jane, 35' and 'Jane, 35' is the output.

#3 The value of 'next(g)' is None so step 1 is repeated.

#4 The value, 'Liz, 50' is sent to the generator so step 2 is repeated, but this time with the value 'Liz, 50' instead of the value, 'Jane, 35'.

#5 The value of 'next(g)' is None so step 1 is repeated.

After this, there are no further next(g) or send lines, so the 'while True' loop terminates.

So, in summary:

The first mention of 'yield' - in this case in the line, 'newName = yield' - assigns to 'yield' the value of the 'next(g)' or the value of 'send' that is currently going through the while True loop.

The value of yield, in turn, can then be assigned to another variable eg newName. Here, this is done in the same line, 'newName = yield'.

The output of the current loop is the value of 'yield' at the point the generator reaches the line 'yield [variable]', here 'yield newName'. Once it has reached the line 'yield [variable]' line the current loop terminates.

You can't 'send' before at least one 'next(g)' has gone through the generator. This is because 'send' replaces the existing yield with 'its' value. If there is no existing yield to replace because nothing has yet been 'yielded', 'send' cannot work.

If the generator has been passed something with a finite number of values, such as a list or dictionary, as in:

def addPerson(list):

and g=addPerson(list)

each item in the list or whatever passed to the generator is assigned as the value of 'yield'. When all the items have been processed by the generator, there are no more values assigned to 'yield', 'while True' no longer holds, and stopIteration is raised. So 'while True' holds only while values are being assigned to yield.

okfar
  • 1
  • 2