0

I wrote this function to read a list of words representing a number and pair 1-9 digits with multipliers.

def listpairs(element):
    pair = []
    for word in enumerate(element):
        pair.append(word[1])
        if word[1] in denoms:
            yield pair
            pair.clear()
        if word[1] in digits and word[0] == (len(element)-1):
            yield pair

When I try it with a test string, it gives this:

list(listpairs('two hundred three ten four'.split())
[['four'], ['four'], ['four']]

If I replace yield with print(pair), it gives the expected output:

['two', 'hundred']
['three', 'ten']
['four']

Why does this happen? Is yield the wrong tool here?

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
cmo
  • 3
  • 2

1 Answers1

1

Solution

Your are yielding the same list all the time. Replace:

pair.clear()

with:

pair = []

To get new list.

Example:

from string import digits
denoms = ['hundred', 'ten']

def listpairs(element):
    pair = []
    for word in enumerate(element):
        pair.append(word[1])
        if word[1] in denoms:
            yield pair
            pair.clear()
        if word[1] in digits and word[0] == (len(element)-1):
            yield pair

list(listpairs('two hundred three ten four'.split()))

Gives:

[['four'], ['four']]

But:

from string import digits

denoms = ['hundred', 'ten']

​

def listpairs(element):
    pair = []
    for word in enumerate(element):
        pair.append(word[1])
        if word[1] in denoms:
            yield pair
            pair = []
        if word[1] in digits and word[0] == (len(element)-1):
            yield pair


list(listpairs('two hundred three ten four'.split()))

Results int:

[['two', 'hundred'], ['three', 'ten']]

Explanation

While mylist.clear() removes all content form a list, it is still the same list. Yielding the same list results in having the same list multiple times in your output. On the other hand, the assignment mylist = [] creates a new list, reusing the name mylist. Reusing the name here is fine because you yield the list, i.e. it will be outside of the function.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
  • Thank you! I thought list.clear() was the same thing as list = []. The function works now. I still don't understand why the same object was treated differently by print and yield, though. – cmo Jun 27 '16 at 19:06
  • 1
    @cmo lists can change, doing `x = [] ; print(x) ; x.append(4) ; print(x)` will print the same list at two different times when it contains different values, if you want to be guaranteed to have immutable results then do `yield tuple(pair)` so that it creates a new `tuple` with the data at the time and then you are free to modify `pair` again as you are. – Tadhg McDonald-Jensen Jun 27 '16 at 19:12