[英]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.