Skip to content

Instantly share code, notes, and snippets.

@KuRRe8
Last active June 22, 2025 09:09
Show Gist options
  • Select an option

  • Save KuRRe8/36f63d23ef205a8e02b7b7ec009cc4e8 to your computer and use it in GitHub Desktop.

Select an option

Save KuRRe8/36f63d23ef205a8e02b7b7ec009cc4e8 to your computer and use it in GitHub Desktop.
和Python使用有关的一些教程,按类别分为不同文件

Python教程

Python是一个新手友好的语言,并且现在机器学习社区深度依赖于Python,C++, Cuda C, R等语言,使得Python的热度稳居第一。本Gist提供Python相关的一些教程,可以直接在Jupyter Notebook中运行。

  1. 语言级教程,一般不涉及初级主题;
  2. 标准库教程,最常见的标准库基本用法;
  3. 第三方库教程,主要是常见的库如numpy,pytorch诸如此类,只涉及基本用法,不考虑新特性

其他内容就不往这个Gist里放了,注意Gist依旧由git进行版本控制,所以可以git clone 到本地,或者直接Google Colab\ Kaggle打开相应的ipynb文件

直接在网页浏览时,由于没有文件列表,可以按Ctrl + F来检索相应的目录,或者点击下面的超链接。

想要参与贡献的直接在评论区留言,有什么问题的也在评论区说 ^.^

目录-语言部分

目录-库部分

目录-具体业务库部分-本教程更多关注机器学习深度学习内容

目录-附录

Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Python 描述符

描述符是实现了__get__ __set__ __delete__其中任一方法的类型对象,根据是否有__set__区别是否为数据描述符。

class DataDesc:
    def __get__(self, obj, objtype=None):
        return 'data'
    def __set__(self, obj, value):
        pass

class NonDataDesc:
    def __get__(self, obj, objtype=None):
        return 'nondata'

class C:
    a = DataDesc()
    b = NonDataDesc()
    c = 42
    d = NonDataDesc()

obj = C()
obj.a = 'inst_a'
obj.b = 'inst_b'
obj.c = 'inst_c'
# d 没有实例属性,直接访问

print(obj.a)  # 'data'(数据描述符优先)
print(obj.b)  # 'inst_b'(实例属性优先)
print(obj.c)  # 'inst_c'(实例属性优先)
print(obj.d)  # 'nondata'(非数据描述符被触发)

