Python 结构模式匹配 - 将 Object 传递给 case 语句

Python Structural pattern matching - pass Object to case statement

这是我的代码

class BasePlayer:
    @staticmethod
    def walk(direction):
        print(f"I run into {direction}")

class Archer(BasePlayer):
    @staticmethod
    def shoot():
        print("shoot")

class Wizard(BasePlayer):
    @staticmethod
    def cast_spell():
        print("Spell casted")

def play(expr):
    match expr.split():
        case [("Archer" | "Wizard") as player, "walk", ("north" | "south" | "west" | "east") as direction]:
            Archer.walk(direction)
        case ["Archer", "shoot"]:
            Archer.shoot()
        case _:
            raise Exception("Command not working...")

play("Archer walk west")

到目前为止一切正常,但我希望在第一个 case 语句中,我希望这样做更通用,如下所示:

    case [(Archer | Wizard) as player, "walk", ("north" | "south" | "west" | "east") as direction]:
        player.walk(direction)

但是我不能在 case 语句中使用对象(模式不绑定 Archer)。如果我将它保留为字符串,player 将不是 class,而只是一个字符串。

有没有办法让它工作?

首先,exprstr 类型,expr.split() 生成 strlist。您需要将匹配语句的那部分更改为一个函数,该函数将生成您想要实际匹配的类型。

您将(或可能遇到)运行 使用您的通用语句版本的问题的第二部分是 ,其中假定裸名是要进行赋值的变量到,因此需要一个解决方法(有关更多详细信息,请参阅该线程中的答案)。故障演示如下::

>>> match some_expression:
...     case [(Archer | Wizard) as player, "walk", ("north" | "south" | "west" | "east") as direction]:
...         player.walk(direction)
... 
  File "<stdin>", line 2
SyntaxError: name capture 'Archer' makes remaining patterns unreachable

作为一个快速而肮脏的答案,我将做一些懒惰的事情并将子classes作为属性分配给一个空的class(以模拟导入一个包含这些可播放的模块类型,例如可玩单位的 unit 模块)。为实现您想要的 objective 应该做些什么的核心思想可能看起来像这样:

class unit():
    "pretend this is a module"

unit.Wizard = Wizard
unit.Archer = Archer

def parse(expr):
    # Parse the incoming expression to [BasePlayer, str, str, ...]
    # Defaults to BasePlayer for unknown unit type.
    r = expr.split()
    r[0] = getattr(unit, r[0], BasePlayer)
    return r

def play2(expr):          
    match(parse(expr)):  # use the above parse function to parse the expression
        case [(unit.Archer | unit.Wizard) as player, "walk", ("north" | "south" | "west" | "east") as direction]:
            player.walk(direction)
        case [unit.Archer as player, "shoot"]:
            player.shoot()
        case _:
            raise Exception("Command not working...")

正在试用 play2 函数:

>>> play2('Archer walk west')
I run into west
>>> play2('Wizard walk west')
I run into west
>>> play2('Archer shoot')
shoot
>>> play2('Wizard shoot')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in play2
Exception: Command not working...