在国际象棋游戏中,我定义p1 = Pawn()
。
我希望能够推广它:
def promote(self, piece):
pos = f'{Config.tile_convert(self.x)}{Config.tile_convert(self.y, True)}'
try:
self = piece(pos, color=self.color, num='s')
except NameError:
print(f'Cannot promote {self.pieceid} to {piece}')
但是,馈入Queen
或Bishop
并不会真正使对象变成Pawn
。我认为是因为范围界定
class Chesspiece:
...
class Pawn(ChessPiece):
def promote()
...
class Queen(Chesspiece):
...
如何更改对象的类?
答案 0 :(得分:1)
重新分配任何裸名(包括self
)重新绑定该名称;以前的所有东西都被扔掉了,这个名字现在指向了一个无关的东西。
因此,当您这样做时:
self = piece(pos, color=self.color, num='s')
您只是无法访问“真实的” self
(调用该方法的对象),而不会更改它被调用的对象。
做你想要的事情的唯一方法是有点笨拙。在__class__
上重新分配self
(并更改使其成为新类的有效实例所需的任何其他属性)。
因此,在这种情况下,您也许可以做到:
self.__class__ = piece
,如果可能需要重新创建/重新验证属性值,或者piece
可能是工厂函数或怪异类,而它们的__new__
不一定返回调用的类型,创建一个新模板作为模板,然后从中复制,就像这样:
# Make a new piece to copy from
newpiece = piece(pos, color=self.color, num='s')
vars(self).clear() # Clear out existing attributes
vars(self).update(vars(newpiece)) # Copy attributes from new piece
self.__class__ = newpiece.__class__ # Using newpiece.__class__ ensures it's the resulting class
# in case of factory functions, weird __new__, etc.
注意:这通常是 不是您要执行的操作。与Rocky Li mentions in the comments一样,通常的方法是用任何保存它的结构替换该对象,而不是在现有对象上更新该类,例如如果您有一个名为board
的变量(它是列表的二维列表),则只需执行以下操作:
a_piece = ... # Piece to replace
new_piece_type = ... # Type of piece it's being replaced with
pos = f'{Config.tile_convert(a_piece.x)}{Config.tile_convert(a_piece.y, True)}'
# Replace entire object (and local alias name) at known coordinates with new object
board[a_piece.x][a_piece.y] = a_piece = new_piece_type(pos, color=a_piece.color, num='s')