Vocabulary test using Queue - python

I have a list with words in two languages where each foreign word is followed (on the next row) by its meaning in a known language. Example:
hablar
talk
llamar
call
Now I wish to create a vocabulary test using queues. My idea is to create 2 queues q1 and q2. All the words start in q1 until each word's meaning has been guessed correctly. If you get a word wrong, the word will get placed in the end of the queue of q1 and if you get it right, it will be moved to q2. When q1 is empty, you move over to q2 and do the same thing, except the words get 'thrown away' when you answer correctly and the test is done once q2 is empty.
The problem is I can't figure out how to create a way to associate the foreign word with the known word. I think I should start like this:
class Wordpair():
def __init__(self, l1, l2):
self.lang1 = l1
self.lang2 = l2
def __str__(self):
question=input('What does'+self.lang1+'mean?')
But I don't know how to test if the preson answers correctly or wrongly. Also, I think I could somehow implement nodes since the meaning of the word (Node) will be the next word (Node.next). I will update as I make progress, but I'd appreciate any tips you have now.
Edit1: This is how I created the queue:
class Queue:
def __init__(self):
self.items = []
def put(self, item):
self.items.append(item)
def get(self):
return self.items.pop(0)
def isempty(self):
return self.items == []

You can simply compare the user input with the known meaning of the word.
I have written a simple script(Python3) for you to solve this problem, hope it helps!
import queue
class Word(object):
def __init__(self, foreign_meaning, known_meaning):
self.foreign_meaning = foreign_meaning
self.known_meaning = known_meaning
if __name__ == '__main__':
q1 = queue.Queue()
q2 = queue.Queue()
# Put some sample words
q1.put(Word('hablar', 'talk'))
q1.put(Word('llamar', 'call'))
while True:
if q1.empty():
print("You have finished all words!")
break
word = q1.get() # Get the next word in q1
ans = input("What is the meaning of `{0}`? ".format(word.foreign_meaning)) # Fetch user input as the answer
if ans == word.known_meaning:
print("Correct!")
q2.put(word)
else:
print("Wrong! The meaning of `{0}` is `{1}`".format(word.foreign_meaning, word.known_meaning))
q1.put(word)
print()
Looks like that you are using your own queue implementation.
I have modified my code to fit the question. However, it is strongly recommended that you use the built-in queue module provided by Python3 as it is thread safe.
#!/usr/bin/env python
class Queue:
def __init__(self):
self.items = []
def put(self, item):
self.items.append(item)
def get(self):
return self.items.pop(0)
def isempty(self):
return self.items == []
class Word(object):
def __init__(self, foreign_meaning, known_meaning):
self.foreign_meaning = foreign_meaning
self.known_meaning = known_meaning
if __name__ == '__main__':
q1 = Queue()
q2 = Queue()
# Put some sample words
q1.put(Word('hablar', 'talk'))
q1.put(Word('llamar', 'call'))
while True:
if q1.isempty():
print("You have finished all words!")
break
word = q1.get() # Get the next word in q1
ans = input("What is the meaning of `{0}`? ".format(word.foreign_meaning)) # Fetch user input as the answer
if ans == word.known_meaning:
print("Correct!")
q2.put(word)
else:
print("Wrong! The meaning of `{0}` is `{1}`".format(word.foreign_meaning, word.known_meaning))
q1.put(word)
print()

In this case, I would just use a list for each word. I don't think you really need a new class. The program I ended up with is a little long (note this is python 2):
#!/usr/bin/env python
from Queue import Queue
FILENAME='words.txt'
def main():
q1 = readwords()
q2 = Queue()
while (not q1.empty()) or (not q2.empty()):
if not q1.empty():
src = 1
word = q1.get()
else:
src = 2
word = q2.get()
ans = input('What does "'+word[0]+'" mean? ')
if ans==word[1]:
print 'Correct!'
src += 1
else:
print 'Incorrect! "'+word[1]+'"'
if src==1:
q1.put(word)
elif src==2:
q2.put(word)
print 'Done! Good job!'
def readwords():
with open(FILENAME,'r') as f:
lines = f.readlines()
first = True
words = Queue()
word = [None,None]
for x in lines:
if not x.strip():
continue
if first:
word[0] = x.strip()
first = False
else:
word[1] = x.strip()
first = True
words.put(word)
word = [None,None]
return words
if __name__ == '__main__':
main()

Related

How do I pass variables from the Parent class method to the a Child class method?

