Related
Intended Function of code: Takes a user input for the volume of 3 jars(1-9) and output the volumes with one of the jars containing the target length. jars can be Emptied/Filled a jar, or poured from one jar to another until one is empty or full.
With the code I have, i'm stuck on a key exception error .
Target length is 4 for this case
Code:
`
class Graph:
class GraphNode:
def __init__(self, jar1 = 0, jar2 = 0, jar3 = 0, color = "white", pi = None):
self.jar1 = jar1
self.jar2 = jar2
self.jar3 = jar3
self.color = color
self.pi = pi
def __repr__(self):
return str(self)
def __init__(self, jl1 = 0, jl2 = 0, jl3 = 0, target = 0):
self.jl1 = jl1
self.jl2 = jl2
self.jl3 = jl3
self.target = target
self.V = {}
for x in range(jl1 + 1):
for y in range(jl2 + 1):
for z in range(jl3 + 1):
node = Graph.GraphNode(x, y, z, "white", None)
self.V[node] = None
def isFound(self, a: GraphNode) -> bool:
if self.target in [a.jar1, a.jar2, a.jar3]:
return True
return False
pass
def isAdjacent(self, a: GraphNode, b: GraphNode) -> bool:
if self.V[a]==b:
return True
return False
pass
def BFS(self) -> [] :
start = Graph.GraphNode(0, 0, 0, "white")
queue=[]
queue.append(start)
while len(queue)>0:
u=queue.pop(0)
for v in self.V:
if self.isAdjacent(u,v):
if v.color =="white":
v.color == "gray"
v.pi=u
if self.isFound(v):
output=[]
while v.pi is not None:
output.insert(0,v)
v=v.pi
return output
else:
queue.append(v)
u.color="black"
return []
#######################################################
j1 = input("Size of first jar: ")
j2 = input("Size of second jar: ")
j3 = input("Size of third jar: ")
t = input("Size of target: ")
jar1 = int(j1)
jar2 = int(j2)
jar3 = int(j3)
target = int(t)
graph1 = Graph(jar1, jar2, jar3, target)
output = graph1.BFS()
print(output)
`
**Error: **
line 37, in isAdjacent
if self.V[a]==b:
KeyError: <exception str() failed>
Strange but when I first ran this in the IPython interpreter I got a different exception:
... :35, in Graph.isAdjacent(self, a, b)
34 def isAdjacent(self, a: GraphNode, b: GraphNode) -> bool:
---> 35 if self.V[a]==b:
36 return True
37 return False
<class 'str'>: (<class 'RecursionError'>, RecursionError('maximum recursion depth exceeded while getting the str of an object'))
When I run it as a script or in the normal interpreter I do get the same one you had:
... line 35, in isAdjacent
if self.V[a]==b:
KeyError: <exception str() failed>
I'm not sure what this means so I ran the debugger and got this:
File "/Users/.../stackoverflow/bfs1.py", line 1, in <module>
class Graph:
File "/Users/.../stackoverflow/bfs1.py", line 47, in BFS
if self.isAdjacent(u,v):
File "/Users/.../stackoverflow/bfs1.py", line 35, in isAdjacent
if self.V[a]==b:
KeyError: <unprintable KeyError object>
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> /Users/.../stackoverflow/bfs1.py(35)isAdjacent()
-> if self.V[a]==b:
(Pdb) type(a)
<class '__main__.Graph.GraphNode'>
(Pdb) str(a)
*** RecursionError: maximum recursion depth exceeded while calling a Python object
So it does seem like a maximum recursion error. (The error message you originally got is not very helpful). But the words <unprintable KeyError object> are a clue. It looks like it was not able to display the KeyError exception...
The culprit is this line in your class definition:
def __repr__(self):
return str(self)
What were you trying to do here?
The __repr__ function is called when the class is asked to produce a string representation of itself. But yours calls the string function on the instance of the class so it will call itself! So I think you actually generated a second exception while the debugger was trying to display the first!!!.
I replaced these lines with
def __repr__(self):
return f"GraphNode({self.jar1}, {self.jar2}, {self.jar3}, {self.color}, {self.pi})"
and I don't get the exception now:
Size of first jar: 1
Size of second jar: 3
Size of third jar: 6
Size of target: 4
Traceback (most recent call last):
File "/Users/.../stackoverflow/bfs1.py", line 77, in <module>
output = graph1.BFS()
File "/Users/.../stackoverflow/bfs1.py", line 45, in BFS
if self.isAdjacent(u,v):
File "/Users/.../stackoverflow/bfs1.py", line 33, in isAdjacent
if self.V[a]==b:
KeyError: GraphNode(0, 0, 0, white, None)
This exception is easier to interpret. Now it's over to you to figure out why this GraphNode was not found in the keys of self.V!
I've seen similar questions to this but I can't figure it out for my own example, I have this code:
import ast
import pytest
import re
def autocomplete1(str,list_name):
return [i for i in list(set(list_name)) if i.startswith(str)]
def autocomplete2(str,list_name):
return(list(filter(lambda x: x.startswith(str), list(set(list_name)))))
def autocomplete3(str,list_name):
return([i for i in list_name if re.match(str,i)])
#fix the list
#pytest.mark.parametrize('input1, input2, output1', [('de',['dog','deer','deal'],['deer','deal']), ('ear',['earplug','earphone','airplane'],['earplug','earphone'])])
def test_function(input1,input2,output1):
assert autocomplete1(input1,input2) == output1
assert autocomplete2(input1,input2) == output1
assert autocomplete3(input1,input2) == output1
The Error is:
start_query_string.py FF [100%]
============================================================================================= FAILURES ==============================================================================================
________________________________________________________________________________ test_function[de-input20-output10] _________________________________________________________________________________
input1 = 'de', input2 = ['dog', 'deer', 'deal'], output1 = ['deer', 'deal']
#pytest.mark.parametrize('input1, input2, output1', [('de',['dog','deer','deal'],['deer','deal']), ('ear',['earplug','earphone','airplane'],['earplug','earphone'])])
def test_function(input1,input2,output1):
> assert autocomplete1(input1,input2) == output1
E AssertionError: assert ['deal', 'deer'] == ['deer', 'deal']
E At index 0 diff: 'deal' != 'deer'
E Use -v to get the full diff
start_query_string.py:27: AssertionError
________________________________________________________________________________ test_function[ear-input21-output11] ________________________________________________________________________________
input1 = 'ear', input2 = ['earplug', 'earphone', 'airplane'], output1 = ['earplug', 'earphone']
#pytest.mark.parametrize('input1, input2, output1', [('de',['dog','deer','deal'],['deer','deal']), ('ear',['earplug','earphone','airplane'],['earplug','earphone'])])
def test_function(input1,input2,output1):
> assert autocomplete1(input1,input2) == output1
E AssertionError: assert ['earphone', 'earplug'] == ['earplug', 'earphone']
E At index 0 diff: 'earphone' != 'earplug'
E Use -v to get the full diff
start_query_string.py:27: AssertionError
I've tried slightly editing the code in different ways (e.g. turning the input in a tuple) but I'd like to understand how to get this version working so I know what I'm doing wrong. Could someone show me what's wrong?
The point is that in autocomplete1 and autocomplete2 - set is unordered type so
there is two ways, as I see it, for function to return predictable results:
Sort list after all manipulations will be done (btw there is no need to do list(set(list_name)), you can iterate over set)
If you need specific order you can use OrderedDict
from collections import OrderedDict
l = [1, 1, 2, 3, 4, 5, 5, 2, 1]
result = list(OrderedDict.fromkeys(l))
print(result) # [1, 2, 3, 4, 5]
Full working code is
import ast
import pytest
import re
from collections import OrderedDict
def autocomplete1(str,list_name):
return [i for i in list(OrderedDict.fromkeys(list_name)) if i.startswith(str)]
def autocomplete2(str,list_name):
return(list(filter(lambda x: x.startswith(str), list(OrderedDict.fromkeys(list_name)))))
def autocomplete3(str,list_name):
return([i for i in list_name if re.match(str,i)])
#fix the list
#pytest.mark.parametrize('input1, input2, output1', [('de',['dog','deer','deal'],['deer','deal']), ('ear',['earplug','earphone','airplane'],['earplug','earphone'])])
def test_function(input1,input2,output1):
assert autocomplete1(input1,input2) == output1
assert autocomplete2(input1,input2) == output1
assert autocomplete3(input1,input2) == output1
def lookup_cell(self, column, row):
return(self.puzzle[row-1][column-1])
def lookup_column(self, column):
output = []
for i in range(9):
output.append(self.lookup_cell(column, i+1))
return output
def check_puzzle(self):
valid = True
#check all the rows
for i in range(1,10):
row = self.lookup_row(i)
while 0 in row: row.remove(0)
for i in range(1,10):
if row.count(i) > 1:
valid = False
#check all the columns
for i in range(1,10):
print(i)
print(easy.lookup_column(i))
puzzle = '''0,9,0,7,5,1,0,2,3 /n
2,1,8,6,0,3,7,5,4 /n
0,0,0,4,0,2,0,0,0 /n
1,0,0,0,0,0,0,9,2 /n
0,0,0,5,0,0,3,8,0 /n
3,0,0,8,2,0,5,0,6 /n
0,0,0,0,7,0,0,4,8 /n
0,4,9,0,0,0,0,7,0 /n
0,2,0,0,0,5,6,3,1 '''
easy = Sudoku(puzzle)
Here the code works and prints the columns of the puzzle properly:
for i in range(1,10):
print(easy.lookup_column(i))
when this runs I get an error which I'll add below:
easy.check_puzzle()
1 [9, 2, 4, 1, 5, 3, 7, 4, 2] 2 [7, 1, 2, 9, 3, 8, 4, 9, 5] 3
Traceback (most recent call last):
File "/Users/ellis/Desktop/Sudoku.py", line 121, in <module>
easy.check_puzzle()
File "/Users/ellis/Desktop/Sudoku.py", line 81, in check_puzzle
print(easy.lookup_column(i))
File "/Users/ellis/Desktop/Sudoku.py", line 65, in lookup_column
output.append(self.lookup_cell(column, i+1))
File "/Users/ellis/Desktop/Sudoku.py", line 19, in lookup_cell
return(self.puzzle[row-1][column-1])
IndexError: list index out of range
Your code works outside of the class method because
for i in range(1,10):
print(easy.lookup_column(i))
is not calling
def lookup_cell(self, column, row):
return(self.puzzle[row-1][column-1]
The traceback you posted shows that the code above is causing the issue, where your accessing values in the object that's outside its bounds
I'm not exactly sure what you are trying to accomplish, but why not use a list for puzzle instead of a string?
Try this:
class Sudoku(object):
def __init__(self,puzzle):
self.puzzle = puzzle
print("Inside class; column lookup")
for i in range(1,10):
print('Column {0} ='.format(i),self.lookup_column(i))
self.check_puzzle()
def lookup_cell(self, column, row):
return self.puzzle[row-1][column-1]
def lookup_row(self,row):
output = []
for i in range(9):
output.append(self.lookup_cell(i+1, row))
return output
def lookup_column(self, column):
output = []
for i in range(9):
output.append(self.lookup_cell(column, i+1))
return output
def check_puzzle(self):
valid = True
#check all the rows
for i in range(1,10):
row = self.lookup_row(i)
while 0 in row: row.remove(0)
for i in range(1,10):
if row.count(i) > 1:
valid = False
puzzle = [
[0,9,0,7,5,1,0,2,3],
[2,1,8,6,0,3,7,5,4],
[0,0,0,4,0,2,0,0,0],
[1,0,0,0,0,0,0,9,2],
[0,0,0,5,0,0,3,8,0],
[3,0,0,8,2,0,5,0,6],
[0,0,0,0,7,0,0,4,8],
[0,4,9,0,0,0,0,7,0],
[0,2,0,0,0,5,6,3,1]]
easy = Sudoku(puzzle)
print("Outside class; column lookup")
for i in range(1,10):
print('Column {0} ='.format(i),easy.lookup_column(i))
easy.check_puzzle()
This question already has answers here:
Accessing class variables from a list comprehension in the class definition
(8 answers)
Closed 7 years ago.
I want to have attribute that is shared by and accessible to all instances of a class.
Sample code:
class Test:
code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
code2d = [ [ code[j*3 + i] for i in range(3) ] for j in range(3) ]
def __init__(self):
pass
However, I get error:
NameError: name 'code' is not defined
If I put the lines with code and code2d into init method, all is working properly.
Why this code throws the error?
code is a class variable , and hence when accessing it you need to call - Test.code , you cannot access them using code .
Also, even if you do access them using Test.code , it would still not work, because the value for class variables (default value) is calculated when the class is being defined, so when you try to access Test.code , you would not be able to access Test as it has not been created yet. Example of that -
>>> class Test:
... code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
... code2d = [ [ Test.code[j*3 + i] for i in range(3) ] for j in range(3) ]
... def __init__(self):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in Test
File "<stdin>", line 3, in <listcomp>
File "<stdin>", line 3, in <listcomp>
NameError: name 'Test' is not defined
I am guessing when you put them in the __init__() you are putting them as -
class Test:
def __init__(self):
code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
code2d = [ [ code[j*3 + i] for i in range(3) ] for j in range(3) ]
This would work, because code here is a local variable and hence can be accesed by the other local variables in the __init__() method , though they would not be accessible outside this function.
Maybe, you do not need them as class variables , if you want to have code and code2d for all instances of the class (objects of the class) , you should create instance variable as-
>>> class Test:
... def __init__(self):
... self.code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
... self.code2d = [ [ self.code[j*3 + i] for i in range(3) ] for j in range(3) ]
If you really want code and code2d to be class variables , one way to do it would be to define code2d outside the class Test , example -
class Test:
code = [ 1, 2, 3, 5, 6, 7, 8, 9, 10]
def __init__(self):
pass
Test.code2d = [ [ Test.code[j*3 + i] for i in range(3) ] for j in range(3) ]
Using Python 2.7....
The print thread["Subject"] should return:
please ignore - test2
and
Please ignore - test
It does successfully with this:
def thread_generator(threads):
tz = pytz.timezone('America/Chicago')
POSTS_SINCE_HOURS = 24
now_date = datetime.datetime.now(tz)
time_stamp = now_date - datetime.timedelta(hours=POSTS_SINCE_HOURS)
for thread in threads:
last_post_time = convert_time(thread["LatestPostDate"])
if last_post_time > time_stamp:
print thread["Subject"]
row = {
"url": thread["Url"],
"author_username": thread["Author"]["Username"],
"author_name": thread["Author"]["DisplayName"],
"thread_id": thread["Id"],
"forum_id": thread["ForumId"],
"subject": thread["Subject"],
"created_date": thread["Content"]["CreatedDate"],
"reply_count": thread["ReplyCount"],
"latest_post_date": thread["LatestPostDate"],
"latest_reply_author": thread["LatestForumReplyAuthorId"] }
But, when adding the yield row the print thread["Subject"] does not show Please ignore - test as it should.
def thread_generator(threads):
tz = pytz.timezone('America/Chicago')
POSTS_SINCE_HOURS = 24
now_date = datetime.datetime.now(tz)
time_stamp = now_date - datetime.timedelta(hours=POSTS_SINCE_HOURS)
for thread in threads:
last_post_time = convert_time(thread["LatestPostDate"])
if last_post_time > time_stamp:
print thread["Subject"]
row = {
"url": thread["Url"],
"author_username": thread["Author"]["Username"],
"author_name": thread["Author"]["DisplayName"],
"thread_id": thread["Id"],
"forum_id": thread["ForumId"],
"subject": thread["Subject"],
"created_date": thread["Content"]["CreatedDate"],
"reply_count": thread["ReplyCount"],
"latest_post_date": thread["LatestPostDate"],
"latest_reply_author": thread["LatestForumReplyAuthorId"] }
yield row
Why is this? Please ignore - test should still show with print thread["Subject"]. Makes no sense to me.
UPDATE: How the generators is called
def sanitize_threads(threads):
for thread in thread_generator(threads):
do stuff
thread_batch.append(thread)
return thread_batch
def get_unanswered_threads():
slug = 'forums/threads/unanswered.json?PageSize=100'
status_code, threads = do_request(slug)
if status_code == 200:
threads = threads["Threads"]
thread_batch = sanitize_threads(threads)
database_update(thread_batch)
Have you tried actually calling next() on the resultant generator? If you call the function with yield the same way you call the function without, in the yield case you'll get a generator object as a result. A generator doesn't evaluate what's inside it until you actually require a value of it, which can be done with next(generator).
For example:
>>> def nogen():
... '''Create a list of values 0-3 and print each one as you build the list.'''
... r = []
... for i in range(3):
... print(i)
... r.append(i)
... return r
...
>>> def firstgen():
... '''Create an iterator of values 0-3 and print each one as you yield the value.'''
... for i in range(3):
... print(i)
... yield i
...
>>> a = nogen() # This function is eager and does everything at once.
0
1
2
>>> a
[0, 1, 2]
>>> b = firstgen() # Note there's no output immediately after this line.
>>> list(b) # The output happens as the list coercion causes the generator to execute.
0
1
2
[0, 1, 2]
>>> c = firstgen() # You can also see this a step at a time using `next`
>>> next(c)
0
0
>>> next(c)
1
1
>>> next(c)
2
2
>>> next(c)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration