Reputation: 2088
I'm trying to use SPM to determine if a certain type is an int
or an str
.
The following code:
from typing import Type
def main(type_to_match: Type):
match type_to_match:
case str():
print("This is a String")
case int():
print("This is an Int")
case _:
print("\nhttps://en.meming.world/images/en/0/03/I%27ve_Never_Met_This_Man_In_My_Life.jpg")
if __name__ == "__main__":
test_type = str
main(test_type)
returns https://en.meming.world/images/en/0/03/I%27ve_Never_Met_This_Man_In_My_Life.jpg
Most of the documentation I found talks about how to test if a certain variable is an instance of a type. But not how to test if a type is of a certain type.
Any ideas on how to make it work?
Upvotes: 11
Views: 19347
Reputation: 973
The accepted answer gives a good solution for simple built in types (like str and int), but that doesn't work for lists, as their type is, for instance list[str]
, so a direction match with builtins.list
is False. This works:
import typing
def test(self, type_: typing.Type):
match typing.get_origin(type_) or type_: # for instance str[int]->str, and or for str->str
case builtins.bool:
print('This is a bool')
case builtins.str:
print('This is a str')
case builtins.int:
print('This is an int')
case builtins.float:
print('This is a float')
case td if typing.is_typeddict(type_):
print('This is a TypedDict')
case builtins.dict:
print('This is a dict')
case builtins.list:
print('This is a list')
case _:
print(f'({type_}) unmatched')
Upvotes: 0
Reputation: 308
One option is to grab the type name and match on that instead of on the type directly:
from typing import Type
def main(type_to_match: Type):
match type_to_match.__name__:
case 'str':
print("This is a String")
case 'int':
print("This is an Int")
case _:
print("\nhttps://en.meming.world/images/en/0/03/I%27ve_Never_Met_This_Man_In_My_Life.jpg")
if __name__ == "__main__":
test_type = str
main(test_type)
Upvotes: 2
Reputation: 19403
As its name suggests, structural pattern matching is more suited for matching patterns, not values (like a classic switch/case
in other languages). For example, it makes it very easy to check different possible structures of a list or a dict, but for values there is not much advantage over a simple if/else
structure:
if type_to_match == str:
print("This is a String")
elif type_to_match == int:
print("This is an Int")
else:
print("\nhttps://en.meming.world/images/en/0/03/I%27ve_Never_Met_This_Man_In_My_Life.jpg")
But if you really want to use SPM, you could use the guard feature along with issublcass
to check if a type is or is a child of any other:
match type_to_match:
case s if issubclass(type_to_match, str):
print(f"{s} - This is a String")
case n if issubclass(type_to_match, int):
print(f"{n} - This is an Int")
case _:
print("\nhttps://en.meming.world/images/en/0/03/I%27ve_Never_Met_This_Man_In_My_Life.jpg")
Upvotes: 6
Reputation: 565
If you just pass a type directly, it will consider it to be a "name capture" rather than a "value capture." You can coerce it to use a value capture by importing the builtins
module, and using a dotted notation to check for the type.
import builtins
from typing import Type
def main(type_: Type):
match (type_):
case builtins.str: # it works with the dotted notation
print(f"{type_} is a String")
case builtins.int:
print(f"{type_} is an Int")
case _:
print("\nhttps://en.meming.world/images/en/0/03/I%27ve_Never_Met_This_Man_In_My_Life.jpg")
if __name__ == "__main__":
main(type("hello")) # <class 'str'> is a String
main(str) # <class 'str'> is a String
main(type(42)) # <class 'int'> is an Int
main(int) # <class 'int'> is an Int
Upvotes: 22