Reputation: 11251
I am writing unit tests fro tic-tat-toe on Python. And I have been extremely confused when noticed that my play object doesn't reinstantiate itself every method.
Here what I'm talking about:
def test_satisfactory_field_occupation(self):
play = tictactoe.Play()
play.make_move("+", 1, 1)
self.assertEqual(play.check_satisfaction(1, 1), "Field has been already occupied, try again")
def test_satisfactory_success(self):
play = tictactoe.Play()
self.assertEqual(play.check_satisfaction(1, 1), "Ok")
And I caught exception:
FAIL: test_satisfactory_success (__main__.TestPlay)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/sergei_rudenkov/PycharmProjects/hello_world/tic-tac-toe/tictactoe_test.py", line 23, in test_satisfactory_success
self.assertEqual(play.check_satisfaction(1, 1), "Ok")
AssertionError: 'Field has been already occupied, try again' != 'Ok'
The Play class is:
class Play(object):
game = [['-', '-', '-'],
['-', '-', '-'],
['-', '-', '-']]
move_count = 1
finished = False
def __str__(self):
return "\n".join(map(str, self.game))
def check_finished(self):
result = False
for i in range(2):
if self.game[i][0] == self.game[i][1] == self.game[i][2] != '-':
result = self.game[i][0]
elif self.game[0][i] == self.game[1][i] == self.game[2][i] != '-':
result = self.game[i][0]
if self.game[0][0] == self.game[1][1] == self.game[2][2] != '-':
return self.game[0][0]
elif self.game[0][2] == self.game[1][1] == self.game[2][0] != '-':
return self.game[0][2]
elif not any("-" in row for row in self.game):
return "Draw"
else:
return result
def make_move(self, sign, x, y):
self.game[x][y] = sign
self.move_count += 1
self.finished = self.check_finished()
print self
def check_satisfaction(self, x, y):
try:
x, y = int(x), int(y)
except ValueError:
return "Please enter integers, try again"
if not (0 <= x <= 2 and 0 <= y <= 2):
return "Arguments greater then 2 or less then 0 are not allowed, try again"
if self.game[x][y] != '-':
return "Field has been already occupied, try again"
return "Ok"
def winner(self):
if self.finished == '+':
return "First player (+) has won!"
elif self.finished == '0':
return "Second player (0) has won!"
elif self.finished == 'Draw':
return "The result is draw!"
Please, understand me correctly: I came from java and was considered each method has it's own stack but what I am seeing highly amazes me. Could someone help me to understand what is happening?
Upvotes: 3
Views: 128
Reputation: 610
You are declaring you list "game" as "static". Means that each instance will share the same list. Move the "game" declaration inside the constructor, and then you should be fine.
class Play(object):
def __init__(self):
self.game = [['-', '-', '-'],
['-', '-', '-'],
['-', '-', '-']]
The reason for that is that when you declare the list at class level, that list gets allocated at parsing time, when they generate the "class object", you could access the game list with Play.game. This should already give you an idea of the scope of the game list. Here a simplified example of what is happening with a list declared at class level:
class Play:
game =[0]
p1 = Play()
print p1.game
p1.game[0] =1
p2 = Play()
print p2.game
Upvotes: 4
Reputation:
class Play(object):
def __init__(self):
self.game = [['-', '-', '-'],
['-', '-', '-'],
['-', '-', '-']]
self.move_count = 1
self.finished = False
Make sure you access these member variables using the self.
prefix always in all other methods of the class:
self.game
self.move_count
self.finished
Take a look at the Python tutorial: 9.3.5. Class and Instance Variables.
Upvotes: 4