【问题标题】:Getting DRY with Python Conditionals and Django returns使用 Python 条件和 Django 返回 DRY
【发布时间】:2011-10-23 14:58:51
【问题描述】:

我要分享的是我的项目中的一个常见模式。有些案例比其他案例更长,但模式或多或少是相同的,我想知道我怎样才能更干。

if status == 'ACTIVE' and p.result != "0":

    messages.add_message(request, messages.ERROR, 
        _('Active Message... bla bla bla'))

    return HttpResponseRedirect(reverse('billing_update'))

if status == 'TOO MANY FAILURES':

    messages.add_message(request, messages.ERROR, 
        _('Failed. Foooobarrrrr'))

    return HttpResponseRedirect(reverse('billing_update'))

if status == 'DEACTIVATED BY MERCHANT':

    messages.add_message(request, messages.ERROR, 
        _('Deactivated derpa derp'))

    return HttpResponseRedirect(reverse('billing_update'))

这里唯一发生的事情是根据状态设置消息。必须有一种方法只调用一次 return,甚至可以收紧条件。

想法?

【问题讨论】:

    标签: python django dry


    【解决方案1】:

    我注意到您的最后一次返回是有条件的,并且根据我自己的类似代码猜测,如果没有任何检查触发,您想继续并返回其他内容,甚至可能不是重定向...

    我认为我会这样做:

    def checkForMessage():
        if status == 'ACTIVE' and p.result != "0":
            return 'Active Message... bla bla bla'
        if status == 'TOO MANY FAILURES':
            return 'Failed. Foooobarrrrr'
        if status == 'DEACTIVATED BY MERCHANT':
            return 'Deactivated derpa derp'
        return None
    
    msg = checkForMessage()
    if msg:
        messages.add_message(request, messages.ERROR, _(msg))
    
        return HttpResponseRedirect(reverse('billing_update'))
    
    // ... go on and do some other stuff ...
    return direct_to_template('some/template.html', {some: stuff})
    

    请注意,函数 checkForMessage 是在视图函数内部定义的,因此我们不必将测试中涉及的所有内容作为参数传递给它(如果 tets 很多且不同,如果它们只需要状态和一些“p”变量,它也可以在视图函数之外声明并获取这些参数)。

    主要的一点是,我们根本不想添加任何消息的“失败”替代方案可以通过在 check 方法中返回 None 并在 view 方法中检查是否存在消息来处理。

    【讨论】:

    • 就好像闭包对于初学者程序员来说既简单又安全...... ;)
    • 闭包当然有其复杂性,但我认为我们不应该仅仅因为实现它的语言特性可以以其他难以理解的方式使用,就避免在函数中使用简单的函数。 :-)
    • 无论如何,这里的重点不是天气是否传递这些参数,而是 checkForMessage 方法可能返回 None,我们可以使用辅助检查来仅添加消息,如果有要添加的消息,我猜这就是消息字符串不只是放在变量中并在所有检查后添加的原因。
    • 我见过很多从优秀到优秀的程序员都因范围综合症及其姐妹 UnboundLocalError-itis 受苦:)
    • 我添加了更多文本来指定范围是完全可选的。但是,只要您不将句柄传递给创建它的范围之外的方法或类似的东西,我仍然不认为在本地声明它并在内部方法中访问外部方法范围是有问题。
    【解决方案2】:

    可能是这样的:

    库模块

    def add_error_message(request, status, result=0):
        if status == 'ACTIVE' and not result:
            msg = 'Active Message... bla bla bla'
        elif status == 'TOO MANY FAILURES':
            msg = 'Failed. Foooobarrrrr'
        elif status == 'DEACTIVATED BY MERCHANT':
            msg = 'Deactivated derpa derp'
        messages.add_message(request, messages.ERROR, _(msg))
    

    如果不是'p.result'条件,字典会更好:

    MESSAGES = {
        'ACTIVE': 'Active Message... bla bla bla',
        'TOO MANY FAILURES': 'Failed. Foooobarrrrr',
        'DEACTIVATED BY MERCHANT': 'Deactivated derpa derp',
    }
    def add_error_message(request, status):
        try:
            messages.add_message(request, messages.ERROR, _(MESSAGES[status]))
        except KeyError:
            pass
    

    查看模块

    from lib import add_error_message
    
    def your_view(request, *args, **kwargs):
        # ...
        add_error_message(request, status, p.result if p else 0)
        return HttpResponseRedirect(reverse('billing_update'))
    

    【讨论】:

    • 我想我喜欢这个,它也有助于证明我可以将重复代码的许多其他部分应用到相同的地方。 lib.py 是 django 项目中的常见模式吗?我从来没有在......views.py之外建立我的观点;)
    • 您可以随意模块化我们的代码。如果其他任何地方都不需要该函数,它可以存在于同一个 views.py 模块中。 DRY 的全部意义在于,将通用代码分解为函数并将它们放在可访问的地方。有些人使用lib.py 一些utils.py,有些喜欢Ruby on Rails 的可以考虑使用helpers.py。只需在您自己的项目中保持连贯性,并记录您的代码。
    • 这并不能真正帮助他不要重复自己——messages.add_message(request, messages.ERROR, _()) 的重复仍然存在。这只是更大的模块化——可以通过将其放入方法中来完成。而且,如果它只是从views.py 使用,它在语义上不一定属于另一个模块。
    • @agf 你是对的,我忘了取消重复那段,它在我的脑海里,但不在我的手指上。无论如何,我现在编辑得更干了。谢谢。
    • @agf 模块的事情在另一条评论中解释。很明显 Flowpoke 并没有意识到将代码放在不同模块中的可能性,所以现在由他来决定是否在必要时使用这个“功能”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-08
    • 2021-07-10
    • 1970-01-01
    • 2018-01-20
    • 2014-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多