如何避免在 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()
,但你如何实际实现它可能取决于你使用的框架,如果有的话。
我正在编写采用 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()
,但你如何实际实现它可能取决于你使用的框架,如果有的话。