I've got a parent class and a child class. I want the child class to take the method from the parent class, perform a operation and apply it. What I'm trying to do is loop through a wordlist file in the parent class method openWordlist(), and for every word in that wordlist file, pass it to the child class method scanDomain() to perform an operation which is to loop through website directories that are available to the public.
class Main:
def __init__(self):
self.wordlistFile = ''
self.word = ''
def openWordlist(self):
with open(self.wordlistFile, 'r') as suppliedWordlist:
for word in suppliedWordlist:
word = word.strip()
self.word = word
class DirectoryScan(Main):
def scanDomain(self):
try:
self.cleanURL = 'https://google.com' + self.word
self.reqURL = requests.get(self.cleanURL)
if self.reqURL.status_code == 200:
print('Found: {self.cleanURL}')
elif self.reqURL.status_code != 200:
pass
except InvalidURL:
print(f'{self.targetURL} does NOT exist.')
if __name__ == '__main__':
s = Main()
d = DirectoryScan()
directoryScan.openWordlist()
directoryScan.scanDomain()
However, the result that I'm getting is just the https://google.com/ back. Is there something wrong with the inheritance that I'm doing?
The name of your input file is '', which can't be opened.
Thus, you never set self.word to anything except ''.
And even if you did open a file, you would only set self.word to the last word in the file.
Do what you say you want to do; "loop through a wordlist file in the parent class method openWordlist(), and for every word in that wordlist file, pass it to the [...] method scanDomain()"
class Main:
def __init__(self, filename):
self.wordlistFile = filename
def scanDomain(self, word):
pass
def openWordlist(self):
with open(self.wordlistFile, 'r') as suppliedWordlist:
for word in suppliedWordlist:
self.scanDomain(word.strip())
class DirectoryScan(Main):
def scanDomain(self, word):
try:
self.cleanURL = 'https://google.com/' + word
self.reqURL = requests.get(self.cleanURL)
if self.reqURL.status_code == 200:
print('Found: {self.cleanURL}')
elif self.reqURL.status_code != 200:
pass
except InvalidURL:
print(f'{self.targetURL} does NOT exist.')
if __name__ == '__main__':
d = DirectoryScan('somefile.txt')
d.openWordlist()
(The point of this inheritance structure is a mystery, though.)
I think your issue is here:
def openWordlist(self):
with open(self.wordlistFile, 'r') as suppliedWordlist:
for word in suppliedWordlist:
word = word.strip()
self.word = word
You are iterating over the suppliedWordList and set self.word = word.
But from the context I get, the suppliedWordList can be longer. So maybe your last line does not contain what you actually want to add there to your url.

I am looking to create instances of a class from user input

I Have this class:
class Bowler:
def __init__(self, name, score):
self.name = name
self.score = score
def nameScore(self):
return '{} {}'.format(self.name, self.score)
I need to get user input until a blank line is entered. Then use the data I got to create instances of a class. I was thinking something like:
def getData():
name, score = input("Please enter your credentails (Name score): ").split()
B1 = Bowler(name, score)
print(B1.nameScore())
But then I would somehow have to loop it until I get a blank user input. Also I would somehow have to create B2 B3 B4 etc in the loop.
Sorry I am still really new to programming, maybe I am looking at this from the wrong angle.
What you're looking for are Python Lists. With these you will be able to keep track of your newly created items while running the loop. To create a list we simply defined it like so:
our_bowlers = []
Now we need to alter our getData function to return either None or a new Bowler:
def getData():
# Get the input
our_input = input("Please enter your credentails (Name score): ").split()
# Check if it is empty
if our_input == '':
return None
# Otherwise, we split our data and create the Bowler
name, score = our_input.split()
return Bowler(name, score)
and then we can run a loop, check for a new Bowler and if we didn't get anything, we can print all the Bowlers we created:
# Get the first line and try create a Bowler
bowler = getData()
# We loop until we don't have a valid Bowler
while bowler is not None:
# Add the Bowler to our list and then try get the next one
our_bowlers.append(bowler)
bowler = getData()
# Print out all the collected Bowlers
for b in our_bowlers:
print(b.nameScore())
This is my code to do what you want:
class Bowler:
def __init__(self, name, score):
self.name = name
self.score = score
def nameScore(self):
return '{} {}'.format(self.name, self.score)
def getData():
try:
line = input("Please enter your credentails (Name score): ")
except SyntaxError as e:
return None
name, score = line.split()
score = int(score)
B = Bowler(name, score)
print(B.nameScore())
return B
if __name__ == '__main__':
bowlers = list()
while True:
B = getData()
if B == None:
break
bowlers.append(B)
for B in bowlers:
print(B.nameScore())
In addition, I recommend you to modify your input for it's inconvenient now

"AttributeError: 'list' object has no attribute 'SMSMessage'"

