V2. Interactive dictionary with inexact look ups (updated)
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
Recently I published a post in which three people made pretty good suggestions. I've learnt a lot since then thanks to them!
From among many things, they encouraged me to use classes. And that's cool because it is the first time I do object oriented programming... Even though the use I gave it was very basic.
Once again, I'd like to receive reviews of my new code. It's uploaded in GitHub, in case someone wants to check it out.
I'm building this dictionary on python, using data.json.
Any suggestions are warmly welcome! So, how can I improme my code?
import json, time, re
from difflib import get_close_matches
class fuzzydict(object):
def __init__(self, json_file):
self.file = json_file
self.data = json.load(open(json_file, 'r+'))
def find_word(self, word):
for version in [word.lower(), word.capitalize(), word.title(), word.upper()]:
if version in self.data:
return version
simils = get_close_matches(word, self.data, 1, 0.7)
if len(simils) > 0:
return simils[0]
else:
return None
def output_word(self, word):
# check if 'keyword' has no values (definitions)
if not self.data[word]:
print('"%s" is yet to be defined.' % word)
# print in a cool format
else:
print('÷ ' + word + ':')
# re.split('--|;', self.data[word]) in case the
# definitions were not given inside a list
for index, definition in enumerate(self.data[word]):
print(str(index + 1) + '.', definition)
def input_word(self, word, definition):
operation = 0
# this prevents the user from adding an already existing definition
if word in self.data and definition not in self.data[word]:
self.data[word] += [definition]
operation = 1
# in case it's a new word
elif word not in self.data:
self.data.update(word: [definition])
operation = 1
# updates the file when necessary
if operation:
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
return 'nOUPS! Apparently the definition you attempted to add already exists.'
def remove_word(self, word):
if word != None:
self.data.pop(word, None)
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
else:
return "nHmm... how can you remove something that doesn't exist? Huh!"
def remove_def(self, word, index):
for i, definition in enumerate(self.data[word]):
if i == int(index) - 1:
self.data[word].remove(definition)
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
return "nHmm... how can you remove something that doesn't exist? Huh!"
# new object
mydict = fuzzydict('data.json')
# can either access the data through 'archives' or 'mydict.data'
while True:
menu = input('nnn'
'0. Quitn'
'1. Searchn'
'2. Add word or definitionn'
'3. Remove wordn'
'4. Remove definitionnn'
' '
'What would you like to do? ')
# '0' to exit
if menu == '0':
break
# '1' to look up a word
elif menu == '1':
search = input('nType in a word: ')
if mydict.find_word(search) == None:
print('"' + search + '"' + " isn't available at the moment.")
yes = input('Would you like to add "' + search + '" to the dictionary? ')
if yes.lower() == 'yes':
meaning = input('Type in the meaning of ' + search + ', please: ')
while meaning == '':
meaning = input('Type in a valid definition, please:')
print(mydict.input_word(search, meaning))
else:
mydict.output_word(mydict.find_word(search))
# '2' to add or remove a new word or definition
elif menu == '2':
print('~ You are now editing the dictionary ~')
new_word = input('tWord: ')
new_def = input('tDefinition: ')
if mydict.find_word(new_word) == None:
print(mydict.input_word(new_word, new_def))
else:
print(mydict.input_word(mydict.find_word(new_word), new_def))
# '3' to remove an existing word
elif menu == '3':
print('~ You are now editing the dictionary ~')
rm_word = input('tType in the word you want to remove from the dictionary: ')
print(mydict.remove_word(mydict.find_word(rm_word)))
# '4' to remove an existing definition using its ID
elif menu == '4':
print('~ You are now editing the dictionary ~')
obj_word = input('tWord: ')
mydict.output_word(obj_word)
id_def = input("nWhich definition do you want to remove? ")
print(mydict.remove_def(obj_word, id_def))
# 5 seconds delay, good for UX
print('nLoading...')
time.sleep(5)
python object-oriented json dictionary
add a comment |Â
up vote
3
down vote
favorite
Recently I published a post in which three people made pretty good suggestions. I've learnt a lot since then thanks to them!
From among many things, they encouraged me to use classes. And that's cool because it is the first time I do object oriented programming... Even though the use I gave it was very basic.
Once again, I'd like to receive reviews of my new code. It's uploaded in GitHub, in case someone wants to check it out.
I'm building this dictionary on python, using data.json.
Any suggestions are warmly welcome! So, how can I improme my code?
import json, time, re
from difflib import get_close_matches
class fuzzydict(object):
def __init__(self, json_file):
self.file = json_file
self.data = json.load(open(json_file, 'r+'))
def find_word(self, word):
for version in [word.lower(), word.capitalize(), word.title(), word.upper()]:
if version in self.data:
return version
simils = get_close_matches(word, self.data, 1, 0.7)
if len(simils) > 0:
return simils[0]
else:
return None
def output_word(self, word):
# check if 'keyword' has no values (definitions)
if not self.data[word]:
print('"%s" is yet to be defined.' % word)
# print in a cool format
else:
print('÷ ' + word + ':')
# re.split('--|;', self.data[word]) in case the
# definitions were not given inside a list
for index, definition in enumerate(self.data[word]):
print(str(index + 1) + '.', definition)
def input_word(self, word, definition):
operation = 0
# this prevents the user from adding an already existing definition
if word in self.data and definition not in self.data[word]:
self.data[word] += [definition]
operation = 1
# in case it's a new word
elif word not in self.data:
self.data.update(word: [definition])
operation = 1
# updates the file when necessary
if operation:
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
return 'nOUPS! Apparently the definition you attempted to add already exists.'
def remove_word(self, word):
if word != None:
self.data.pop(word, None)
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
else:
return "nHmm... how can you remove something that doesn't exist? Huh!"
def remove_def(self, word, index):
for i, definition in enumerate(self.data[word]):
if i == int(index) - 1:
self.data[word].remove(definition)
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
return "nHmm... how can you remove something that doesn't exist? Huh!"
# new object
mydict = fuzzydict('data.json')
# can either access the data through 'archives' or 'mydict.data'
while True:
menu = input('nnn'
'0. Quitn'
'1. Searchn'
'2. Add word or definitionn'
'3. Remove wordn'
'4. Remove definitionnn'
' '
'What would you like to do? ')
# '0' to exit
if menu == '0':
break
# '1' to look up a word
elif menu == '1':
search = input('nType in a word: ')
if mydict.find_word(search) == None:
print('"' + search + '"' + " isn't available at the moment.")
yes = input('Would you like to add "' + search + '" to the dictionary? ')
if yes.lower() == 'yes':
meaning = input('Type in the meaning of ' + search + ', please: ')
while meaning == '':
meaning = input('Type in a valid definition, please:')
print(mydict.input_word(search, meaning))
else:
mydict.output_word(mydict.find_word(search))
# '2' to add or remove a new word or definition
elif menu == '2':
print('~ You are now editing the dictionary ~')
new_word = input('tWord: ')
new_def = input('tDefinition: ')
if mydict.find_word(new_word) == None:
print(mydict.input_word(new_word, new_def))
else:
print(mydict.input_word(mydict.find_word(new_word), new_def))
# '3' to remove an existing word
elif menu == '3':
print('~ You are now editing the dictionary ~')
rm_word = input('tType in the word you want to remove from the dictionary: ')
print(mydict.remove_word(mydict.find_word(rm_word)))
# '4' to remove an existing definition using its ID
elif menu == '4':
print('~ You are now editing the dictionary ~')
obj_word = input('tWord: ')
mydict.output_word(obj_word)
id_def = input("nWhich definition do you want to remove? ")
print(mydict.remove_def(obj_word, id_def))
# 5 seconds delay, good for UX
print('nLoading...')
time.sleep(5)
python object-oriented json dictionary
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
Recently I published a post in which three people made pretty good suggestions. I've learnt a lot since then thanks to them!
From among many things, they encouraged me to use classes. And that's cool because it is the first time I do object oriented programming... Even though the use I gave it was very basic.
Once again, I'd like to receive reviews of my new code. It's uploaded in GitHub, in case someone wants to check it out.
I'm building this dictionary on python, using data.json.
Any suggestions are warmly welcome! So, how can I improme my code?
import json, time, re
from difflib import get_close_matches
class fuzzydict(object):
def __init__(self, json_file):
self.file = json_file
self.data = json.load(open(json_file, 'r+'))
def find_word(self, word):
for version in [word.lower(), word.capitalize(), word.title(), word.upper()]:
if version in self.data:
return version
simils = get_close_matches(word, self.data, 1, 0.7)
if len(simils) > 0:
return simils[0]
else:
return None
def output_word(self, word):
# check if 'keyword' has no values (definitions)
if not self.data[word]:
print('"%s" is yet to be defined.' % word)
# print in a cool format
else:
print('÷ ' + word + ':')
# re.split('--|;', self.data[word]) in case the
# definitions were not given inside a list
for index, definition in enumerate(self.data[word]):
print(str(index + 1) + '.', definition)
def input_word(self, word, definition):
operation = 0
# this prevents the user from adding an already existing definition
if word in self.data and definition not in self.data[word]:
self.data[word] += [definition]
operation = 1
# in case it's a new word
elif word not in self.data:
self.data.update(word: [definition])
operation = 1
# updates the file when necessary
if operation:
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
return 'nOUPS! Apparently the definition you attempted to add already exists.'
def remove_word(self, word):
if word != None:
self.data.pop(word, None)
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
else:
return "nHmm... how can you remove something that doesn't exist? Huh!"
def remove_def(self, word, index):
for i, definition in enumerate(self.data[word]):
if i == int(index) - 1:
self.data[word].remove(definition)
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
return "nHmm... how can you remove something that doesn't exist? Huh!"
# new object
mydict = fuzzydict('data.json')
# can either access the data through 'archives' or 'mydict.data'
while True:
menu = input('nnn'
'0. Quitn'
'1. Searchn'
'2. Add word or definitionn'
'3. Remove wordn'
'4. Remove definitionnn'
' '
'What would you like to do? ')
# '0' to exit
if menu == '0':
break
# '1' to look up a word
elif menu == '1':
search = input('nType in a word: ')
if mydict.find_word(search) == None:
print('"' + search + '"' + " isn't available at the moment.")
yes = input('Would you like to add "' + search + '" to the dictionary? ')
if yes.lower() == 'yes':
meaning = input('Type in the meaning of ' + search + ', please: ')
while meaning == '':
meaning = input('Type in a valid definition, please:')
print(mydict.input_word(search, meaning))
else:
mydict.output_word(mydict.find_word(search))
# '2' to add or remove a new word or definition
elif menu == '2':
print('~ You are now editing the dictionary ~')
new_word = input('tWord: ')
new_def = input('tDefinition: ')
if mydict.find_word(new_word) == None:
print(mydict.input_word(new_word, new_def))
else:
print(mydict.input_word(mydict.find_word(new_word), new_def))
# '3' to remove an existing word
elif menu == '3':
print('~ You are now editing the dictionary ~')
rm_word = input('tType in the word you want to remove from the dictionary: ')
print(mydict.remove_word(mydict.find_word(rm_word)))
# '4' to remove an existing definition using its ID
elif menu == '4':
print('~ You are now editing the dictionary ~')
obj_word = input('tWord: ')
mydict.output_word(obj_word)
id_def = input("nWhich definition do you want to remove? ")
print(mydict.remove_def(obj_word, id_def))
# 5 seconds delay, good for UX
print('nLoading...')
time.sleep(5)
python object-oriented json dictionary
Recently I published a post in which three people made pretty good suggestions. I've learnt a lot since then thanks to them!
From among many things, they encouraged me to use classes. And that's cool because it is the first time I do object oriented programming... Even though the use I gave it was very basic.
Once again, I'd like to receive reviews of my new code. It's uploaded in GitHub, in case someone wants to check it out.
I'm building this dictionary on python, using data.json.
Any suggestions are warmly welcome! So, how can I improme my code?
import json, time, re
from difflib import get_close_matches
class fuzzydict(object):
def __init__(self, json_file):
self.file = json_file
self.data = json.load(open(json_file, 'r+'))
def find_word(self, word):
for version in [word.lower(), word.capitalize(), word.title(), word.upper()]:
if version in self.data:
return version
simils = get_close_matches(word, self.data, 1, 0.7)
if len(simils) > 0:
return simils[0]
else:
return None
def output_word(self, word):
# check if 'keyword' has no values (definitions)
if not self.data[word]:
print('"%s" is yet to be defined.' % word)
# print in a cool format
else:
print('÷ ' + word + ':')
# re.split('--|;', self.data[word]) in case the
# definitions were not given inside a list
for index, definition in enumerate(self.data[word]):
print(str(index + 1) + '.', definition)
def input_word(self, word, definition):
operation = 0
# this prevents the user from adding an already existing definition
if word in self.data and definition not in self.data[word]:
self.data[word] += [definition]
operation = 1
# in case it's a new word
elif word not in self.data:
self.data.update(word: [definition])
operation = 1
# updates the file when necessary
if operation:
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
return 'nOUPS! Apparently the definition you attempted to add already exists.'
def remove_word(self, word):
if word != None:
self.data.pop(word, None)
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
else:
return "nHmm... how can you remove something that doesn't exist? Huh!"
def remove_def(self, word, index):
for i, definition in enumerate(self.data[word]):
if i == int(index) - 1:
self.data[word].remove(definition)
with open(self.file, 'w') as file:
json.dump(self.data, file)
return 'nDone!'
return "nHmm... how can you remove something that doesn't exist? Huh!"
# new object
mydict = fuzzydict('data.json')
# can either access the data through 'archives' or 'mydict.data'
while True:
menu = input('nnn'
'0. Quitn'
'1. Searchn'
'2. Add word or definitionn'
'3. Remove wordn'
'4. Remove definitionnn'
' '
'What would you like to do? ')
# '0' to exit
if menu == '0':
break
# '1' to look up a word
elif menu == '1':
search = input('nType in a word: ')
if mydict.find_word(search) == None:
print('"' + search + '"' + " isn't available at the moment.")
yes = input('Would you like to add "' + search + '" to the dictionary? ')
if yes.lower() == 'yes':
meaning = input('Type in the meaning of ' + search + ', please: ')
while meaning == '':
meaning = input('Type in a valid definition, please:')
print(mydict.input_word(search, meaning))
else:
mydict.output_word(mydict.find_word(search))
# '2' to add or remove a new word or definition
elif menu == '2':
print('~ You are now editing the dictionary ~')
new_word = input('tWord: ')
new_def = input('tDefinition: ')
if mydict.find_word(new_word) == None:
print(mydict.input_word(new_word, new_def))
else:
print(mydict.input_word(mydict.find_word(new_word), new_def))
# '3' to remove an existing word
elif menu == '3':
print('~ You are now editing the dictionary ~')
rm_word = input('tType in the word you want to remove from the dictionary: ')
print(mydict.remove_word(mydict.find_word(rm_word)))
# '4' to remove an existing definition using its ID
elif menu == '4':
print('~ You are now editing the dictionary ~')
obj_word = input('tWord: ')
mydict.output_word(obj_word)
id_def = input("nWhich definition do you want to remove? ")
print(mydict.remove_def(obj_word, id_def))
# 5 seconds delay, good for UX
print('nLoading...')
time.sleep(5)
python object-oriented json dictionary
edited Jan 6 at 19:32
asked Jan 6 at 16:18
c-horwicz
435
435
add a comment |Â
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
2
down vote
accepted
User experience:
Quit
option usually is the last one in the list.- Some words definitions are so long that I had to scroll horizontally.
- Going back to main menu after few seconds pass seems not very user-friendly. When there are many definitions you just don't have enough time to read all of them. I think it's better to go back to menu if some button is pressed.
- Also, while I'm shown a list of definitions there is this
Loading...
printed. It's a bit confusing. I was expecting more definitions to be printed out. But in fact there is no loading at all. Just waiting for some time. - Printing out similar words seems like a good idea, but sometimes it gives strange results. For example, if I wanted to look for
loan
but instead typedloqn
, it will give melong
. - If I made a mistake and typed word incorrectly when I wanted to delete it, the program wouldn't warn me and just delete the most similar word. There should be a warning about what word exactly is going to be deleted.
- Also, what if I change my mind about deleting word? I think there should be a way to go back to main menu.
- If I search for a word that doesn't exist, program asks if I want to add it to the dictionary. I typed
y
and expected it to be saved. But it didn't because you are checking only foryes
.
PEP 8:
Imports should be on separate lines. Also,
re
is never used.Class definition should be surrounded by 2 blank lines.
Class names are usually in CamelCase.
if len(simils) > 0:
should be replaced by simplyif simils:
. Also, why not rename it tosimilar_words
?
output_word
:
It's possible to avoid unnecessary nesting here like this:
if not self.data[word]:
print(f'"word" is yet to be defined.')
return
print('÷ ' + word + ':')
for index, definition in enumerate(self.data[word]):
print(str(index + 1) + '.', definition)Note the f-string above. It's a new feature of Python 3.6.
input_word
:
There is no need for a flag-variable
operation
. It is possible to avoid it here after some refactoring.Don't return strings like
Done!
. In your case you just want to print them and return nothing.It is possible to significantly reduce the code using
get
andsetdefault
methods like this:if definition in self.data.get(word, ):
print('nOUPS! Apparently the definition you attempted to add '
'already exists.')
return
self.data.setdefault(word, ).append(definition)
with open(self.file, 'w') as file:
json.dump(self.data, file)
print('nDone!')
remove_word
- Same as in
output_word
. First, check ifword is None
then without nesting withelse
remove the word from the dictionary.
remove_def
:
There is no need to iterate over definitions here. Just remove it by index and catch exceptions:
try:
self.data[word].pop(index - 1)
except IndexError:
print("nHmm... how can you remove something that doesn't exist? "
"Huh!")
return
with open(self.file, 'w') as file:
json.dump(self.data, file)
print("nDone!")
Other notes:
Everything that you put outside of a class should be put in functions. And use
if __name__ == '__main__':
Now you are opening, recording, closing your json file for every operation. Consider applying changes locally, and recording everything at once only in the very end, when you finish working with your dictionary.
1
That was knowledge enriching! Thank you so much, Georgy!!
â c-horwicz
Jan 10 at 10:00
add a comment |Â
up vote
3
down vote
You are particular about supporting various forms of the input word. I would suggest that you create a normalized key dictionary that maps lowercased versions of the key to a list of forms stored in the main dict.
That is:
def find_word(self, word):
lcword = word.lower()
stored_cases = self.get_keys[lcword] # Map 'cat' -> ['Cat', 'CAT', 'cat']
for key in stored_cases:
yield key
I would also suggest that you utilize None
instead of your 'N0t_F0uNd'
string. This case is pretty much why it exists - to express the idea that nothing is available. Except for the next suggestion...
I would also suggest that you write your code expecting find_word
to return multiple values. Actually, to generate multiple values as an iterator. So your code wouldn't check for a sentinel value meaning "I got nothing." Instead, it would iterate over all possible values, and possibly special-case the empty sequence:
for w in my_dict.find_word('cat'):
... etc ...
Finally, I would suggest that instead of dropping into insert mode when a match is not found, you print a message saying "Select option 2 to add it" or something. For extra points, you can remember the last searched word and make that the default during add/remove operations.
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
User experience:
Quit
option usually is the last one in the list.- Some words definitions are so long that I had to scroll horizontally.
- Going back to main menu after few seconds pass seems not very user-friendly. When there are many definitions you just don't have enough time to read all of them. I think it's better to go back to menu if some button is pressed.
- Also, while I'm shown a list of definitions there is this
Loading...
printed. It's a bit confusing. I was expecting more definitions to be printed out. But in fact there is no loading at all. Just waiting for some time. - Printing out similar words seems like a good idea, but sometimes it gives strange results. For example, if I wanted to look for
loan
but instead typedloqn
, it will give melong
. - If I made a mistake and typed word incorrectly when I wanted to delete it, the program wouldn't warn me and just delete the most similar word. There should be a warning about what word exactly is going to be deleted.
- Also, what if I change my mind about deleting word? I think there should be a way to go back to main menu.
- If I search for a word that doesn't exist, program asks if I want to add it to the dictionary. I typed
y
and expected it to be saved. But it didn't because you are checking only foryes
.
PEP 8:
Imports should be on separate lines. Also,
re
is never used.Class definition should be surrounded by 2 blank lines.
Class names are usually in CamelCase.
if len(simils) > 0:
should be replaced by simplyif simils:
. Also, why not rename it tosimilar_words
?
output_word
:
It's possible to avoid unnecessary nesting here like this:
if not self.data[word]:
print(f'"word" is yet to be defined.')
return
print('÷ ' + word + ':')
for index, definition in enumerate(self.data[word]):
print(str(index + 1) + '.', definition)Note the f-string above. It's a new feature of Python 3.6.
input_word
:
There is no need for a flag-variable
operation
. It is possible to avoid it here after some refactoring.Don't return strings like
Done!
. In your case you just want to print them and return nothing.It is possible to significantly reduce the code using
get
andsetdefault
methods like this:if definition in self.data.get(word, ):
print('nOUPS! Apparently the definition you attempted to add '
'already exists.')
return
self.data.setdefault(word, ).append(definition)
with open(self.file, 'w') as file:
json.dump(self.data, file)
print('nDone!')
remove_word
- Same as in
output_word
. First, check ifword is None
then without nesting withelse
remove the word from the dictionary.
remove_def
:
There is no need to iterate over definitions here. Just remove it by index and catch exceptions:
try:
self.data[word].pop(index - 1)
except IndexError:
print("nHmm... how can you remove something that doesn't exist? "
"Huh!")
return
with open(self.file, 'w') as file:
json.dump(self.data, file)
print("nDone!")
Other notes:
Everything that you put outside of a class should be put in functions. And use
if __name__ == '__main__':
Now you are opening, recording, closing your json file for every operation. Consider applying changes locally, and recording everything at once only in the very end, when you finish working with your dictionary.
1
That was knowledge enriching! Thank you so much, Georgy!!
â c-horwicz
Jan 10 at 10:00
add a comment |Â
up vote
2
down vote
accepted
User experience:
Quit
option usually is the last one in the list.- Some words definitions are so long that I had to scroll horizontally.
- Going back to main menu after few seconds pass seems not very user-friendly. When there are many definitions you just don't have enough time to read all of them. I think it's better to go back to menu if some button is pressed.
- Also, while I'm shown a list of definitions there is this
Loading...
printed. It's a bit confusing. I was expecting more definitions to be printed out. But in fact there is no loading at all. Just waiting for some time. - Printing out similar words seems like a good idea, but sometimes it gives strange results. For example, if I wanted to look for
loan
but instead typedloqn
, it will give melong
. - If I made a mistake and typed word incorrectly when I wanted to delete it, the program wouldn't warn me and just delete the most similar word. There should be a warning about what word exactly is going to be deleted.
- Also, what if I change my mind about deleting word? I think there should be a way to go back to main menu.
- If I search for a word that doesn't exist, program asks if I want to add it to the dictionary. I typed
y
and expected it to be saved. But it didn't because you are checking only foryes
.
PEP 8:
Imports should be on separate lines. Also,
re
is never used.Class definition should be surrounded by 2 blank lines.
Class names are usually in CamelCase.
if len(simils) > 0:
should be replaced by simplyif simils:
. Also, why not rename it tosimilar_words
?
output_word
:
It's possible to avoid unnecessary nesting here like this:
if not self.data[word]:
print(f'"word" is yet to be defined.')
return
print('÷ ' + word + ':')
for index, definition in enumerate(self.data[word]):
print(str(index + 1) + '.', definition)Note the f-string above. It's a new feature of Python 3.6.
input_word
:
There is no need for a flag-variable
operation
. It is possible to avoid it here after some refactoring.Don't return strings like
Done!
. In your case you just want to print them and return nothing.It is possible to significantly reduce the code using
get
andsetdefault
methods like this:if definition in self.data.get(word, ):
print('nOUPS! Apparently the definition you attempted to add '
'already exists.')
return
self.data.setdefault(word, ).append(definition)
with open(self.file, 'w') as file:
json.dump(self.data, file)
print('nDone!')
remove_word
- Same as in
output_word
. First, check ifword is None
then without nesting withelse
remove the word from the dictionary.
remove_def
:
There is no need to iterate over definitions here. Just remove it by index and catch exceptions:
try:
self.data[word].pop(index - 1)
except IndexError:
print("nHmm... how can you remove something that doesn't exist? "
"Huh!")
return
with open(self.file, 'w') as file:
json.dump(self.data, file)
print("nDone!")
Other notes:
Everything that you put outside of a class should be put in functions. And use
if __name__ == '__main__':
Now you are opening, recording, closing your json file for every operation. Consider applying changes locally, and recording everything at once only in the very end, when you finish working with your dictionary.
1
That was knowledge enriching! Thank you so much, Georgy!!
â c-horwicz
Jan 10 at 10:00
add a comment |Â
up vote
2
down vote
accepted
up vote
2
down vote
accepted
User experience:
Quit
option usually is the last one in the list.- Some words definitions are so long that I had to scroll horizontally.
- Going back to main menu after few seconds pass seems not very user-friendly. When there are many definitions you just don't have enough time to read all of them. I think it's better to go back to menu if some button is pressed.
- Also, while I'm shown a list of definitions there is this
Loading...
printed. It's a bit confusing. I was expecting more definitions to be printed out. But in fact there is no loading at all. Just waiting for some time. - Printing out similar words seems like a good idea, but sometimes it gives strange results. For example, if I wanted to look for
loan
but instead typedloqn
, it will give melong
. - If I made a mistake and typed word incorrectly when I wanted to delete it, the program wouldn't warn me and just delete the most similar word. There should be a warning about what word exactly is going to be deleted.
- Also, what if I change my mind about deleting word? I think there should be a way to go back to main menu.
- If I search for a word that doesn't exist, program asks if I want to add it to the dictionary. I typed
y
and expected it to be saved. But it didn't because you are checking only foryes
.
PEP 8:
Imports should be on separate lines. Also,
re
is never used.Class definition should be surrounded by 2 blank lines.
Class names are usually in CamelCase.
if len(simils) > 0:
should be replaced by simplyif simils:
. Also, why not rename it tosimilar_words
?
output_word
:
It's possible to avoid unnecessary nesting here like this:
if not self.data[word]:
print(f'"word" is yet to be defined.')
return
print('÷ ' + word + ':')
for index, definition in enumerate(self.data[word]):
print(str(index + 1) + '.', definition)Note the f-string above. It's a new feature of Python 3.6.
input_word
:
There is no need for a flag-variable
operation
. It is possible to avoid it here after some refactoring.Don't return strings like
Done!
. In your case you just want to print them and return nothing.It is possible to significantly reduce the code using
get
andsetdefault
methods like this:if definition in self.data.get(word, ):
print('nOUPS! Apparently the definition you attempted to add '
'already exists.')
return
self.data.setdefault(word, ).append(definition)
with open(self.file, 'w') as file:
json.dump(self.data, file)
print('nDone!')
remove_word
- Same as in
output_word
. First, check ifword is None
then without nesting withelse
remove the word from the dictionary.
remove_def
:
There is no need to iterate over definitions here. Just remove it by index and catch exceptions:
try:
self.data[word].pop(index - 1)
except IndexError:
print("nHmm... how can you remove something that doesn't exist? "
"Huh!")
return
with open(self.file, 'w') as file:
json.dump(self.data, file)
print("nDone!")
Other notes:
Everything that you put outside of a class should be put in functions. And use
if __name__ == '__main__':
Now you are opening, recording, closing your json file for every operation. Consider applying changes locally, and recording everything at once only in the very end, when you finish working with your dictionary.
User experience:
Quit
option usually is the last one in the list.- Some words definitions are so long that I had to scroll horizontally.
- Going back to main menu after few seconds pass seems not very user-friendly. When there are many definitions you just don't have enough time to read all of them. I think it's better to go back to menu if some button is pressed.
- Also, while I'm shown a list of definitions there is this
Loading...
printed. It's a bit confusing. I was expecting more definitions to be printed out. But in fact there is no loading at all. Just waiting for some time. - Printing out similar words seems like a good idea, but sometimes it gives strange results. For example, if I wanted to look for
loan
but instead typedloqn
, it will give melong
. - If I made a mistake and typed word incorrectly when I wanted to delete it, the program wouldn't warn me and just delete the most similar word. There should be a warning about what word exactly is going to be deleted.
- Also, what if I change my mind about deleting word? I think there should be a way to go back to main menu.
- If I search for a word that doesn't exist, program asks if I want to add it to the dictionary. I typed
y
and expected it to be saved. But it didn't because you are checking only foryes
.
PEP 8:
Imports should be on separate lines. Also,
re
is never used.Class definition should be surrounded by 2 blank lines.
Class names are usually in CamelCase.
if len(simils) > 0:
should be replaced by simplyif simils:
. Also, why not rename it tosimilar_words
?
output_word
:
It's possible to avoid unnecessary nesting here like this:
if not self.data[word]:
print(f'"word" is yet to be defined.')
return
print('÷ ' + word + ':')
for index, definition in enumerate(self.data[word]):
print(str(index + 1) + '.', definition)Note the f-string above. It's a new feature of Python 3.6.
input_word
:
There is no need for a flag-variable
operation
. It is possible to avoid it here after some refactoring.Don't return strings like
Done!
. In your case you just want to print them and return nothing.It is possible to significantly reduce the code using
get
andsetdefault
methods like this:if definition in self.data.get(word, ):
print('nOUPS! Apparently the definition you attempted to add '
'already exists.')
return
self.data.setdefault(word, ).append(definition)
with open(self.file, 'w') as file:
json.dump(self.data, file)
print('nDone!')
remove_word
- Same as in
output_word
. First, check ifword is None
then without nesting withelse
remove the word from the dictionary.
remove_def
:
There is no need to iterate over definitions here. Just remove it by index and catch exceptions:
try:
self.data[word].pop(index - 1)
except IndexError:
print("nHmm... how can you remove something that doesn't exist? "
"Huh!")
return
with open(self.file, 'w') as file:
json.dump(self.data, file)
print("nDone!")
Other notes:
Everything that you put outside of a class should be put in functions. And use
if __name__ == '__main__':
Now you are opening, recording, closing your json file for every operation. Consider applying changes locally, and recording everything at once only in the very end, when you finish working with your dictionary.
answered Jan 8 at 20:13
Georgy
5521415
5521415
1
That was knowledge enriching! Thank you so much, Georgy!!
â c-horwicz
Jan 10 at 10:00
add a comment |Â
1
That was knowledge enriching! Thank you so much, Georgy!!
â c-horwicz
Jan 10 at 10:00
1
1
That was knowledge enriching! Thank you so much, Georgy!!
â c-horwicz
Jan 10 at 10:00
That was knowledge enriching! Thank you so much, Georgy!!
â c-horwicz
Jan 10 at 10:00
add a comment |Â
up vote
3
down vote
You are particular about supporting various forms of the input word. I would suggest that you create a normalized key dictionary that maps lowercased versions of the key to a list of forms stored in the main dict.
That is:
def find_word(self, word):
lcword = word.lower()
stored_cases = self.get_keys[lcword] # Map 'cat' -> ['Cat', 'CAT', 'cat']
for key in stored_cases:
yield key
I would also suggest that you utilize None
instead of your 'N0t_F0uNd'
string. This case is pretty much why it exists - to express the idea that nothing is available. Except for the next suggestion...
I would also suggest that you write your code expecting find_word
to return multiple values. Actually, to generate multiple values as an iterator. So your code wouldn't check for a sentinel value meaning "I got nothing." Instead, it would iterate over all possible values, and possibly special-case the empty sequence:
for w in my_dict.find_word('cat'):
... etc ...
Finally, I would suggest that instead of dropping into insert mode when a match is not found, you print a message saying "Select option 2 to add it" or something. For extra points, you can remember the last searched word and make that the default during add/remove operations.
add a comment |Â
up vote
3
down vote
You are particular about supporting various forms of the input word. I would suggest that you create a normalized key dictionary that maps lowercased versions of the key to a list of forms stored in the main dict.
That is:
def find_word(self, word):
lcword = word.lower()
stored_cases = self.get_keys[lcword] # Map 'cat' -> ['Cat', 'CAT', 'cat']
for key in stored_cases:
yield key
I would also suggest that you utilize None
instead of your 'N0t_F0uNd'
string. This case is pretty much why it exists - to express the idea that nothing is available. Except for the next suggestion...
I would also suggest that you write your code expecting find_word
to return multiple values. Actually, to generate multiple values as an iterator. So your code wouldn't check for a sentinel value meaning "I got nothing." Instead, it would iterate over all possible values, and possibly special-case the empty sequence:
for w in my_dict.find_word('cat'):
... etc ...
Finally, I would suggest that instead of dropping into insert mode when a match is not found, you print a message saying "Select option 2 to add it" or something. For extra points, you can remember the last searched word and make that the default during add/remove operations.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
You are particular about supporting various forms of the input word. I would suggest that you create a normalized key dictionary that maps lowercased versions of the key to a list of forms stored in the main dict.
That is:
def find_word(self, word):
lcword = word.lower()
stored_cases = self.get_keys[lcword] # Map 'cat' -> ['Cat', 'CAT', 'cat']
for key in stored_cases:
yield key
I would also suggest that you utilize None
instead of your 'N0t_F0uNd'
string. This case is pretty much why it exists - to express the idea that nothing is available. Except for the next suggestion...
I would also suggest that you write your code expecting find_word
to return multiple values. Actually, to generate multiple values as an iterator. So your code wouldn't check for a sentinel value meaning "I got nothing." Instead, it would iterate over all possible values, and possibly special-case the empty sequence:
for w in my_dict.find_word('cat'):
... etc ...
Finally, I would suggest that instead of dropping into insert mode when a match is not found, you print a message saying "Select option 2 to add it" or something. For extra points, you can remember the last searched word and make that the default during add/remove operations.
You are particular about supporting various forms of the input word. I would suggest that you create a normalized key dictionary that maps lowercased versions of the key to a list of forms stored in the main dict.
That is:
def find_word(self, word):
lcword = word.lower()
stored_cases = self.get_keys[lcword] # Map 'cat' -> ['Cat', 'CAT', 'cat']
for key in stored_cases:
yield key
I would also suggest that you utilize None
instead of your 'N0t_F0uNd'
string. This case is pretty much why it exists - to express the idea that nothing is available. Except for the next suggestion...
I would also suggest that you write your code expecting find_word
to return multiple values. Actually, to generate multiple values as an iterator. So your code wouldn't check for a sentinel value meaning "I got nothing." Instead, it would iterate over all possible values, and possibly special-case the empty sequence:
for w in my_dict.find_word('cat'):
... etc ...
Finally, I would suggest that instead of dropping into insert mode when a match is not found, you print a message saying "Select option 2 to add it" or something. For extra points, you can remember the last searched word and make that the default during add/remove operations.
answered Jan 6 at 17:33
Austin Hastings
6,1591130
6,1591130
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184457%2fv2-interactive-dictionary-with-inexact-look-ups-updated%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password