由此,我们有以下总结:

  1. 描述符必须是type类型的成员,也就是class定义的内部成员(或者通过type(,,)动态定义的类型)
  2. 通过类名可访问描述符C.a,也可以通过实例对象访问obj.a,而实例对象访问时候会有以下查找顺序:
    1. 无论obj.__dict__中是否有a,优先查找C.__dict__中的数据描述符。
    2. 如果没有1那么回退到访问obj.dict__该名称a的普通对象(当obj只有__slot__时候转而查找__slot)
    3. 如果没有2则查找C.__dict__的非数据描述符
    4. 如果没有3则返回C.__dict__中名为a的普通对象
    5. 如果没有4则报错
  3. 注意上述数据中的第三条,平时在class中使用def定义的都是function类型的实例,其实现了__get__方法,所以在obj调用实例方法obj.foo时候(此时obj.__dict__自然没有覆盖obj.foo的项),会访问function的描述符协议,导致其访问内容变为bound method而不是function。这也是为什么直接通过类名和实例名访问函数时候的行为不一样。 特别的,内建的staticmethod和classmethod都是实现了__get__的装饰器,所以访问这些方法时候都会按描述符协议去访问。
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Python 结构化模式匹配 (PEP 634, 635, 636) - Python 3.10+ 教程\n",
"\n",
"欢迎来到 Python 3.10+ 中引入的强大特性——结构化模式匹配的教程!这个特性,通常简称为“模式匹配”,提供了一种更富有表现力、更简洁的方式来处理复杂的数据结构,可以替代一系列嵌套的 `if/elif/else` 语句或复杂的字典/列表解析。\n",
"\n",
"**核心语法:`match` 和 `case`**\n",
"\n",
"```python\n",
"match subject:\n",
" case <pattern_1>:\n",
" # action_1\n",
" case <pattern_2>:\n",
" # action_2\n",
" case <pattern_3> if <guard_condition>:\n",
" # action_3 (if guard is true)\n",
" case _: # 通配符,匹配任何未被前面case捕获的内容 (可选)\n",
" # default_action\n",
"```\n",
"\n",
"**关键点:**\n",
"\n",
"1. **主题 (Subject)**:`match` 关键字后面的表达式,即我们要匹配的值。\n",
"2. **模式 (Pattern)**:`case` 关键字后面的部分。模式可以很简单(如字面量)也可以很复杂(如包含变量捕获、类型检查、结构解包等)。\n",
"3. **匹配过程**:Python 会按顺序尝试将 `subject` 与每个 `case` 的 `pattern` 进行匹配。第一个成功匹配的 `case` 块将被执行,然后 `match` 语句结束(没有像C语言 `switch` 那样的“fall-through”行为)。\n",
"4. **守卫 (Guard)**:`if <condition>` 子句,附加在 `case` 模式之后。只有当模式匹配成功 **并且** 守卫条件为真时,该 `case` 块才会执行。\n",
"5. **通配符 (`_`)**:一个特殊的模式,可以匹配任何东西,但不会绑定到任何名称。通常用作最后一个 `case` 来处理所有未匹配的情况。\n",
"\n",
"**本教程将涵盖各种模式类型:**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. 字面量模式 (Literal Patterns)\n",
"\n",
"匹配精确的字面量值,如数字、字符串、`True`, `False`, `None`。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def http_status_description(status_code):\n",
" match status_code:\n",
" case 200:\n",
" return \"OK\"\n",
" case 400:\n",
" return \"Bad Request\"\n",
" case 404:\n",
" return \"Not Found\"\n",
" case 500:\n",
" return \"Internal Server Error\"\n",
" case _:\n",
" return \"Unknown status code\"\n",
"\n",
"print(f\"200: {http_status_description(200)}\")\n",
"print(f\"404: {http_status_description(404)}\")\n",
"print(f\"301: {http_status_description(301)}\")\n",
"\n",
"def process_command(command):\n",
" match command:\n",
" case \"start\":\n",
" print(\"Starting process...\")\n",
" case \"stop\":\n",
" print(\"Stopping process...\")\n",
" case \"restart\":\n",
" print(\"Restarting process...\")\n",
" case _:\n",
" print(f\"Unknown command: {command}\")\n",
"\n",
"process_command(\"start\")\n",
"process_command(\"pause\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. 捕获模式 (Capture Patterns) 和通配符模式 (Wildcard Pattern)\n",
"\n",
"* **捕获模式 (变量名)**:如果一个模式是一个未加点的标识符(例如 `x`),它会匹配任何值,并将该值绑定到这个名称上。\n",
"* **通配符模式 (`_`)**:匹配任何值,但不绑定到任何名称。用于忽略某个部分。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def describe_value(value):\n",
" match value:\n",
" case 0:\n",
" print(\"Value is zero.\")\n",
" case x if isinstance(x, int) and x > 0:\n",
" print(f\"Value is a positive integer: {x}\") # x 被捕获\n",
" case y if isinstance(y, str):\n",
" print(f\"Value is a string: '{y}' of length {len(y)}\") # y 被捕获\n",
" case _:\n",
" print(f\"Value is something else: {value}\") # _ 匹配但不捕获\n",
"\n",
"describe_value(0)\n",
"describe_value(42)\n",
"describe_value(\"hello\")\n",
"describe_value([1, 2, 3])\n",
"\n",
"point = (10, 20, 30)\n",
"match point:\n",
" case (x, y, _): # 捕获 x 和 y,忽略第三个元素\n",
" print(f\"2D projection: x={x}, y={y}\")\n",
" case _:\n",
" print(\"Not a 3-tuple starting point or something else\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**注意:** 捕获模式的名称不能是 `_` 或其他关键字。如果模式是 `some.attribute`,它被视为值模式 (Value Pattern),而不是捕获模式。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. 值模式 (Value Patterns) 或 点号查找 (Dotted Lookups)\n",
"\n",
"匹配一个具名常量或枚举成员的值。模式看起来像一个点号路径,如 `Color.RED` 或 `math.pi`。\n",
"Python 会计算这个表达式的值,并尝试将 `subject` 与该计算结果进行比较。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from enum import Enum\n",
"import math\n",
"\n",
"class Color(Enum):\n",
" RED = 1\n",
" GREEN = 2\n",
" BLUE = 3\n",
"\n",
"def get_color_meaning(color: Color):\n",
" match color:\n",
" case Color.RED: # 值模式\n",
" return \"Passion, Danger\"\n",
" case Color.GREEN:\n",
" return \"Nature, Growth\"\n",
" case Color.BLUE:\n",
" return \"Calm, Sky\"\n",
" case _:\n",
" return \"Unknown color\"\n",
"\n",
"print(f\"Meaning of RED: {get_color_meaning(Color.RED)}\")\n",
"print(f\"Meaning of BLUE: {get_color_meaning(Color.BLUE)}\")\n",
"\n",
"MY_CONSTANT = \"special_value\"\n",
"\n",
"def check_constant(val):\n",
" match val:\n",
" case MY_CONSTANT: # 必须是点号查找或已定义的常量名\n",
" print(f\"'{val}' matches MY_CONSTANT\")\n",
" # case my_constant: # 这会是捕获模式,而不是值模式!\n",
" # print(f\"'{val}' captured by my_constant (value: {my_constant})\")\n",
" case _:\n",
" print(f\"'{val}' does not match MY_CONSTANT\")\n",
"\n",
"check_constant(\"special_value\")\n",
"check_constant(\"other_value\")\n",
"\n",
"class Constants:\n",
" PI_APPROX = 3.14\n",
"\n",
"def check_pi(val):\n",
" match val:\n",
" case Constants.PI_APPROX:\n",
" print(f\"{val} is approximately pi.\")\n",
" case math.pi:\n",
" print(f\"{val} is math.pi.\") # 也可以匹配模块级常量\n",
" case _:\n",
" print(f\"{val} is not a known pi value.\")\n",
"\n",
"check_pi(3.14)\n",
"check_pi(math.pi)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**重要区分**:\n",
"* `case x:` - `x` 是一个捕获变量,它会匹配并绑定 `subject` 的值。\n",
"* `case some.name:` 或 `case QUALIFIED.NAME:` - 这是一个值模式,它会获取 `some.name` 的值,并用该值与 `subject` 进行比较。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. 序列模式 (Sequence Patterns)\n",
"\n",
"匹配序列类型(如 `list`, `tuple`)。可以匹配固定长度、可变长度,并捕获元素。\n",
"* `[p1, p2, ..., pN]`:匹配一个长度为 N 的序列,并将每个元素与对应的子模式 `pi` 匹配。\n",
"* `[p1, p2, *rest]`:匹配一个长度至少为 2 的序列,前两个元素与 `p1`, `p2` 匹配,剩余部分(一个列表)被捕获到 `rest`。\n",
"* `[p1, p2, *_]`:类似上面,但忽略剩余部分。\n",
"* `*` 只能出现一次。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def process_list(data_list):\n",
" match data_list:\n",
" case []:\n",
" print(\"Empty list\")\n",
" case [item1]:\n",
" print(f\"List with one item: {item1}\")\n",
" case [\"start\", command, count]:\n",
" print(f\"Start command: {command} with count: {count}\")\n",
" case [x, y, z]:\n",
" print(f\"List of three items: {x}, {y}, {z}\")\n",
" case [\"log\", *messages]: # 星号捕获剩余部分为一个列表\n",
" print(f\"Log messages: {messages}\")\n",
" case [first, second, *_]: # 星号通配符忽略剩余部分\n",
" print(f\"List starts with {first}, {second}, and has more elements.\")\n",
" case _:\n",
" print(f\"Unmatched list structure: {data_list}\")\n",
"\n",
"process_list([])\n",
"process_list([100])\n",
"process_list([\"start\", \"process_A\", 5])\n",
"process_list([1, 2, 3])\n",
"process_list([\"log\", \"Error 1\", \"Warning 2\", \"Info 3\"])\n",
"process_list([\"user\", \"Alice\", 30, \"admin\"])\n",
"process_list((1,2)) # 也适用于元组,因为元组是序列"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. 映射模式 (Mapping Patterns)\n",
"\n",
"匹配映射类型(如 `dict`)。可以匹配特定的键,捕获对应的值,并用 `**rest` 捕获剩余的键值对。\n",
"* `{\"key1\": p1, \"key2\": p2}`:匹配一个至少包含 \"key1\" 和 \"key2\" 的字典,它们的值分别与 `p1` 和 `p2` 匹配。\n",
"* `{\"key1\": val1, \"key2\": val2, **rest}`:`val1` 和 `val2` 是捕获变量,`rest` 捕获剩余的键值对(一个字典)。\n",
"* `**_` 可以用来表示字典可以有其他键,但我们不关心它们。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def process_dict(data_dict):\n",
" match data_dict:\n",
" case {\"name\": str(name), \"age\": int(age)} if age >= 18:\n",
" print(f\"Adult: {name}, Age: {age}\")\n",
" case {\"name\": str(name), \"age\": int(age)}:\n",
" print(f\"Minor: {name}, Age: {age}\")\n",
" case {\"city\": city, \"country\": \"USA\", **other_details}:\n",
" print(f\"Location in USA: {city}. Other details: {other_details}\")\n",
" case {\"error_code\": code, \"message\": msg, **_}: # 忽略其他键\n",
" print(f\"Error {code}: {msg}\")\n",
" case {}:\n",
" print(\"Empty dictionary\")\n",
" case _:\n",
" print(f\"Unmatched dictionary structure: {data_dict}\")\n",
"\n",
"process_dict({\"name\": \"Alice\", \"age\": 30})\n",
"process_dict({\"name\": \"Bob\", \"age\": 15})\n",
"process_dict({\"city\": \"New York\", \"country\": \"USA\", \"zip\": \"10001\"})\n",
"process_dict({\"error_code\": 404, \"message\": \"Resource not found\", \"timestamp\": 12345})\n",
"process_dict({})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. 类模式 (Class Patterns)\n",
"\n",
"匹配特定类的实例,并可以解构其属性。\n",
"* `ClassName()`:匹配 `ClassName` 的任何实例。\n",
"* `ClassName(attr1=p1, attr2=p2)`:匹配 `ClassName` 的实例,并且其 `attr1` 属性与 `p1` 匹配,`attr2` 属性与 `p2` 匹配。\n",
"* `ClassName(pos_arg1, pos_arg2, attr1=p1)`:如果类定义了 `__match_args__` 来指定位置参数的顺序,则可以按位置匹配。\n",
"\n",
"**`__match_args__`**:一个类属性(通常是元组或列表),列出在类模式中可以用作位置参数的实例属性的名称和顺序。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class Point:\n",
" # __match_args__ 告诉模式匹配如何按位置解释参数\n",
" __match_args__ = (\"x\", \"y\") \n",
"\n",
" def __init__(self, x, y, label=None):\n",
" self.x = x\n",
" self.y = y\n",
" self.label = label\n",
"\n",
" def __repr__(self):\n",
" return f\"Point({self.x}, {self.y}, label='{self.label}')\"\n",
"\n",
"class Circle:\n",
" __match_args__ = (\"center\", \"radius\")\n",
" def __init__(self, center: Point, radius: float):\n",
" self.center = center\n",
" self.radius = radius\n",
"\n",
" def __repr__(self):\n",
" return f\"Circle(center={self.center!r}, radius={self.radius})\"\n",
"\n",
"def describe_shape(shape):\n",
" match shape:\n",
" case Point(x=0, y=0, label=lbl): # 匹配关键字参数\n",
" print(f\"Origin Point with label: '{lbl}'\")\n",
" case Point(0, 0): # 使用 __match_args__ 进行位置匹配 (x=0, y=0)\n",
" print(\"Origin Point (no label or label ignored)\")\n",
" case Point(x_coord, y_coord): # 位置捕获\n",
" print(f\"Point at ({x_coord}, {y_coord})\")\n",
" case Circle(Point(cx, cy), r) if r > 0: # 嵌套模式和守卫\n",
" print(f\"Circle centered at ({cx}, {cy}) with radius {r}\")\n",
" case Circle(center=_, radius=0):\n",
" print(f\"Degenerate circle (point) at {shape.center}\")\n",
" case Point(): # 匹配任何 Point 实例\n",
" print(\"Some other Point instance\")\n",
" case _: \n",
" print(\"Unknown shape\")\n",
"\n",
"describe_shape(Point(0, 0, label=\"Origin\"))\n",
"describe_shape(Point(0, 0))\n",
"describe_shape(Point(10, 20))\n",
"describe_shape(Point(5, 8, label=\"P1\"))\n",
"describe_shape(Circle(Point(5,5), 10))\n",
"describe_shape(Circle(Point(1,1), 0))\n",
"describe_shape(\"Not a shape\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. OR 模式 (OR Patterns)\n",
"\n",
"使用 `|` (管道符号) 连接多个模式。如果 `subject` 匹配 `|` 左边或右边的任何一个模式,则整个 OR 模式匹配成功。\n",
"**限制**:OR 模式中的所有子模式必须绑定相同的变量名集合。如果一个子模式绑定了 `x`,那么其他所有子模式也必须绑定 `x` (或者不绑定任何变量)。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def process_media_command(command):\n",
" match command:\n",
" case \"play\" | \"start\" | \"resume\":\n",
" print(\"Playing media...\")\n",
" case \"pause\" | \"hold\":\n",
" print(\"Pausing media...\")\n",
" case \"stop\" | \"end\" | \"quit\":\n",
" print(\"Stopping media...\")\n",
" case (\"set_volume\", int(level)) | (\"volume\", int(level)) if 0 <= level <= 100:\n",
" print(f\"Setting volume to {level}\")\n",
" case (\"set_volume\", _) | (\"volume\", _):\n",
" print(\"Invalid volume level.\")\n",
" case _:\n",
" print(f\"Unknown media command: {command}\")\n",
"\n",
"process_media_command(\"play\")\n",
"process_media_command(\"hold\")\n",
"process_media_command(\"quit\")\n",
"process_media_command((\"set_volume\", 75))\n",
"process_media_command((\"volume\", 120))\n",
"process_media_command((\"volume\", \"high\")) # 会匹配第二个 volume case"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. AS 模式 (AS Patterns) - 命名子模式\n",
"\n",
"使用 `pattern as name`。如果 `pattern` 匹配成功,那么匹配到的 `subject` (或其一部分,取决于 `pattern`) 会被绑定到 `name`。\n",
"这对于在复杂模式匹配成功后,仍然需要引用匹配到的整个对象或子对象非常有用。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def process_complex_data(data):\n",
" match data:\n",
" case [x, y] as pair: # 匹配列表 [x, y],并将整个列表绑定到 pair\n",
" print(f\"Pair: {pair}, sum: {x + y}\")\n",
" case {\"coord\": (int(a), int(b)) as point, \"value\": val}:\n",
" print(f\"Data point {point} at ({a},{b}) has value {val}\")\n",
" case str() as text if len(text) > 10:\n",
" print(f\"Long string: {text[:10]}... (Full: {text})\")\n",
" case (first, *_, last) as sequence if len(sequence) >=3:\n",
" print(f\"Sequence: {sequence}, first={first}, last={last}\")\n",
" case _:\n",
" print(f\"Other data: {data}\")\n",
"\n",
"process_complex_data([10, 20])\n",
"process_complex_data({\"coord\": (5, 3), \"value\": 100, \"meta\": \"info\"})\n",
"process_complex_data(\"This is a very long string example.\")\n",
"process_complex_data((1,2,3,4,5))\n",
"process_complex_data(42)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 9. 守卫 (Guards)\n",
"\n",
"如前所述,`if <condition>` 子句可以加在 `case` 模式之后。只有当模式匹配并且守卫条件为真时,`case` 块才会执行。\n",
"守卫中可以使用模式中捕获的变量。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def process_number_with_guard(num):\n",
" match num:\n",
" case int(x) if x > 0 and x % 2 == 0:\n",
" print(f\"{x} is a positive even integer.\")\n",
" case int(x) if x > 0:\n",
" print(f\"{x} is a positive odd integer.\")\n",
" case int(x) if x == 0:\n",
" print(f\"{x} is zero.\")\n",
" case int(x):\n",
" print(f\"{x} is a negative integer.\")\n",
" case float(y) if y > 0.0:\n",
" print(f\"{y} is a positive float.\")\n",
" case _:\n",
" print(f\"{num} is not a recognized number type or condition.\")\n",
"\n",
"process_number_with_guard(10)\n",
"process_number_with_guard(7)\n",
"process_number_with_guard(0)\n",
"process_number_with_guard(-5)\n",
"process_number_with_guard(3.14)\n",
"process_number_with_guard(\"text\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 总结与最佳实践\n",
"\n",
"结构化模式匹配是 Python 3.10+ 中一个非常强大的工具,它可以使处理复杂数据结构的代码更加清晰、简洁和易于维护。\n",
"\n",
"**优点:**\n",
"* **可读性**:对于分支逻辑复杂的场景,`match/case` 通常比一长串 `if/elif/else` 更易读。\n",
"* **解构赋值**:自然地从数据结构中提取值并赋给变量。\n",
"* **详尽性检查的潜力**:虽然 Python 的 `match` 本身不像某些静态语言那样强制进行详尽性检查,但它鼓励思考所有可能的情况(尤其是配合 `_` 通配符)。静态分析工具(如 MyPy)未来可能会在这方面提供更多支持。\n",
"* **减少样板代码**:例如,在解析 JSON 数据或处理不同类型的事件时。\n",
"\n",
"**使用建议:**\n",
"* **不要滥用**:对于简单的条件分支,传统的 `if/else` 可能仍然更清晰。\n",
"* **优先考虑可读性**:选择最能表达你意图的方式。\n",
"* **注意模式的顺序**:更具体的模式应该放在更通用的模式之前,因为 `match` 会在第一个匹配成功后停止。\n",
"* **利用守卫**:当模式本身不足以表达条件时,守卫非常有用。\n",
"* **善用 `__match_args__`**:对于自定义类,定义 `__match_args__` 可以使类模式更简洁易用。\n",
"* **结合类型提示**:模式匹配与类型提示可以很好地协同工作,提高代码的健壮性。\n",
"\n",
"结构化模式匹配为 Python 开发者提供了一个强大的新工具。通过实践和熟悉各种模式类型,你可以有效地利用它来编写更优雅的 Python 代码。"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

