0

I was set a challenge after I told somebody I exported a dictionary to a database (simple python script to export the OPTED dictionary HTML pages into a database), it was to convert space-less Morse code into a word.

e.g. Normally messages would be: .- .--. .--. .-.. . (apple), with a space in between each character. But since there is a database to check every possibility against, the new input would be: .-.--..--..-... (apple), without the spaces in between.

I wrote a python script to do this, but I found a very odd phenomena, old values (which aren't stored in any variable) are coming up again.

Code is below:

import sqlite3
conn = sqlite3.connect('english_dictionary.db')
c = conn.cursor()

#Morse code alphabet
mc = {'.-' : 'a', '-...' : 'b', '-.-.' : 'c', '-..' : 'd', '.' : 'e', '..-.' : 'f', '--.' : 'g', '....' : 'h', '..' : 'i', '.---' : 'j', '-.-' : 'k', '.-..' : 'l', '--' : 'm', '-.' : 'n', '---' : 'o', '.--.' : 'p', '--.-' : 'q', '.-.' : 'r', '...' : 's', '-' : 't', '..-' : 'u', '...-' : 'v', '.--' : 'w', '-..-' : 'x', '-.--' : 'y', '--..' : 'z'}

#Recursive function - input, current words, current index, current_word
def magic(inp, curwords=[''], curindex=0, current_word=''):
    #print 'inp: "%s", curwords = %s, curindex = %i, current_word = "%s"' % (inp, str(curwords), curindex, current_word)
    #If the function is being called with an empty input, then this word has been finished, so set it up for a new one
    if inp == "":
        curwords.append('')
        curindex += 1
        return curwords,curindex
    #Finding valid Morse code letters
    for i in range(1, len(inp)+1):
        #print 'Current: %i in (1, %i)' % (i, len(inp)+1)
        if inp[:i] in mc:
            #print 'Morse Code: "%s" -> %s in (1, %i)' % (inp[:i],mc[inp[:i]], len(inp)+1)
            curwords[curindex] = current_word + mc[inp[:i]]
            curwords,curindex = magic(inp[i:], curwords, curindex, current_word + mc[inp[:i]])
        #else:
            #print 'Not Morse Code: "%s" in (1, %i)' % (inp[:i], len(inp)+1)
    return curwords,curindex

while 1:
    x = raw_input('> ')
    mag = magic(x)[0]
    for row in c.execute('SELECT DISTINCT word FROM dictionary WHERE LOWER(word) IN %s' % (str(tuple(mag)))):
        print row[0]

(Please ask if you want part of the code explained more in-depth)

The problem:

If I input ..- it returns It

If I input --. it returns Me

(Both of which are correct)

However if I do .-.--..--..-... it returns Apple (again, correct but here is where it breaks)

Now, if I do any morse code after I check Apple, then Apple is returned as a result.

e.g.

(Run these in order)

> ..- -> It

> --. -> Me

> .-.--..--..-... -> Apple

> ..- -> Apple, It

> --. -> Apple, Me

I made it output mag before the SQL statement, and it has all the possibilities that apple has + the possibilities of the new input (therefor its not caused by SQL).

I have tried adding mag = [] at the end of the while loop, and still doesn't work.

I had experienced odd behavior similar to this in a different language which was caused by modifying the value of arguments parsed into a function, so I tried copying the values to new variables, but to no avail.

lewisjb
  • 678
  • 10
  • 26
  • At a quick glance, `curwords=['']` looks dangerous to me. For more info, see: http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument – Kevin May 18 '15 at 03:45
  • @Kevin Thanks, that seems to be the problem, I'm looking further into it because from a preliminary check, there are inconsistencies (ie, only "apple" causes the problem, "it" and "me" don't 'stick around') – lewisjb May 18 '15 at 03:50

1 Answers1

0

Python default arguments are only evaluated once. When you append to a list that was a default argument (like curwords) the default argument will be changed in subsequent calls to the function.

If you want to get an empty list automatically whenever you call the function without supplying curwords, try something like:

def magic(curwords=None):
  if curwords is None: curwords = []
  # ...

For more information, refer to Default Argument Values in the Python language tutorial.

Will Angley
  • 1,392
  • 7
  • 11