如何将大小写与类类型一起使用

pau*_*are 10 python types class case match

我想用来match确定基于类执行的操作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)
Run Code Online (Sandbox Code Playgroud)

输出如下:

aaa
bbb
???
???
Run Code Online (Sandbox Code Playgroud)

con*_*ger 6

尝试使用typ()而不是typ在行中match

        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)        
Run Code Online (Sandbox Code Playgroud)

输出:

aaa
bbb
aaa
bbb
Run Code Online (Sandbox Code Playgroud)

更新:

根据OP的评论,要求提供比问题中的示例类更普遍的类解决方案,以下是解决此问题的答案:

aaa
bbb
aaa
bbb
Run Code Online (Sandbox Code Playgroud)

输出:

aaa
bbb
aaa
bbb
Run Code Online (Sandbox Code Playgroud)

更新#2: 基于这篇文章和matchPEP 364 的一些阅读,我创建了一个示例,展示了如何使用一些数据类型(Python 内置、集合模块中的类和用户定义的类)根据类类型(或更一般地说,数据类型)确定要执行的操作:

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)
Run Code Online (Sandbox Code Playgroud)

输出:

aaa
str
Counter
Run Code Online (Sandbox Code Playgroud)

正如另一篇文章中的回答所述:

case 子句中的变量名称被视为名称捕获模式。它始终匹配并尝试对变量名称进行赋值。...我们需要将名称捕获模式替换为非捕获模式,例如使用. 用于属性查找的运算符。点是匹配非捕获模式的关键。

换句话说,如果我们尝试说,case aaa:例如,aaa将被解释为我们分配主题的名称(typ在您的代码中),并且将始终匹配并阻止任何匹配后续case行的尝试。

为了解决这个问题,对于可以使用点指定的类类型名称(或通常的名称)(可能因为它们属于命名空间或另一个类),我们可以使用点名称作为不会被解释为名称捕获。

对于内置类型str,我们可以使用case __builtins__.str:. 对于CounterPythoncollections模块中的类,我们可以使用case collections.Counter:. 如果我们aaa在另一个名为 的类中定义类namespacing_class,我们可以使用case namespacing_class.aaa:.

但是,如果我们bbb在 Python 代码中的顶层定义类,我不清楚是否有任何方法可以使用点名称来引用它,从而避免名称捕获。

可能有一种方法可以type在一行中指定用户定义的类case,但我还没有弄清楚。否则,能够对可点类型而不是非可点类型执行此操作似乎相当任意(并且不幸)。

  • 谢谢。你是对的,我不喜欢它,但非常感谢你的回答及其完整性。我想我可能会坚持使用 ifs 和 elifs 来对抗类型。 (2认同)

use*_*ica 6

您想要匹配一个常量值。这是恒定值模式的情况:

match typ:
    case somemodule.ClassOne:
        ...
    case anothermodule.ClassTwo:
        ...
Run Code Online (Sandbox Code Playgroud)

常量值模式必须采用以下形式NAME ('.' NAME)+:即名称后跟至少一个属性查找。裸名称将被视为捕获模式。这对于其他模块中定义的类来说很好,但是如果您想与同一模块中的类匹配,您可以导入当前模块:

# in somemodule.py
import somemodule

class ClassOne:
    ...
class ClassTwo:
    ...

match typ:
    case somemodule.ClassOne:
        ...
    case somemodule.ClassTwo:
...
Run Code Online (Sandbox Code Playgroud)

或者如果你想避免循环导入,你可以创建一个命名空间:

import types

options = types.SimpleNamespace()
options.ClassOne = ClassOne
options.ClassTwo = ClassTwo

match typ:
    case options.ClassOne:
        ...
    case options.ClassTwo:
        ...
Run Code Online (Sandbox Code Playgroud)

请注意,如果您选择“导入当前模块”路线,则需要注意 Python 的奇怪之处,即入口点脚本被视为模块__main__,而不管其文件名如何。如果您这样做python somefile.py并尝试import somefile进入其中,它将作为模块执行第二次运行并创建所有类的第二个副本,并且您的匹配语句将不起作用。somefile.pysomefile