[英]In Python, use a method both as instance and class method
我正在编写一个播放Tic Tac Toe并具有各种版本的ComputerPlayer
,例如RandomPlayer
和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
如果无法进行获胜动作或对手的获胜动作被阻止, THandPlayer
也会随机选择动作。 现在,我通过创建RandomPlayer
实例并在其上调用get_move
来实现此目的。 但是,如果可以将get_move
设置为可以同时解释为类方法和实例方法,则可以使其更加简洁。 这可能吗?
编辑
为了简化这个问题,假设我们有两个类, RandomPlayer
和OtherPlayer
,它们都有一个实例方法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)
是否有可能使用RandomPlayer
的get_move
的方法OtherPlayer
而无需创建实例RandomPlayer
?
听起来您正在寻找一种staticmethod
,该方法无法访问cls
或self
但可以通过以下任一方法进行访问:
>>> class Foo:
... @staticmethod
... def bar():
... print('baz')
...
>>> Foo.bar()
baz
>>> Foo().bar()
baz
随机移动是一种特定类型的移动。 在ComputerPlayer
放置一个生成一个的方法; 然后RandomPlayer
和THandPlayer
都可以根据需要调用它。
class ComputerPlayer(...):
@staticmethod
def choose_random_move(moves):
if moves:
return moves[np.random.choice(len(moves))]
class RandomPlayer(ComputerPlayer):
def get_move(self, board):
moves = board.available_moves()
if moves:
return self.choose_random_move(moves)
class THandPlayer(ComputerPlayer):
def get_move(self, board):
moves = board.available_moves()
for move in moves:
for mark in [self.mark, self.opponent_mark]:
if board.get_next_board(move, mark).winner() == mark:
return move
else:
return self.choose_random_move(moves)
一些额外的注意事项:
如果您的__init__
方法除了调用super
并传递完全相同的参数之外什么也不做,请不要实现它;否则,请执行它。 只需直接调用继承的方法即可。
可以重构赢家的两张支票。
choose_random_move
不一定需要是静态方法; 您可以将其保留为具有默认实现的实例方法,该实现在选择举动时会忽略任何特定于玩家的信息。 派生类可以根据需要重写该方法。
(这是我的其他答案的替代方法,使用了不同的抽象。)
随机移动与玩家无关,而与棋盘相关。 就像board.available_moves
一样,但是返回单个动作而不是所有动作。
class Board(...):
# Given how often this is called by or before
# random_move(), it would be smart to implement
# some kind of caching so that the available
# moves don't have to be recalcuated for the same board
# state every time it is called.
def available_moves(self):
...
def random_move(self):
moves = self.available_moves()
if moves:
return moves[np.random.choice(len(moves))]
class RandomPlayer(ComputerPlayer):
def get_move(self, board):
return board.random_move()
class THandPlayer(ComputerPlayer):
def get_move(self, board):
moves = board.available_moves()
if moves:
for move in moves:
if board.get_next_board(move, self.mark).winner() == self.mark:
return move
elif board.get_next_board(move, self.opponent_mark).winner() == self.opponent_mark:
return move
else:
return board.random_move()
为了完整起见,这是我对deceze建议的解决方案的实现 ,其中我还遵循chepner的建议来重构这两个布尔语句:
class RandomPlayer(ComputerPlayer):
def __init__(self, mark):
super(RandomPlayer, self).__init__(mark=mark)
@staticmethod
def get_move(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 selection 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:
for move in moves:
if THandPlayer.next_move_winner(board, move, self.mark):
return move
elif THandPlayer.next_move_winner(board, move, self.opponent_mark):
return move
else:
return RandomPlayer.get_move(board)
@staticmethod
def next_move_winner(board, move, mark):
return board.get_next_board(move, mark).winner() == mark
静态方法既可用于默认使用随机播放器,也可用于重构布尔语句。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.