Python结构模式匹配 - 将对象传递给案例语句

发布于 2025-02-02 13:41:04 字数 981 浏览 2 评论 0原文

这是我到目前为止正常工作的代码

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)

但是我无法在案例语句中使用对象(模式没有模式绑定弓箭手)。如果我将其作为字符串留下,player将不是类,而只是字符串。

有没有办法做这项工作?

this is my code

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")

That works fine so far, but I want in the first case statement, I want so do it more generic like this:

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

However I can not use Objects in the case statements (pattern does not bind Archer). If I leave it as a string, player will not be the class, but also just a string.

Is there a way to make this work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

静若繁花 2025-02-09 13:41:04

首先,expr是类型strexpr.split()生成list> list of str。您需要将比赛语句的那部分更改为将产生您要实际匹配的类型的函数。

问题的第二部分(或可能已经存在)使用的通用语句版本为这个特定的问题,假定裸机是进行分配的变量,因此需要解决方法(有关更多详细信息,请参见该线程中的答案)。故障的演示如下::

>>> 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

作为一个快速而肮脏的答案,我将做懒惰的事情,并将子类作为属性分配给一个空类(以模拟导入包含这些可玩类型的模块,例如单元可播放单元的模块)。应采取什么措施实现所需目标的核心思想可能看起来像这样:

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...

First off, expr is of type str and expr.split() produces a list of str. You will need to change that part of the match statement to a function that will produce the type you want to actually match on.

Second part of the problem you will (or probably have) run into with your version of the generic statement is this particular issue, where the bare name is assumed to be a variable to make assignment to, so a workaround is required (see the answer in that thread for more details). A demonstration of the fault follows::

>>> 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

As a quick and dirty answer, I am going to do the lazy thing and assign the subclasses as attributes to an empty class (to emulate importing a module that contain these playable types, e.g. the unit module for playable units). The core idea of what should be done to achieve your desired objective might look something like this:

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...")

Trying out the play2 function:

>>> 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...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文