I have tried many ways but can't seem to get the length of my list through the method in my class my code:
SMSStore = []
unreadMessage = []
class SMSMessage(object):
def __init__(self, hasBeenRead, messageText, fromNumber):
self.hasBeenRead = hasBeenRead
self.messageText = messageText
self.fromNumber = fromNumber
hasBeenRead = False
def markAsRead(self, hasBeenRead):
hasBeenRead = True
def add_sms(self):
newMessage = (self.hasBeenRead, self.messageText, self.fromNumber)
return SMSStore.append(newMessage)
def get_count():
return len(SMSStore)
def get_message(self, i):
hasBeenRead = True
return SMSStore[i][1]
def get_unread_messages(i):
for i in SMSStore:
if SMSStore[i][0] == False:
unreadMessage.append(SMSStore[i])
print unreadMessage
def remove(self, i):
return SMSStore.remove(i)
This is how a message in the list would ideally look like:
#sample = SMSMessage(False, "Hello friend!", 0742017560)
And here is how the class is used
userChoice = ""
while userChoice != "quit":
userChoice = raw_input("What would you like to do - read/send/quit?")
if userChoice == "read":
print len(SMSStore)#this way i can get the length of the list anyway without using get_count
SMSStore(get_count()
unreadChoice = raw_input("Would you like to retrieve all unread messages or one of your own choice? - all unread/custom ")
if unreadChoice == "custom":
i = int(raw_input("Please enter which message number you want to read: "))
print get_message(i) #I dont understand how i works and how to get it working with the object definition
elif userChoice == "send":
messageText = raw_input("Please type in your message: ")
fromNumber = raw_input("Please type in the number it was sent from ")
newObject = SMSMessage(False, messageText, fromNumber)
newObject.add_sms()
print SMSStore
elif userChoice == "quit":
print "Goodbye"
else:
print "Oops - incorrect input"
I can just use len(SMSStore) but I want to be able to use the method inside the class to get it. Can point out any mistakes?
This was the question asked:
Open the file called​  sms.py​
Create a class definition for an SMSMessage which has three variables:
hasBeenRead, messageText, and fromNumber. 
The constructor should initialise the sender’s number. 
The constructor should also initialise hasBeenRead  to false
Create a method in this class called MarkAsRead which should change hasBeenRead to true.
Create a list called SMSStore to be used as the inbox.
Then create the following methods:
add_sms - which takes in the text and number from the received sms to
make a new SMSMessage object. 
get_count - returns the number of messages in the store.
get_message - returns the text of a message in the list.Forthis, allow the
user to input an index i.e. GetMessage(i) returns the message
stored at position i in the list. Once this has been done,
hasBeenRead should now be true. 
get_unread_messages - should return a list of all the messages which
haven’t been read. 
remove - removes a message in the SMSStore. 
Now that you have these set up, let’s get everything working! 
in your SMSMessage class
def get_count(self, *args):
return len(SMSStore)
in your script
# create instance
sms_msg = SMSMessage() # init arg needed
print sms_msg.get_count()
SMSStore is a global variable, you could remove get_count from SMSMessage scope
SMSStore = []
unreadMessage = []
class SMSMessage(object):
...functions...
def get_count(*args):
return len(SMSStore)
and call it regularly OR
ls = range(20)
class A(object):
# declare default value for your arguments
def __init__(self, hasBeenRead = False, messageText = "", fromNumber=0):
self.a = a
self.b = b
#using classmethod
#classmethod
def get_count(cls, *args):
return len(ls)
print A.get_count()

Looping a function until another function is called

I am making a menu that runs on an LCD screen powered by a Raspberry Pi. I am trying to use the threading module to make the text, on the LCD, update until the menu position changes.
The menu is made up of a list of functions that are called when the menu position is changed. The switch_menu() function is called from outside the class, using an event handler, and is used to call the correct menu function. With some of these functions(item2); I want them to loop, and with others(item1); just display static text. The important thing is that they stop looping when switch_menu() is called again. How can I do this?
(here is a simplified version of my code)
class Menu:
def __init__(self):
self.LCD = Adafruit_CharLCD()
self.m_pos = 0
self.items = [self.item1,self.item2]
self.switch_menu(0)
def switch_menu(self,operation):
# 2. And here I want to stop it.
m_pos = self.m_pos
pos = m_pos
max_pos = len(self.items) - 1
m_pos = self.loop_selection(pos,max_pos,operation)
# 1. Here I want to start looping the function below.
self.items[m_pos]()
self.m_pos = m_pos
def loop_selection(self,pos,max_pos,operation):
if pos >= max_pos and operation == 1:
pos = 0
elif pos <= 0 and operation == -1:
pos = max_pos
else:
pos += operation
return pos
def item1(self):
self.LCD.clear()
text = "item1"
self.LCD.message(text)
def item2(self):
while True:
self.LCD.clear()
text = "item2"
self.LCD.message(text)
time.sleep(10)
There are many ways to achieve this, one simple way is to make the while loop in a variable and then set it to False outside the loop (for example, when calling switch_menu) once you want to stop it. Just beware of any race conditions that may be caused, of which I can't talk much more about since I don't know the rest of your code.
Typical, I have been trying to get this to work for days and as soon as I post a question; I find the answer.
Here is where I found my answer:
Stopping a thread after a certain amount of time
And this is what I did to make it work:
class Menu:
def __init__(self):
self.LCD = Adafruit_CharLCD()
self.m_pos = 0
self.items = [self.item1,self.item2]
self.switch_menu(0)
def switch_menu(self,operation):
try:
self.t_stop.set()
except:
pass
m_pos = self.m_pos
pos = m_pos
max_pos = len(self.items) - 1
m_pos = self.loop_selection(pos,max_pos,operation)
item = self.items[m_pos][0]
self.t_stop = threading.Event()
self.t = threading.Thread(target=item,args=(1,self.t_stop))
self.t.start()
self.m_pos = m_pos
def loop_selection(self,pos,max_pos,operation):
if pos >= max_pos and operation == 1:
pos = 0
elif pos <= 0 and operation == -1:
pos = max_pos
else:
pos += operation
return pos
def item1(self,arg):
while not stop_event.is_set():
text = "item1"
self.LCD.clear()
if not stop_event.is_set(): self.LCD.message(text)
stop_event.wait(10)
def item2(self,arg):
while not stop_event.is_set():
text = "item2"
self.LCD.clear()
if not stop_event.is_set(): self.LCD.message(text)
stop_event.wait(10)
I used a try/except to bypass the initial execution of switch_menu():
try:
self.t_stop.set()
except:
pass
I check the condition a second time as a workaround, to prevent race conditions:
if not stop_event.is_set(): self.LCD.message(text)
And I don't know why I had to pass in an argument when creating a thread, but it gave me errors when I didn't:
self.t = threading.Thread(target=item,args=(1,self.t_stop))
I know it needs some tidying up, but it works. If anyone has a more elegant solution feel free to post it.

'Queue' object has no attribute 'size'

I have seen other examples of this happening on StackOverflow, but I didn't understand any of the answers (I'm still a new programmer,) nor did the other examples I saw look quite like mine, else I wouldn't post this question.
I'm running Python 3.2 on Windows 7.
I have never had this happen to me before and I've done classes this way many times, so I don't really know what is different this time. The only difference is that I didn't make all of the Class file; I was given a template to fill in and a test file to try it on. It worked on the test file, but is not working on my file. I have been calling on the methods in the class in the exact same way as the test file (e.g. Lineup.size())
This is my Class:
class Queue:
# Constructor, which creates a new empty queue:
def __init__(self):
self.__items = []
# Adds a new item to the back of the queue, and returns nothing:
def queue(self, item):
self.__items.insert(0,item)
return
# Removes and returns the front-most item in the queue.
# Returns nothing if the queue is empty.
def dequeue(self):
if len(self.__items) == 0:
return None
else:
return self.__items.pop()
# Returns the front-most item in the queue, and DOES NOT change the queue.
def peek(self):
if len(self.__items) == 0:
return None
else:
return self.__items[(len(self.__items)-1)]
# Returns True if the queue is empty, and False otherwise:
def is_empty(self):
return len(self.__items) == 0
# Returns the number of items in the queue:
def size(self):
return len(self.__items)
# Removes all items from the queue, and sets the size to 0:
def clear(self):
del self.__items[0:len(self.__items)]
return
# Returns a string representation of the queue:
def __str__(self):
return "".join(str(i) for i in self.__items)
This is my program:
from queue import Queue
Lineup = Queue()
while True:
decision = str(input("Add, Serve, or Exit: ")).lower()
if decision == "add":
if Lineup.size() == 3:
print("There cannot be more than three people in line.")
continue
else:
person = str(input("Enter the name of the person to add: "))
Lineup.queue(person)
continue
elif decision == "serve":
if Lineup.is_empty() == True:
print("The lineup is already empty.")
continue
else:
print("%s has been served."%Lineup.peek())
Lineup.dequeue()
continue
elif (decision == "exit") or (decision == "quit"):
break
else:
print("%s is not a valid command.")
continue
And this is my error message when I enter "add" as my decision variable:
line 8, in
builtins.AttributeError: 'Queue' object has no attribute 'size'
So, what is going on here? What is different about this one?
Python 3 already has a queue module (which you might want to take a look at). When you import queue, Python finds that queue.py file before it finds your queue.py.
Rename your queue.py file to my_queue.py, change your import statements to from my_queue import Queue, and your code will work as you intend.
try rename size for other name or implement a counter to the list __items some like
def get_size(self):
cnt = 0
for i in self.__items:
cnt++
return cnt

Categories

Resources