inspectorG4dget
inspectorG4dget

Reputation: 114005

Variables inside a function not recreated at each function call

I was answering this question, to which my solution was the following (I didn't post this answer):

def wordigit(w):
    digits = {}
    c = itertools.count(1)
    for char in w:
        if w not in digits:
            digits[char] = c.next()
    return ''.join(str(i) for i in (digits[char] for char in w))

print ' '.join(wordigit(w) for w in s.split())

At first glance, this looks right. But I got an erroneous result:

In [236]: ' '.join(wordigit(w) for w in s.split())
Out[236]: '12345 14345 33345' # notice the numbers in the second "word". 1-4 is not a legal progression for itertools.count. It should have been 12324 instead of 14345

I had developed this solution in IPython. Thinking that this might be a bug with some optimization that IPython does under the hood, I fired up a python interpreter to see what it said. I also thought that the list-comprehension might be leading to some anomalous behaviour. So I tried calling wordigit twice - once on each of two unequal strings and got the following results:

>>> def wordigit(w):
...     digits = {}
...     c = itertools.count(1)
...     for char in w:
...         if w not in digits:
...             digits[char] = c.next()
...     return ''.join(str(i) for i in (digits[char] for char in w))
... 
>>> wordigit('areyo')
'12345'
>>> wordigit('uanap')
'14345'

So it seems that even though I create the itertools.count object within the function (and therefore the function should recreate it at every run), it somehow persists after the function has returned and gets reused without re-initialization when the function is called again. Similarly, It is clear that this is the case for the dict "digits" in wordigit as well.

How is this happening? Somehow, this behavior doesn't make sense to me.

I notice this behavior with Python 2.7.1 in Ipython and a fresh Python 2.7.3 interpreter

Upvotes: 1

Views: 94

Answers (1)

Jon Clements
Jon Clements

Reputation: 142176

This doesn't look right:

for char in w:
    if w not in digits:
      ^^^

Maybe:

for char in w:
    if char not in digits: 
       ^^^^

Upvotes: 4

Related Questions