Kurt Peek Kurt Peek - 3 months ago 9
Python Question

In Python, use a method both as instance and class method

I'm writing a program which plays Tic Tac Toe and has various versions of

ComputerPlayer
, such as the
RandomPlayer
and
THandPlayer
:

class RandomPlayer(ComputerPlayer):
def __init__(self, mark):
super(RandomPlayer, self).__init__(mark=mark)

def get_move(self, board):
moves = board.available_moves()
if moves: # If "moves" is not an empty list (as it would be if cat's game were reached)
return moves[np.random.choice(len(moves))] # Apply random select to the index, as otherwise it will be seen as a 2D array

class THandPlayer(ComputerPlayer):
def __init__(self, mark):
super(THandPlayer, self).__init__(mark=mark)

def get_move(self, board):
moves = board.available_moves()
if moves: # If "moves" is not an empty list (as it would be if cat's game were reached)
for move in moves:
if board.get_next_board(move, self.mark).winner() == self.mark: # Make winning move (if possible)
return move
elif board.get_next_board(move, self.opponent_mark).winner() == self.opponent_mark: # Block opponent's winning move
return move
else:
# return moves[np.random.choice(len(moves))] # This is a repetition of the code in RandomPlayer and is not DRY
randomplayer = RandomPlayer(mark=self.mark)
return randomplayer.get_move(board)
# return RandomPlayer.get_move(board) # This returns an error as "get_move" is an instance method


The
THandPlayer
also selects moves at random if no winning move can be made or an opponent's winning move blocked. Right now I am doing this by creating an instance of
RandomPlayer
and calling
get_move
on it. This could be made more succinct, however, if
get_move
could be made such that it can be interpreted both as a class method and an instance method. Is this possible?

EDIT

To simplify the question, suppose we have two classes,
RandomPlayer
and
OtherPlayer
, both which have an instance method
get_move
:

import numpy as np

class RandomPlayer:
def get_move(self, arr):
return np.random.choice(arr)

class OtherPlayer:
def get_move(self, arr):
if max(arr) > 5:
return max(arr)
else:
randomplayer=RandomPlayer()
return randomplayer.get_move(arr)

arr = np.arange(4)

otherplayer = OtherPlayer()
print otherplayer.get_move(arr)


Is it possible to use
RandomPlayer
's
get_move
method in
OtherPlayer
without creating an instance of
RandomPlayer
?

Answer

It sounds like you're looking for a staticmethod, which has access to neither cls nor self but can be accessed via either:

>>> class Foo:
...     @staticmethod
...     def bar():
...         print('baz')
...         
>>> Foo.bar()
baz
>>> Foo().bar()
baz