Python 我应该如何重构一段存在于许多不同函数中但包含return语句的代码
代码片段来自django视图代码,但这并不重要 假设我有下面的一段代码Python 我应该如何重构一段存在于许多不同函数中但包含return语句的代码,python,django,refactoring,Python,Django,Refactoring,代码片段来自django视图代码,但这并不重要 假设我有下面的一段代码 def unsubscribe(request): #start of block user = request.user sid = request.POST.get('subscription_id') try: sub = Subscription.objects.get(id=sid) except ObjectDoesNotExist: return ajax_response(
def unsubscribe(request):
#start of block
user = request.user
sid = request.POST.get('subscription_id')
try:
sub = Subscription.objects.get(id=sid)
except ObjectDoesNotExist:
return ajax_response(False, [('subscription', 'Given subscription does not exist.')])
if sub.user != user:
return ajax_response(False, [('subscription', 'Invalid permission.')])
#end of block.
sub.is_active = False
sub.save()
return ajax_response(True)
比如说,我有另一个函数resubscribe()
,它的作用与上述函数完全相同,只是它的作用是sub.is\u active=True
在这种情况下,组织代码的最佳方式是什么,这样#block
和#endblock
之间的代码就不会重复?我想一般来说,这个问题可以写成:
有一段代码可以复制并粘贴到许多不同的函数上。但是,这段代码包含return
语句。在这种情况下,将这段逻辑抽象出来的最佳方法是什么
编辑:修复了代码段
EDIT2:实际上,解决这个问题的简单方法是创建一个函数,比如toggle_active_status,它接受request
和一个布尔值。(我把问题贴出来后就明白了)
但是,我想知道函数之间的不同逻辑超过1行的情况。。。比如说,在#block和#endlbock之间的代码只进行输入验证,可能会出现任意应用程序逻辑 一种方法是简单地创建一个包含重复功能的单独函数。您可以使用函数的参数来引入必要的差异
如果代码段返回某些内容,则可以使用约定,例如如果函数不应返回,则返回
None
,否则返回对象。在调用者函数中,只需测试返回的参数是否为None
,如果返回的变量不是None
,则返回该变量。一种方法是简单地创建一个包含重复功能的单独函数。您可以使用函数的参数来引入必要的差异
如果代码段返回某些内容,则可以使用约定,例如如果函数不应返回,则返回
None
,否则返回对象。在调用者函数中,只需测试返回的参数是否为None
,如果返回的变量不是None
,则返回该变量,将重复的块分解出来,并将差异传递进来,创建传递差异的包装函数:
def alter_subscription(request, make_active):
# start of block
# (...)
# end of block
sub.is_active = make_active
sub.save()
return ajax_response(True)
def unsubscribe(request):
return alter_subscription(request, False)
def resubscribe(request):
return alter_subscription(request, True)
分解出重复的块并传入差异,创建传入差异的包装函数:
def alter_subscription(request, make_active):
# start of block
# (...)
# end of block
sub.is_active = make_active
sub.save()
return ajax_response(True)
def unsubscribe(request):
return alter_subscription(request, False)
def resubscribe(request):
return alter_subscription(request, True)
一些尚未显示的选项: 由于这是一个验证例程,请使用异常指示失败,使用正常的None(忽略)返回指示成功:
def verify_permissions(request):
user = request.user
sid = request.POST.get('subscription_id')
try:
sub = Subscription.objects.get(id=sid)
except ObjectDoesNotExist:
raise PermissionError, 'Given subscription does not exist.'
if sub.user != user:
raise PermissionError, 'Invalid permission.'
def subscribe(request):
try:
verify_permissions(request)
sub.save()
return ajax_response(True)
except PermissionError, why:
return ajax_response(False, [('subscription', why)])
或者,由于Python是动态类型的,显然可以通过两种不同的方式调用ajax\u response
:返回用于构造响应的参数,并检查第一个参数的值
def verify_permissions(request, purpose):
user = request.user
sid = request.POST.get('subscription_id')
try:
sub = Subscription.objects.get(id=sid)
except ObjectDoesNotExist:
return (False, [(purpose, 'Given subscription does not exist.')])
if sub.user != user:
return (False, [(purpose, 'Invalid permission.')])
return (True,)
def subscribe(request):
result = verify_permissions(request, 'subscription')
if result[0]: sub.save()
return ajax_response(*result)
一些尚未显示的选项: 由于这是一个验证例程,请使用异常指示失败,使用正常的None(忽略)返回指示成功:
def verify_permissions(request):
user = request.user
sid = request.POST.get('subscription_id')
try:
sub = Subscription.objects.get(id=sid)
except ObjectDoesNotExist:
raise PermissionError, 'Given subscription does not exist.'
if sub.user != user:
raise PermissionError, 'Invalid permission.'
def subscribe(request):
try:
verify_permissions(request)
sub.save()
return ajax_response(True)
except PermissionError, why:
return ajax_response(False, [('subscription', why)])
或者,由于Python是动态类型的,显然可以通过两种不同的方式调用ajax\u response
:返回用于构造响应的参数,并检查第一个参数的值
def verify_permissions(request, purpose):
user = request.user
sid = request.POST.get('subscription_id')
try:
sub = Subscription.objects.get(id=sid)
except ObjectDoesNotExist:
return (False, [(purpose, 'Given subscription does not exist.')])
if sub.user != user:
return (False, [(purpose, 'Invalid permission.')])
return (True,)
def subscribe(request):
result = verify_permissions(request, 'subscription')
if result[0]: sub.save()
return ajax_response(*result)
我实际上已经想到了它,并创建了函数
def\u toggle\u subscription(request,toggle\u to):
其中有一行sub.is\u active=toggle\u to
。。。但是我觉得我已经利用了这样一个事实,即这个示例在提供的代码之间有如此小的差异。如果这两个函数之间的差异是可分性的呢?好吧,如果差异是相当大的,我不认为这算是代码重复。对不起,我想我没有具体说明。。。当我提到“差异”时,我的意思是指出非公共逻辑之间的差异。在提供的示例中,subscribe()和unsubscribe()之间的差异为sub.is_active=False(或True)。但是,如果#block和#endblock之间的代码只是初步检查,而后面的实际逻辑更复杂,该怎么办?在更复杂的情况下,您可以尝试第二个建议,使用常规的“无”结果。或者试试我的建议我实际上已经想到了它,并创建了函数def\u toggle\u subscription(request,toggle\u to):
其中有一行sub.is\u active=toggle\u to
。。。但是我觉得我已经利用了这样一个事实,即这个示例在提供的代码之间有如此小的差异。如果这两个函数之间的差异是可分性的呢?好吧,如果差异是相当大的,我不认为这算是代码重复。对不起,我想我没有具体说明。。。当我提到“差异”时,我的意思是指出非公共逻辑之间的差异。在提供的示例中,subscribe()和unsubscribe()之间的差异为sub.is_active=False(或True)。但是,如果#block和#endblock之间的代码只是初步检查,而后面的实际逻辑更复杂,该怎么办?在更复杂的情况下,您可以尝试第二个建议,使用常规的“无”结果。或者试试我的建议如果公共代码只进行验证,则从包装器调用它并检查返回值。如果这是一个django问题,并且您正在尝试进行验证,那么可以查看中间件或装饰器?但不要调用参数“bool
”,因为这会掩盖一个内置项(类型的名称)。:)固定(关于“bool”)ty,Karl.:)如果公共代码只进行验证,则从包装器调用它并检查返回值。如果这是一个django问题,并且您正在尝试进行验证,那么可以查看中间件或装饰器,但不要调用参数“boo”