在不破坏可读性的情况下压缩此Python语句

时间:2009-10-09 14:59:14

标签: python

我对Python还很陌生,所以我想弄清楚如何做到这一点并需要一些帮助。

我使用返回代码来验证我的内部函数是否成功返回。例如(来自内部库函数):

result = some_function(arg1,arg2)
if result != OK: return result

或(从主脚本级别):

result = some_function(arg1,arg2)
if result != OK: abort_on_error("Could not complete 'some_function': %s" % messages(result))

我可以将它降低到一行而不会让它变得不可读吗?

编辑:有些人认识到例外可能是更好的选择。我想仅为非常“特殊”的场景捕获保存异常。返回代码有时可能会失败,我认为在这种情况下使用异常通常是不好的做法。

5 个答案:

答案 0 :(得分:10)

您是否可以使用例外来表示失败,而不是返回代码?那么你的大多数if result != OK:陈述都会消失。

答案 1 :(得分:3)

pythonic

  

一个与Python语言最常见的习语密切相关的想法或一段代码,而不是使用其他语言共有的概念来实现代码。[...]

并不意味着写上线!

答案 2 :(得分:3)

听起来好像你想要的东西......

if result = some_function(arg1, arg2):
    return result

这在Python中是非常有意的。编写if a = b而不是if a == b这是一个很常见的拼写错误,并且允许这种情况与流量控制混合。如果有必要,将其分成两行:

x = some_function()
if x:
    print "Function returned True"

更实际的例子是......

result = re.match("a", "b")
if result:
   print result.groups()

(更准确地说,在这种情况下你应该做if result is not None:,虽然上面有效)

在您的特定情况下(“验证我的内部函数是否成功返回”),听起来您应该使用异常。如果一切都很好,只需返回任何你想要的东西。如果出现问题,请提出异常。

Python中的异常与许多其他语言不同 - 例如,它们用于内部流控制(例如StopIteration异常)

我认为以下比使用返回码更多Pythonic:

#!/usr/bin/env python2.6
def some_function(arg1, arg2):
    if arg1 + arg2 > 5:
        return "some data for you"
    else:
        raise ValueError("Could not complete, arg1+arg2 was too small")

然后,您可以在一行中调用该函数:

return some_function(3, 2)

这会返回值,或者引发异常,你可以在某个合理的地方处理异常:

def main():
    try:
        result = some_function(3, 5)
    except ValueError, errormsg:
        print errormsg
        sys.exit(1)
    else:
        print "Everything is perfect, the result was {0}".format(result)

或者,如果这种情况实际上是一个错误,只需使用一个很好的堆栈跟踪暂停应用程序。

是的,它比一行长得多,但Python背后的想法是简洁,但外观和可读性。

基本上,如果函数不能再继续,则引发异常。处理此异常,无论您可以从问题中恢复,还是向用户显示错误消息。除非您正在编写库,在这种情况下请保留异常以将堆栈运行到调用代码

或者,以诗的形式:

$ python -m this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

最后,可能值得阅读Python的样式指南"PEP 8"。它可能会回答你的一些问题,例如“如果声明是单线的'pythonic'吗?”

  

通常不鼓励使用复合语句(同一行上的多个语句)。

     

是:

if foo == 'blah':
    do_blah_thing()
do_one()
do_two()
do_three()
     

而不是:

if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()

答案 3 :(得分:1)

如果您坚持使用不使用例外,那么我会写两行(这里一行太长):

res = some_function(arg1, arg2)
return res if res != OK else ...

顺便说一句,我建议你提出函数返回的一些 static 类型的值(尽管在Python中进行动态类型化)。例如,您可以返回“intNone”。您可以将这样的描述放入docstring。

如果您有int个结果值和int错误代码,您可以通过引入错误类来区分它们:

class ErrorCode(int): pass

然后检查isinstance的结果ErrorCode

答案 4 :(得分:-1)

除了例外,使用装饰器是解决此问题的好方法:

# Create a function that creates a decorator given a value to fail on...
def fail_unless(ok_val):
   def _fail_unless(f):
       def g(*args, **kwargs):
           val = f(*args, **kwargs)
           if val != ok_val:
               print 'CALLING abort_on_error...'
           else:
               return val
       return g
   return _fail_unless


# Now you can use the decorator on any function you'd like to fail 
@fail_unless('OK')
def no_negatives(n):
    if n < 0:
        return 'UH OH!'
    else:
        return 'OK'

在实践中:

>>> no_negatives(9)
'OK'
>>> no_negatives(0)
'OK'
>>> no_negatives(-1)
'CALLING abort_on_error...'

我知道定义fail_unless的语法有点棘手,如果你不习惯装饰器和函数闭包但fail_unless()应用程序是不是很好吗?< / p>