我应该如何重构一个存在于许多不同函数中的代码,但在其中包含return语句

时间:2010-12-15 06:57:14

标签: 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(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_active = True

在这种情况下,组织代码的最佳方法是什么,以便#block#endblock之间的代码不重复?我想一般来说,这个问题可以写成:

  

有一段代码可以通过许多不同的功能进行复制和粘贴。但是,这段代码包含return语句。在那种情况下,抽出这条逻辑的最佳方法是什么?

编辑:固定代码段。

EDIT2:实际上,解决这个问题的简单方法是创建一个函数,比如toggle_active_status,它取request和一个布尔值。 (我在发布问题后想出来了。)

但是,我想知道函数之间的不同逻辑超过1行的情况......比如说,#block和#endlbock之间的代码只进行输入验证,可能任意应用程序逻辑都可以来吧。

3 个答案:

答案 0 :(得分:3)

将重复的块分解出来并传递差异,创建传递差异的包装函数:

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)

答案 1 :(得分:1)

一种方法是简单地创建一个包含重复功能的单独函数。您可以使用函数的参数来引入必要的差异。

如果代码片段返回了某些内容,那么您可以使用约定,例如,如果函数不应返回则返回None,否则返回对象。在调用函数中,只测试返回的参数是否为None,如果不是None则返回返回的变量。

答案 2 :(得分:1)

尚未显示的几个选项:

由于这是一个验证例程,因此使用例外来表示失败,并使用正常的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_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)