就在之前10月,Python 3.10 正式发布了,我发现了一个可怕的功能......

Posted 不想秃头的晨晨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了就在之前10月,Python 3.10 正式发布了,我发现了一个可怕的功能......相关的知识,希望对你有一定的参考价值。

在之前10月,Python 3.10 正式发布了,我发现了一个可怕的功能......

就在之前( 2021年10月4日) Python 终于正式发布了 3.10 版本,看了下这个版本的一些特性,最受关注的应该就是结构模式匹配了吧?也就是大家所熟悉的 match-case 。
下边是最简单的一个 match-case 的例子,看起来是不是非常的直观简洁?

def http_error(status):
    match status:
        case 400:
            print("Bad request")
        case 404:
            print("Not found")
        case 418:
            print("I'm a teapot")
        case _:
            print("Something's wrong with the internet")

对这个功能满怀期待的我,赶紧就下载升级了 3.10 的 Python 赶紧试用,可没想到在我深入的体验过后,我从最开始的期待,变成了敬畏。

敬畏,是因为这样一个看似简单的新功能,却有着不少的学习成本,并且对结构模式匹配半知半解的人来说,会增大代码出错的概率,并不是大数人都能轻松驾驭的。

为什么会这么说呢?在文章最后来简述观点。

鉴于大多数人,都没有实际用过这种 结构模式匹配,会从 升级 3.10 开始教大家如何尝鲜这个新功能,然后会详细的介绍 match-case 的使用方法。

1. 升级 3.10 新版本

本机的电脑上目前的 Python 版本是 3.9.1 的

$ /usr/local/bin/python3 --version
Python 3.9.1

由于这边使用的是 mac,因此从官网上下载的是 Python 3.10 的 pkg 文件,如果是 win 的用户,可以下载相应的 msi 或者 exe 文件。

下载链接我贴在下边,可以直接访问下载

mac: https://www.python.org/ftp/python/3.10.0/python-3.10.0-macos11.pkg
win: https://www.python.org/ftp/python/3.10.0/python-3.10.0-amd64.exe

下载好安装文件后,双击安装,之后就双击下载的 pkg 文件,进入安装流程

一路点击继续,该同意的同意一下,出现如下提示表示安装成功。
再次在终端上确认下是否升级成功

2.or模式的使用

在上面我已经贴出一个 match-case 的最简单示例,这边就直接跳过简单示例,来说说那些比较特殊的用法。

在 Python 3.10 中其实有新增一个 联合类型操作符|,但这个只能用于类型,具体的用法,我会在下一篇文章中做详细的介绍,本篇文章还是集中于 match-case 的使用。

在学习match-case 的时候,你会发现,也有一个类似于联合类型操作符的用法,但请你要注意区别,它并不是联合类型操作,而是在 match-case 下独有的 or模式操作符|,它可以将多个具体相同逻辑的 case 语句简写成同一个

match status:
    case 401 | 403 | 404:
        print("Not allowed")
    case _:
        print("Something's wrong with the internet")

3. 通配符匹配任意对象

match-case 的出现有利于提高代码的可读性,让你的代码更加优雅,但同时要使用好它,也是有一些门槛的,特别是通配符的使用。

下边我举一些例子来进行讲解

在如下代码中,使用了通配符_ 和 可变参数中的*符号

import sys

match sys.argv[1:]:
    case ["quit"]:
        print("exit")
    case ["create", user]:     # 创建单个用户
        print("create", user)
    case ["create", *users]:  # 批量创建多个用户
        for user in users:
            print("create", user)
    case _:
        print("Sorry, I couldn't understand the argv")

最后一个 case 中的_并不作为变量名,而表示一种特殊的模式,在前面的 case 中都未命中的情况下,该 case 会是最后的保障,能确保命中,它相当于 Go 语言中的default分支。

import "fmt"

func main() 
    education := "本科"

    switch education 
    case "博士":
        fmt.Println("我是博士")
    case "研究生":
        fmt.Println("我是研究生")
    case "本科":
        fmt.Println("我是本科生")
    case "大专":
        fmt.Println("我是大专生")
    default:
        fmt.Println("学历未达标..")
    

4.使用可变参数*args

第二个 case 和 第三个 case 非常的像,区别在于第三个 case中users前加了个*,他跟原 Python 函数中的可变参数是一个用法,会匹配列表的多个值。

在该中表示可以从命令行参数中批量创建用户。
在 match-case 中相应的 case 若有运行到,对应的变量是会被创建的。比如

5. 使用可变参数**kv

在如下代码中,**rest会匹配到所有的 args 中的 key 和 value

  • 长度的匹配方式#
    若你希望使用 case 仅对对象的长度做一些匹配,可以使用下面这样的方式
  • [*_] 匹配任意长度的list;
  • (_, _, *_) 匹配长度至少为 2 的tuple

7. 类对象的匹配

对于类对象的匹配,下边这个例子足够简单

8. 匹配要注意顺序

在上边基本介绍完了 match-case 的使用方法,如需更详细的内容,不如去通读下pep 636 的内容

开发者应该对这些新特性心存敬畏,match-case 这样一个看似简单的新功能,却有着不少的学习成本,如果对结构模式匹配半知半解的人来说,可能会增大代码出错的概率,并不是大数人都能轻松驾驭的。

之所以会这么说,是因为 match-case 在面对不同的对象,它的匹配的规则也有所不同。

  • 当 match 的对象是一个 list 或者 tuple 的时候,需要长度和元素值都能匹配,才能命中,这就是为什么下面这个例子走的是第三个 case 而不是第二个 case。
  • 当 match 的对象是一个 dict 的时候,规则却有所不同,只要 case 表达式中的 key 在所 match 的对象中有存在,即可命中。
  • 而当 match 的对象是类对象时,匹配的规则是,跟 dict 有点类似,只要对象类型和对象的属性有满足 case 的条件,就能命中。

    因此在写 match-case 的时候,最大的难点可能就是如何把握这个顺序,才能确保你写的代码不会翻车。

个人总结一些规律,仅供大家参考:

  • list 或者 tuple:应该从不格式到严格
  • dict 或者 object:应该从严格到不严格

建议大家在充分了解match-case匹配规则后,再去使用它。

另外,这个功能一出,有许多人表示终于来了,也有一些人表示太鸡肋了。

对于此事的看法是,match-case 必然有一定的适用场景,但这不意味着 match-case 是必要的,所有的 match-case 都可以换成 if 表达式,但反过来却不然,if 可以结合 and 和 or 承接 n 个多复杂的组合判断,但 match-case 却不行,它只能用于单个对象进行匹配判断。

但是从一定程度上来说,它有点多余,而且有一定的上手成本。

那么对于这样的一个 新特性,你会用它吗?

最后,感谢您的阅读。您的每个点赞、留言、分享都是对我们最大的鼓励,笔芯~

如有疑问,欢迎在评论区一起讨论!

以上是关于就在之前10月,Python 3.10 正式发布了,我发现了一个可怕的功能......的主要内容,如果未能解决你的问题,请参考以下文章

刚刚,Python 3.10 正式发布了!我发现了一个可怕的功能...

刚刚,Python 3.10 正式发布了!我发现了一个可怕的功能...

刚刚,Python 3.10 正式发布了!我发现了一个可怕的功能...

利用Conda尝鲜Python 3.10

Python 3.10 版本 match-case 尝鲜体验!

Python 3.10 正式发布,新增模式匹配,同事用了直呼真香!