确定Python函数中返回值的数量

我正在创建一个装饰器,捕获目标函数中引发的错误,并允许用户继续执行脚本(绕过函数)或退出脚本。

def catch_error(func):
    """
    This decorator is used to make sure that if a decorated function breaks 
    in the execution of a script, the script doesn't automatically crash. 
    Instead, it gives you the choice to continue or gracefully exit.    

    """
    def caught(*args):
        try:
            return func(*args)
        except Exception as err:
            question = 'n{0} failed. Continue? (yes/no): '.format(func.func_name)
            answer = raw_input(question)
            if answer.lower() in ['yes','y']:
                pass
            else:
                print "   Aborting! Error that caused failure:n"
                raise err 
            return None
    return caught

请注意,如果用户选择绕过错误返回函数并继续执行脚本,则修饰器返回None。 这适用于只返回单个值的函数,但它试图解压多个值的函数会崩溃。 例如,

# Both function and decorator return single value, so works fine
one_val = decorator_works_for_this_func() 
# Function nominally returns two values, but decorator only one, so this breaks script
one_val, two_val = decorator_doesnt_work_for_this_func()

有没有一种方法可以确定我的目标函数应该返回的值的数量? 例如,像这样的东西:

def better_catch_error(func):
    def caught(*args):
        try:
            return func(*args)
        except Exception as err:
            ...
            num_rvals = determine_num_rvals(func)
            if num_rvals > 1:
                return [ None for count in range(num_rvals) ]
            else:
                return None               
    return caught

一如既往,如果有更好的方法来做这种事情,请让我知道。 谢谢!

更新:

感谢所有的建议。 我决定将catch_error的范围缩小为一个函数类,它只返回一个字符串值。 我只是将所有返回多个值的函数分解成单独的函数,并返回一个值以使它们兼容。 我一直希望catch_error更通用(关于如何做到这一点有几个有用的建议),但对我的应用程序来说,这有点矫枉过正。 再次感谢。


Martijn Pieters的回答是正确的,这是停机问题的一个具体案例

不过你可以通过向装饰器传递一个错误返回值来绕过它。 像这样的东西:

def catch_error(err_val):
    def wrapper(func):
        def caught(*args):
            try:
                return func(*args)
            except Exception as err:
                question = 'n{0} failed. Continue? (yes/no): '.format(func.func_name)
                answer = raw_input(question)
                if answer.lower() in ['yes','y']:
                    pass
                else:
                    print "   Aborting! Error that caused failure:n"
                    raise err 
                return err_val
        return caught
    return wrapper

然后你可以用下面的装饰:

@catch_error({})
def returns_a_dict(*args, **kwargs):
    return {'a': 'foo', 'b': 'bar'}

同样作为一种风格,如果你在你的包装函数中抓取*args ,你应该也可以抓住**kwargs这样你就可以正确地包装带有关键字参数的函数。 否则,如果调用wrapped_function(something=value)您的包装函数将失败

最后,作为另一种风格的观点,看到if a: pass使用其他方法进行if a: pass代码时会产生混淆。 在这些情况下尝试使用if !a 。 所以最终的代码是:

def catch_error(err_val):
    def wrapper(func):
        def caught(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as err:
                question = 'n{0} failed. Continue? (yes/no): '.format(func.func_name)
                answer = raw_input(question)
                if answer.lower() not in ['yes','y']:
                    print "   Aborting! Error that caused failure:n"
                    raise err
                return err_val
        return caught
    return wrapper

不,你无法确定这一点。

Python是一种动态语言,根据输入和其他因素,给定的函数可以返回任意大小的任意序列或根本没有序列。

例如:

import random

def foo():
    if random.random() < 0.5:
        return ('spam', 'eggs')
    return None

这个函数会在一半的时间内返回一个元组,但是None另一半,所以Python没有办法告诉你foo()会返回什么。

你的装饰器可以失败的方式有很多,顺便说一下,不仅仅是当函数返回一个调用者解开的序列时。 如果调用者期望字典并开始尝试访问密钥或列表并想知道长度,该怎么办?


你的装饰器无法预测你的函数将要返回什么,但没有任何东西阻止你告诉装饰器要模拟的返回签名:

@catch_error([None, None])
def tuple_returner(n):
    raise Exception
    return [2, 3]

您的装饰器将返回其参数( [None, None] ),而不是返回None

编写自变量装饰器只是稍微有点棘手:表达式catch_error([None, None])将被计算,并且必须返回将应用于装饰函数的实际装饰器。 它看起来像这样:

def catch_error(signature=None):
    def _decorator(func):
        def caught(*args):
            try:
                return func(*args)
            except Exception as err:
                # Interactive code suppressed
                return signature

        return caught

    return _decorator

请注意,即使您只是希望它返回None ,您也需要执行一次:

@catch_error()
def some_function(x):
    ...
链接地址: http://www.djcxy.com/p/53561.html

上一篇: Determining the number of return values in a Python function

下一篇: Python: tuple assignment while at same time converting type