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?
CodePudding user response:
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...