对动态语言Python的一些感慨

众所周知Python是完全动态的语言,体现在

  1. 类型动态绑定
  2. 运行时检查
  3. 对象结构内容可动态修改(而不仅仅是值)
  4. 反射
  5. 一切皆对象(instance, class, method)
  6. 可动态执行代码(eval, exec)
  7. 鸭子类型支持

动态语言的约束更少,对使用者来说更易于入门,但相应的也会有代价就是运行时开销很大,和底层汇编执行逻辑完全解耦不知道代码到底是怎么执行的。

而且还有几点是我认为较为严重的缺陷。下面进行梳理。

破坏了OOP的语义

较为流行的编程语言大多支持OOP编程范式。即继承和多态。同样,Python在执行简单任务时候可以纯命令式(Imperative Programming),也可以使用复杂的面向对象OOP。

但是,其动态特性破环了OOP的结构:

  1. 类型模糊:任何类型实例,都可以在运行时添加或者删除属性或者方法(相比之下静态语言只能在运行时修改它们的值)。经此修改的实例,按理说不再属于原来的类型,毕竟和原类型已经有了明显的区别。但是该实例的内建__class__属性依旧会指向原类型,这会给类型的认知造成困惑。符合一个class不应该只是名义上符合,而是内容上也应该符合。
  2. 破坏继承:体现在以下两个方面
    1. 大部分实践没有虚接口继承。abc模块提供了虚接口的基类ABC,经典的做法是让自己的抽象类继承自ABC,然后具体类继承自自己的抽象类,然后去实现抽象方法。但PEP提案认为Pythonic的做法是用typing.Protocol来取代ABC,具体类完全不继承任何虚类,只要实现相应的方法,那么就可以被静态检查器认为是符合Protocol的。
    2. 不需要继承自具体父类。和上一条一样,即使一个类没有任何父类(除了object类),它依旧可以生成同名的方法,以实现和父类方法相同的调用接口。这样在语义逻辑上,类的定义完全看不出和其他类有何种关系。完全可以是一种松散的组织结构,任何两个类之间都没继承关系。
  3. 破坏多态:任何一个入参出参,天然不限制类型。这使得要求父类型的参数处,传入子类型显得没有意义,依旧是因为任何类型都能动态修改满足要求。

