jak*_*vdp 39 python switch-statement python-3.x python-3.10 structural-pattern-matching
我正在尝试了解Python 3.10 中新的结构模式匹配语法。我知道可以匹配这样的文字值:
def handle(retcode):
match retcode:
case 200:
print('success')
case 404:
print('not found')
case _:
print('unknown')
handle(404)
# not found
Run Code Online (Sandbox Code Playgroud)
但是,如果我重构并将这些值移动到模块级变量,则会导致错误,因为语句现在表示结构或模式而不是值:
SUCCESS = 200
NOT_FOUND = 404
def handle(retcode):
match retcode:
case SUCCESS:
print('success')
case NOT_FOUND:
print('not found')
case _:
print('unknown')
handle(404)
# File "<ipython-input-2-fa4ae710e263>", line 6
# case SUCCESS:
# ^
# SyntaxError: name capture 'SUCCESS' makes remaining patterns unreachable
Run Code Online (Sandbox Code Playgroud)
有没有办法使用 match 语句来匹配存储在变量中的值?
Gre*_*Guy 34
如果您要测试的常量是带点名称的常量,则应将其视为常量而不是将捕获放入的变量的名称(请参阅PEP 636 # Matching against constants and enums):
class Codes:
SUCCESS = 200
NOT_FOUND = 404
def handle(retcode):
match retcode:
case Codes.SUCCESS:
print('success')
case Codes.NOT_FOUND:
print('not found')
case _:
print('unknown')
Run Code Online (Sandbox Code Playgroud)
虽然,考虑到 python 是如何尝试实现模式匹配的,我认为对于这种情况,if/elif/else在检查常量值时只使用一个塔可能更安全、更清晰。
Bra*_*her 19
希望我能帮助阐明为什么裸名称在这里以这种方式工作。
首先,正如其他人已经指出的,如果您需要将值作为模式的一部分进行匹配,您可以通过以下方式进行:
Noneif)我担心我们(PEP 的作者)在早期教程中包含这个玩具片段可能犯了一个小错误……它已经有点像病毒了。我们的目标是用最简单的模式匹配示例来引导,但我们似乎也给许多人造成了令人困惑的第一印象(尤其是在没有上下文的情况下重复时)。
这些 PEP 标题中最容易被忽视的词是“结构性”。如果您不匹配主题的结构,则结构模式匹配可能不是该工作的正确工具。
此功能的设计是由解构驱动的(例如在赋值的 LHS 上可迭代解包,但适用于所有对象),这就是为什么我们使提取对象部分并将它们绑定到的核心功能变得非常容易名称。我们还决定允许程序员匹配值也很有用,所以我们添加了这些(条件是在命名值时,它们必须用点限定,以便将它们与更常见的提取区分开来) )。
Python 的模式匹配从来没有真正设计为支持像这样的 C 风格的 switch 语句;之前曾两次为 Python 提出(但被拒绝),所以我们选择了不同的方向。此外,还有一个已经很明显的方式来开关一个值,这是更简单,更短,并适用于Python中的每一个版本:一个良好的醇” if/ elif/else阶梯!
SUCCESS = 200
NOT_FOUND = 404
def handle(retcode):
if retcode == SUCCESS:
print('success')
elif retcode == NOT_FOUND:
print('not found')
else:
print('unknown')
handle(404)
Run Code Online (Sandbox Code Playgroud)
(如果您真的很关心性能或需要表达式,从字典中调度也是一个不错的选择。)
Gar*_*ary 11
除了使用字面值之外,PEP 635的值模式部分还提到了使用虚线名称或使用guards。对比见下图:
字面值
def handle(code):
match code:
case 200:
print('success')
case 404:
print('not found')
case _:
print('unknown')
Run Code Online (Sandbox Code Playgroud)
参考:
虚线名称
任何带点的名称(即属性访问)都被解释为值模式。
class StatusCodes:
OK = 200
NOT_FOUND = 404
def handle(code):
match code:
case StatusCodes.OK:
print('success')
case StatusCodes.NOT_FOUND:
print('not found')
case _:
print('unknown')
Run Code Online (Sandbox Code Playgroud)
参考:
卫兵
[A] 守卫是附加到模式的任意表达式,必须评估为“真实”值才能使模式成功。
SUCCESS = 200
NOT_FOUND = 404
def handle(code):
match code:
case status if status == SUCCESS:
print('success')
case status if status == NOT_FOUND:
print('not found')
case _:
print('unknown')
Run Code Online (Sandbox Code Playgroud)
参考:
Pythonmatch不仅仅是一个简单的 switch 语句。如果您只使用您认为的“变量名称”,它们实际上将是捕获模式。根据PEP 编号中的定义。第634章
除了您可能不应该在您的用例中使用这一事实之外match,您还必须通过以下方式之一使用限定(点)名称:
statuses = object()
statuses.success = 200
status.not_found = 404
def handle(retcode):
match retcode:
case statuses.success: print("Success")
case statuses.not_found: print("Not found")
Run Code Online (Sandbox Code Playgroud)
class StatusValues:
success = 200
not_found = 404
def handle(retcode):
match retcode:
case StatusValues.success: print("Success")
case StatusValues.not_found: print("Not found")
Run Code Online (Sandbox Code Playgroud)
我开发了match-ref 库,它允许您访问任何函数内部或外部的任何本地或全局变量,只需使用ref.前缀即可。
from matchref import ref
import random
SUCCESS = 200
NOT_FOUND = 404
def handle(retcode):
random_code = random.randint(600,699)
match retcode:
case ref.SUCCESS: print("Success")
case ref.NOT_FOUND: print("Not found")
case ref.random_code: print("OK, you win!")
Run Code Online (Sandbox Code Playgroud)
如您所见,ref自动解析来自本地和全局命名空间的变量(按此顺序)。无需额外设置。
如果您不想使用第三方库,您可以在下面看到一个稍微类似的无库版本。
locals()和globals()是 Python 中的内置函数,它们返回dict包含映射到各自值的所有变量名称的 。您需要能够使用点语法访问字典的值,因为match也不支持字典访问语法。因此,您可以编写这个简单的帮助器类:
class GetAttributeDict(dict):
def __getattr__(self, name):
return self[name]
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
import random
SUCCESS = 200
NOT_FOUND = 404
def handle(retcode):
random_code = random.randint(600, 699)
globs = GetAttributeDict(globals())
locs = GetAttributeDict(locals())
match retcode:
case globs.SUCCESS: print("Success")
case globs.NOT_FOUND: print("Not found")
case locs.random_code: print("OK , you win!")
Run Code Online (Sandbox Code Playgroud)
鉴于您似乎打算重复使用状态代码(因为否则您可以将它们内联到您的cases 中),您可能会考虑为此使用单独的模块。
constants.py:
SUCCESS = 200
NOT_FOUND = 404
Run Code Online (Sandbox Code Playgroud)
main.py
import constants
match retcode:
case constants.SUCCESS: ...
...
Run Code Online (Sandbox Code Playgroud)
同样,您可能需要重新考虑是否要使用match。
| 归档时间: |
|
| 查看次数: |
4483 次 |
| 最近记录: |