如何避免在 Python 中重复工作而不通过引用传递?

How to avoid repeating work in Python without pass by reference?

我正在编写采用 JSON Web 令牌 (JWT) 并且必须检查令牌上的签名的 Web 端点。因为每次我都会检查签名,所以我应该将这一步分解成一个函数,因为 DRY。

但是,检查 JWT 是否正确签名的唯一方法是使用其密钥对其进行解码并捕获错误。这使我得到以下功能:

def is_valid_token(token_string, secret_key):
    try:
        jwt.decode(token_string, secret_key)
        return True
    except jwt.DecodeError:
        return False

这在验证令牌方面工作得很好,但是我有这个函数似乎真的很浪费,它会通过解码检查令牌是否有效,然后在这个函数之后我将不得不再次解码。也就是说我会做:

if not is_valid_token(token_string, secret_key):
    # Respond with an error to the client
else:
    token_data = jwt.decode(token_string, secret_key)

在这种情况下,我正在解码以检查它是否有效,如果有效,我将再次解码。在 C/C++ 中,我会通过引用传递一个变量来捕获解码数据,然后 return true 或 false。在Python有什么办法可以做这样的事情吗?

我突然想到,我可以通过传入一个空列表来捕获解码数据来解决这个问题,但这看起来真的很不雅观。有没有 Pythonic 方法来做到这一点?

在与 Nullman 讨论后,我们得出以下解决方案

def is_valid_token(jwt_string, secret_key, reference_list):
    try:
        data = jwt.decode(jwt_string, secret_key)
        reference_list.append(data) 
        return True
    except:
        return False

reference_var = []
if not is_valid_token(jwt_string, secret_key, reference_var):
    # Respond with an error to the client
else:
    data = reference_var[0]

您的方法已经在使用良好的 Pythonic EAFP idiom, but it then shoehorns it into a C style LBYL return 代码检查模式。不要那样做,继续使用异常。

在这种情况下 is_valid_token 有点毫无意义;当您仍然需要基于其 return 值的 if/else 时,它实际上并没有保存任何内容。根本不测试,只做内联解析并在发生异常时处理:

try:
    token_data = jwt.decode(token_string, secret_key)
except jwt.DecodeError:
    # respond with error to client
else:
    # Use token_data

它没有意义地更冗长(如果没有其他方法可以引发 jwt.DecodeError,您可以通过将 else 块的内容放在 try 中来缩短它,它将是和 if/else).

一样冗长

如果这是在更深层嵌套的代码中,您甚至可能不会在此处捕获异常,而是让它在堆栈中冒泡,直到知道如何响应客户端的人接收到它。

再次重申,您的问题是尝试使用 LBYL 习语来查看是否允许您做某事,然后去做,而最简单的方法是只做它并在异常发生时进行处理。您实际上并没有避免 DRY,因为在解析时不是 RY,而是在检查 return 并使用结果时 RY。

编辑:正如@ShadowRanger 指出的那样,下面的代码应该可以工作,但它实际上并没有改进任何东西,异常需要从 __init__ 重新引发并且调用者需要检查它。所以这个包装器并没有真正的帮助。我会留下答案供参考,但正确的做法可能是 .

也许你可以在这里利用 class 继承:

class WebEndPoint(object):
    def __init__(self, token_string, secret_key)
        try:
            self.data = jwt.decode(token_string, secret_key)
        except jwt.DecodeError as e:
            # respond with "invalid token"
            raise e

然后在您的代码中,您可以使用 class,例如:

class MyEndpoint(WebEndPoint):
    def handle_request(self,...):
        # do something with self.data, which you know is
        # valid if you reach this point

myendpoint = MyEndPoint(token, secret)

这样你甚至根本不需要调用 is_valid(),但你如何实际实现它可能取决于你使用的框架,如果有的话。