变更物件的类别

时间:2019-04-25 19:19:34

标签: python class

在国际象棋游戏中,我定义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}')

但是,馈入QueenBishop并不会真正使对象变成Pawn。我认为是因为范围界定

class Chesspiece:
...

class Pawn(ChessPiece):
    def promote()
    ...

class Queen(Chesspiece):
...

如何更改对象的类?

1 个答案:

答案 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')