如何使用 class 类型的匹配大小写
How to use match case with a class type
我想使用 match
根据 class type
确定要执行的操作。我似乎无法弄清楚该怎么做。我知道他们是实现这一目标的其他方式,我只是想知道是否可以通过这种方式完成。我不是在寻找有很多解决方法。
class aaa():
pass
class bbb():
pass
def f1(typ):
if typ is aaa:
print("aaa")
elif typ is bbb:
print("bbb")
else:
print("???")
def f2(typ):
match typ:
case aaa():
print("aaa")
case bbb():
print("bbb")
case _:
print("???")
f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)
输出结果如下:
aaa
bbb
???
???
尝试在 match
行中使用 typ()
而不是 typ
:
class aaa():
pass
class bbb():
pass
def f1(typ):
if typ is aaa:
print("aaa")
elif typ is bbb:
print("bbb")
else:
print("???")
def f2(typ):
match typ():
case aaa():
print("aaa")
case bbb():
print("bbb")
case _:
print("???")
f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)
输出:
aaa
bbb
aaa
bbb
更新:
根据 OP 的评论,要求提供比问题中的示例 classes 更适用于 classes 的解决方案,这里是解决此问题的答案:
class aaa():
pass
class bbb():
pass
def f1(typ):
if typ is aaa:
print("aaa")
elif typ is bbb:
print("bbb")
else:
print("???")
def f2(typ):
match typ.__qualname__:
case aaa.__qualname__:
print("aaa")
case bbb.__qualname__:
print("bbb")
case _:
print("???")
f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)
输出:
aaa
bbb
aaa
bbb
更新#2:
基于 post and some perusal of PEP 364 here,我创建了一个示例来展示一些数据类型(一个 Python 内置,一个来自集合模块的 class,以及一个用户定义的 class)被 match
用于根据 class 类型(或更一般地,数据类型)确定要执行的操作:
class bbb:
pass
class namespacing_class:
class aaa:
pass
def f1(typ):
if typ is aaa:
print("aaa")
elif typ is bbb:
print("bbb")
else:
print("???")
def f2(typ):
match typ.__qualname__:
case aaa.__qualname__:
print("aaa")
case bbb.__qualname__:
print("bbb")
case _:
print("???")
def f3(typ):
import collections
match typ:
case namespacing_class.aaa:
print("aaa")
case __builtins__.str:
print("str")
case collections.Counter:
print("Counter")
case _:
print("???")
'''
f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)
'''
f3(namespacing_class.aaa)
f3(str)
import collections
f3(collections.Counter)
输出:
aaa
str
Counter
如 另一个 post 的回答所述:
A variable name in a case clause is treated as a name capture pattern. It always matches and tries to make an assignment to the variable name. ... We need to replace the name capture pattern with a non-capturing pattern such as a value pattern that uses the . operator for attribute lookup. The dot is the key to matching this a non-capturing pattern.
换句话说,如果我们尝试说 case aaa:
,aaa
将被解释为我们分配主题的名称(您的代码中的 typ
)和将始终匹配并阻止任何匹配后续 case
行的尝试。
为了解决这个问题,对于可以使用点指定的 class 类型名称(或一般名称)(可能是因为它们属于名称空间或另一个 class),我们可以使用带点的名称作为不会被解释为名称捕获的模式。
对于built-in类型str
,我们可以使用case __builtins__.str:
。对于Python的collections
模块中的Counter
class,我们可以使用case collections.Counter:
。如果我们在另一个名为 namespacing_class
的 class 中定义 class aaa
,我们可以使用 case namespacing_class.aaa:
.
但是,如果我们在 Python 代码的顶层定义 class bbb
,我不清楚是否有任何方法可以使用带点的名称来引用到它,从而避免名称捕获。
可能有一种方法可以在 case
行中指定用户定义的 class type
,我只是还没有弄明白。否则,能够对可点类型而不是 non-dottable 类型执行此操作似乎相当武断(并且不幸)。
您想匹配一个常量值。 constant value patterns:
就是这种情况
match typ:
case somemodule.ClassOne:
...
case anothermodule.ClassTwo:
...
常量值模式必须采用 NAME ('.' NAME)+
形式 - 即名称后跟至少一个属性查找。裸名将被视为捕获模式。这对于在其他模块中定义的 类 没问题,但是如果你想匹配同一个模块中的 类,你可以导入当前模块:
# in somemodule.py
import somemodule
class ClassOne:
...
class ClassTwo:
...
match typ:
case somemodule.ClassOne:
...
case somemodule.ClassTwo:
...
或者如果你想避免循环导入,你可以创建一个命名空间:
import types
options = types.SimpleNamespace()
options.ClassOne = ClassOne
options.ClassTwo = ClassTwo
match typ:
case options.ClassOne:
...
case options.ClassTwo:
...
请注意,如果您采用“导入当前模块”路线,则需要注意 Python 的奇怪之处,其中入口点脚本被视为 __main__
模块,无论它的文件名。如果您执行 python somefile.py
并尝试在其中执行 import somefile
,它将执行 somefile.py
的 second 运行 作为 somefile
模块并创建所有 类 的第二个副本,你的匹配语句将不起作用。
我想使用 match
根据 class type
确定要执行的操作。我似乎无法弄清楚该怎么做。我知道他们是实现这一目标的其他方式,我只是想知道是否可以通过这种方式完成。我不是在寻找有很多解决方法。
class aaa():
pass
class bbb():
pass
def f1(typ):
if typ is aaa:
print("aaa")
elif typ is bbb:
print("bbb")
else:
print("???")
def f2(typ):
match typ:
case aaa():
print("aaa")
case bbb():
print("bbb")
case _:
print("???")
f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)
输出结果如下:
aaa
bbb
???
???
尝试在 match
行中使用 typ()
而不是 typ
:
class aaa():
pass
class bbb():
pass
def f1(typ):
if typ is aaa:
print("aaa")
elif typ is bbb:
print("bbb")
else:
print("???")
def f2(typ):
match typ():
case aaa():
print("aaa")
case bbb():
print("bbb")
case _:
print("???")
f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)
输出:
aaa
bbb
aaa
bbb
更新:
根据 OP 的评论,要求提供比问题中的示例 classes 更适用于 classes 的解决方案,这里是解决此问题的答案:
class aaa():
pass
class bbb():
pass
def f1(typ):
if typ is aaa:
print("aaa")
elif typ is bbb:
print("bbb")
else:
print("???")
def f2(typ):
match typ.__qualname__:
case aaa.__qualname__:
print("aaa")
case bbb.__qualname__:
print("bbb")
case _:
print("???")
f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)
输出:
aaa
bbb
aaa
bbb
更新#2:
基于 match
用于根据 class 类型(或更一般地,数据类型)确定要执行的操作:
class bbb:
pass
class namespacing_class:
class aaa:
pass
def f1(typ):
if typ is aaa:
print("aaa")
elif typ is bbb:
print("bbb")
else:
print("???")
def f2(typ):
match typ.__qualname__:
case aaa.__qualname__:
print("aaa")
case bbb.__qualname__:
print("bbb")
case _:
print("???")
def f3(typ):
import collections
match typ:
case namespacing_class.aaa:
print("aaa")
case __builtins__.str:
print("str")
case collections.Counter:
print("Counter")
case _:
print("???")
'''
f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)
'''
f3(namespacing_class.aaa)
f3(str)
import collections
f3(collections.Counter)
输出:
aaa
str
Counter
如
A variable name in a case clause is treated as a name capture pattern. It always matches and tries to make an assignment to the variable name. ... We need to replace the name capture pattern with a non-capturing pattern such as a value pattern that uses the . operator for attribute lookup. The dot is the key to matching this a non-capturing pattern.
换句话说,如果我们尝试说 case aaa:
,aaa
将被解释为我们分配主题的名称(您的代码中的 typ
)和将始终匹配并阻止任何匹配后续 case
行的尝试。
为了解决这个问题,对于可以使用点指定的 class 类型名称(或一般名称)(可能是因为它们属于名称空间或另一个 class),我们可以使用带点的名称作为不会被解释为名称捕获的模式。
对于built-in类型str
,我们可以使用case __builtins__.str:
。对于Python的collections
模块中的Counter
class,我们可以使用case collections.Counter:
。如果我们在另一个名为 namespacing_class
的 class 中定义 class aaa
,我们可以使用 case namespacing_class.aaa:
.
但是,如果我们在 Python 代码的顶层定义 class bbb
,我不清楚是否有任何方法可以使用带点的名称来引用到它,从而避免名称捕获。
可能有一种方法可以在 case
行中指定用户定义的 class type
,我只是还没有弄明白。否则,能够对可点类型而不是 non-dottable 类型执行此操作似乎相当武断(并且不幸)。
您想匹配一个常量值。 constant value patterns:
就是这种情况match typ:
case somemodule.ClassOne:
...
case anothermodule.ClassTwo:
...
常量值模式必须采用 NAME ('.' NAME)+
形式 - 即名称后跟至少一个属性查找。裸名将被视为捕获模式。这对于在其他模块中定义的 类 没问题,但是如果你想匹配同一个模块中的 类,你可以导入当前模块:
# in somemodule.py
import somemodule
class ClassOne:
...
class ClassTwo:
...
match typ:
case somemodule.ClassOne:
...
case somemodule.ClassTwo:
...
或者如果你想避免循环导入,你可以创建一个命名空间:
import types
options = types.SimpleNamespace()
options.ClassOne = ClassOne
options.ClassTwo = ClassTwo
match typ:
case options.ClassOne:
...
case options.ClassTwo:
...
请注意,如果您采用“导入当前模块”路线,则需要注意 Python 的奇怪之处,其中入口点脚本被视为 __main__
模块,无论它的文件名。如果您执行 python somefile.py
并尝试在其中执行 import somefile
,它将执行 somefile.py
的 second 运行 作为 somefile
模块并创建所有 类 的第二个副本,你的匹配语句将不起作用。