简体   繁体   English

结构模式匹配和无限

[英]Structural pattern matching and infinity

I am computing the Lp distance functions for non-negative p 's.我正在计算非负pLp距离函数。 For all but p = 0 and p = ∞ a built-in pow() function serves well.对于除p = 0 和p = ∞ 之外的所有情况,内置的pow() function 都能很好地发挥作用。 Before I learned about a structural pattern matching, I had used a dictionary and exception handling:在了解结构模式匹配之前,我使用过字典和异常处理:

from math import sqrt, inf
distance_function = {   0.0: lambda x, y: int(x != 0.0) + int(y != 0.0),
                        1.0: lambda x, y: abs(x) + abs(y), # Likely a tad faster than 'pow()'       
                        inf: lambda x, y: max(abs(x), abs(y))}                  
def lp_distance(x, y, p): 
    try:                return distance_function[p](x, y)                   
    except KeyError:    return pow(pow(abs(x), p) + pow(abs(y), p), 1.0/p)

Some people didn't want exceptions here.有些人不想在这里有例外。 So I rewrote the snippet into the following one:所以我将片段重写为以下片段:

def lp_distance(x, y, p):
    match p:
        case 0.0:           return int(x != 0.0) + int(y != 0.0)
        case 1.0:           return abs(x) + abs(y)      
        # The line below triggers "SyntaxError: name capture 'inf' makes remaining patterns unreachable"
        case inf:           return max(abs(x), abs(y))
        # But the following works:
        case p if p == inf: return max(abs(x), abs(y))
        case _:             return pow(pow(abs(x), p) + pow(abs(y), p), 1.0/p)

Why case inf: is not correct ( Python v3.10.2 )?为什么case inf:不正确 ( Python v3.10.2 )?

In a case statement, a simple name is a pattern that captures (assigns) to that name .case语句中, 简单名称是一种捕获(分配)给该名称的模式 In contrast, a dotted name is a patterns that refers to the value of that name .相反, 带点的名称是指代该名称的模式

In simple terms NAME will always succeed and it will set NAME = <subject> .简而言之, NAME将始终成功,并且它将设置NAME = <subject>

In simple terms NAME1.NAME2 will succeed only if <subject> == NAME1.NAME2简单来说,只有<subject> == NAME1.NAME2 NAME1.NAME2才会成功

Using just case inf: means that the value to match is unconditionally assigned to the name inf – it does not matter if the name was previously bound.使用 just case inf:意味着要匹配的值无条件地分配给名称inf名称是否先前绑定并不重要。
What you want instead is case math.inf: , which means to compare against this value.你想要的是case math.inf: ,这意味着要与这个值进行比较。

import math

def lp_distance(x, y, p):
    match p:
        case 0.0:
            return int(x != 0.0) + int(y != 0.0)
        case 1.0:
            return abs(x) + abs(y)      
        # compare against a value by using its dotted name
        case math.inf:
            return max(abs(x), abs(y))
        case _:
            return pow(pow(abs(x), p) + pow(abs(y), p), 1.0/p)

As noted by the other respondents, you can't use inf directly because that is a capture pattern.正如其他受访者所指出的,您不能直接使用inf ,因为那是一种捕获模式。 The obvious solution is to use a value pattern with a dotted lookup;显而易见的解决方案是使用带点查找的模式; however, that only works for positive infinity .但是,这仅适用于正无穷大

To handle other all special values like negative infinity and NaNs, you need guards:要处理其他所有特殊值,如负无穷大和 NaN,你需要守卫:

match x:
    case 1.0: ...                   # Exact value (literal pattern)
    case 0.0: ...                   # Exact value (literal pattern)
    case _ if math.isfinite(x): ... # Normal cases
    case _ if math.isnan(x): ...    # NaNs defy equality tests
    case _: ...                     # Negative infinity   


   

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM