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

发布于 2025-01-13 07:40:42 字数 574 浏览 4 评论 0原文

我想使用 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)

输出如下:

aaa
bbb
???
???

I want to use match to determine an action to perform based on a class type. I cannot seem to figure out how to do it. I know their are other ways of achieving this, I would just like to know can it be done this way. I am not looking for workarounds of which there are many.


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)

The output is as follows:

aaa
bbb
???
???

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

初雪 2025-01-20 07:40:42

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

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并尝试在其中导入somefile,它将执行第二次运行somefile.py< /code> 作为 somefile 模块并创建所有类的第二个副本,并且您的 match 语句将不起作用。

You want to match against a constant value. That's a case for constant value patterns:

match typ:
    case somemodule.ClassOne:
        ...
    case anothermodule.ClassTwo:
        ...

Constant value patterns must be of the form NAME ('.' NAME)+ - that is, a name followed by at least one attribute lookup. A bare name will be considered a capture pattern. That's fine for classes defined in other modules, but if you want to match against classes in the same module, you can import the current module:

# in somemodule.py
import somemodule

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

match typ:
    case somemodule.ClassOne:
        ...
    case somemodule.ClassTwo:
...

or if you want to avoid the circular import, you can create a namespace:

import types

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

match typ:
    case options.ClassOne:
        ...
    case options.ClassTwo:
        ...

Note that if you go the "import the current module" route, you need to be aware of Python's weird thing where the entry point script is considered the __main__ module, regardless of its file name. If you do python somefile.py and try to import somefile inside that, it will perform a second run of somefile.py as the somefile module and create a second copy of all your classes, and your match statements won't work.

回心转意 2025-01-20 07:40:42

尝试在 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 的评论询问对于比问题中的示例类更普遍地适用于类的解决方案,这里有一个解决此问题的答案:

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:
基于 这篇 文章以及对 PEP 364 此处,我创建了一个示例,展示了一些数据类型(Python match 可以使用内置类、集合模块中的类和用户定义的类来根据类类型(或更一般地说,数据类型)确定要执行的操作:

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

正如另一篇文章中的这个答案所述:

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

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

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

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

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

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

Try using typ() instead of typ in the match line:

        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)        

Output:

aaa
bbb
aaa
bbb

UPDATE:

Based on OP's comment asking for solution that works for classes more generally than the example classes in the question, here is an answer addressing this:

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)

Output:

aaa
bbb
aaa
bbb

UPDATE #2:
Based on this post and some perusal of PEP 364 here, I have created an example showing how a few data types (a Python builtin, a class from the collections module, and a user defined class) can be used by match to determine an action to perform based on a class type (or more generally, a data type):

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)

Outputs:

aaa
str
Counter

As stated in this answer in another 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.

In other words, if we try to say case aaa: for example, aaa will be interpreted as a name to which we assign the subject (typ in your code) and will always match and block any attempts to match subsequent case lines.

To get around this, for class type names (or names generally) that can be specified using a dot (perhaps because they belong to a namespace or another class), we can use the dotted name as a pattern that will not be interpreted as a name capture.

For built-in type str, we can use case __builtins__.str:. For the Counter class in Python's collections module, we can use case collections.Counter:. If we define class aaa within another class named namespacing_class, we can use case namespacing_class.aaa:.

However, if we define class bbb at the top level within our Python code, it's not clear to me that there is any way to use a dotted name to refer to it and thereby avoid name capture.

It's possible there's a way to specify a user defined class type in a case line and I simply haven't figured it out yet. Otherwise, it seems rather arbitrary (and unfortunate) to be able to do this for dottable types and not for non-dottable ones.

ゃ人海孤独症 2025-01-20 07:40:42

在相关情况下使用 if 防护怎么样?

class aaa():
    pass

class bbb():
    pass

def f(typ):
    match typ:
        case aaa():
            print("aaa instance")
        case bbb():
            print("bbb instance")
        case _aaa if _aaa is aaa:
            print("aaa class")
        case _bbb if _bbb is bbb:
            print("bbb class")
        case _:
            print("???")

f(aaa())
f(bbb())
f(aaa)
f(bbb)
# output:
aaa instance
bbb instance
aaa class
bbb class

参考:请参阅 PEP 的向模式添加条件部分636.

How about using an if guard in the relevant cases?

class aaa():
    pass

class bbb():
    pass

def f(typ):
    match typ:
        case aaa():
            print("aaa instance")
        case bbb():
            print("bbb instance")
        case _aaa if _aaa is aaa:
            print("aaa class")
        case _bbb if _bbb is bbb:
            print("bbb class")
        case _:
            print("???")

f(aaa())
f(bbb())
f(aaa)
f(bbb)
# output:
aaa instance
bbb instance
aaa class
bbb class

Reference: See the Adding conditions to patterns section of PEP 636.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文