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,而只是一个字符串。
有没有办法让它工作?
首先,expr
是 str
类型,expr.split()
生成 str
的 list
。您需要将匹配语句的那部分更改为一个函数,该函数将生成您想要实际匹配的类型。
您将(或可能遇到)运行 使用您的通用语句版本的问题的第二部分是 ,其中假定裸名是要进行赋值的变量到,因此需要一个解决方法(有关更多详细信息,请参阅该线程中的答案)。故障演示如下::
>>> 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...
这是我的代码
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,而只是一个字符串。
有没有办法让它工作?
首先,expr
是 str
类型,expr.split()
生成 str
的 list
。您需要将匹配语句的那部分更改为一个函数,该函数将生成您想要实际匹配的类型。
您将(或可能遇到)运行 使用您的通用语句版本的问题的第二部分是
>>> 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...