破坏了设计模式

经典的模式诸如工厂模式,抽象工厂,访问者模式,都严重依赖于继承和多态的性质。但是在python的设计中,其动态能力使得设计模式形同虚设。 大家常见的库中使用设计模式的有transformers库,其中的from_pretrained系列则是工厂模式,通过字符串名称确定了具体的构造器得到具体的子类。而工厂构造器的输出类型是一个所有模型的基类。

安全性问题

Python在代码层面一般不直接管理指针,所以指针越界,野指针,悬空指针等问题一般不存在。而gc机制也能自动处理垃圾回收使得编码过程不必关注这类安全性问题。但与之相对的,Python也有自己的安全性问题。以往非托管形式的代码的攻击难度较大,注入代码想要稳定执行需要避免破坏原来的结构导致程序直接崩溃(段错误)。 Python却可以直接注入任何代码修改原本的逻辑,并且由于不是在code段固定的内容,攻击时候也无需有额外考虑。运行时可以手动修改globals() locals()内容,亦有一定风险。 另一个危险则是类型不匹配导致的代码执行问题,因为只有在运行时才确定类型,无法提前做出保证,可能会产生类型错误的异常,造成程序崩溃。

总结

我出身于C++。但是近年来一直在用python编程。而且python的市场占有率已经多年第一,且遥遥领先。这和其灵活性分不开关系。对于一个面向大众的编程语言,这样的特性是必要的。即使以上说了诸多python的不严谨之处,但是对于程序员依旧可以选择严谨的面向对象写法。所以,程序的优劣不在于语言怎么样,而在于程序员本身。程序员有责任写出易于维护,清晰,规范的代码~

Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@KuRRe8
Copy link
Author

KuRRe8 commented May 8, 2025

返回顶部

有见解,有问题,或者单纯想盖楼灌水,都可以在这里发表!

因为文档比较多,有时候渲染不出来ipynb是浏览器性能的问题,刷新即可

或者git clone到本地来阅读

ChatGPT Image May 9, 2025, 04_45_04 AM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment