检查有效参数

时间:2011-01-29 04:32:06

标签: python

所以让我们定义一些函数:

def x(a, b, c): pass
def y(a, b=1, c=2): pass
def z(a=1, b=2, c=3): pass

现在,给出xyzp)指针的最佳方法是什么,这是一个args元组({{1} })和kwargs字典(a),检查是否

k

会产生关于没有足够的参数或不正确的参数的任何异常,等等 - 没有实际调用p(*a, **kw) 然后捕获引发的异常。

实施例

p(*a, **kw)

3 个答案:

答案 0 :(得分:5)

您可以使用inspect模块的getargspec函数来确定参数的功能及其默认值(如果有),以及函数是否接受varargs或keywordargs。这应该足以确定给定元组是否满足参数要求。

这是一个开始(必须运行,但我认为发布一个开始比没有好)。


def valid(f, *args, **kwargs):
    specs = getargspec(f)
    required = specs.args[:-len(specs.defaults)] if (specs.defaults != None) else specs.args 
    #Now just check that your required arguments list is fulfilled by args and kwargs
    #And check that no args are left over, unless the argspec has varargs or kwargs defined.

答案 1 :(得分:2)

我能想到的最好的方法是创建一个具有完全相同签名和默认值的新函数,并尝试调用它并捕获异常。新函数代码的主体应该是pass,这样就没有副作用了。这里没有什么真正深刻的,代码只是单调乏味。值得注意的是,这确实将您与CPython内部联系起来。它适用于2.6。你必须把它移植到其他版本,但这不应该太难。

import types


ARGS_FLAG = 4   #If memory serves, this can be found in code.h in the Python source.
KWARGS_FLAG = 8

def valid(f, args, kwargs):

    def dummy():
        pass

    dummy_code = dummy.func_code
    real_code = f.func_code

    args_flag = real_code.co_flags & ARGS_FLAG
    kwargs_flag = real_code.co_flags & KWARGS_FLAG

    # help(types.CodeType) for details
    test_code = types.CodeType(real_code.co_argcount,
                               real_code.co_nlocals,
                               dummy_code.co_stacksize,
                               args_flag | kwargs_flag,
                               dummy_code.co_code,
                               dummy_code.co_consts,
                               dummy_code.co_names,
                               real_code.co_varnames,
                               "<test>", "", 0, "", ())

    # help(types.FunctionType) for details
    test_func = types.FunctionType(test_code, {}, "test", f.func_defaults)

    try:
        test_func(*args, **kwargs)
    except TypeError:
        return False
    else:
        return True


def x(a, b, c): pass
def y(a, b=1, c=2): pass
def z(a=1, b=2, c=3): pass

print valid(x, ("hello", "goodbye", "what?"), {}) # => True
print valid(x, ("hello", "goodbye"), {}) # => False
print valid(y, ("hello", "goodbye", "what?"), {}) # => True
print valid(y, (), {"a": "hello", "b": "goodbye", "c": "what"}) #=> True
print valid(y, ("hello", "goodbye"), {"c": "what?"}) #=> True

运行此代码会产生:

$ python argspec.py
True
False
True
True
True

答案 2 :(得分:0)

查看此方法签名类型检查装饰器:

Python 3:http://code.activestate.com/recipes/572161/
Python 2:同一站点/.../ recipes / 426123 /

在Python 3中使用它更容易,因为它使用了注释类型规范,非常直观:

@typecheck
def foo(a1: int, a2: str, a3: dict, *, kw1: bool) -> list:
    ...

@typecheck
def bar(el: list_of(str),
        stream: with_attr("write", "flush"),
        num: by_regex("^[0-9]+$"),
        f: optional(callable) = None):
    ...

@typecheck
def biz(p: lambda x: isinstance(x, int) and x % 3 == 0):
    ...

Python 2版本不是那么漂亮,但仍可使用:

@takes(int, str, dict, kw1 = bool)
@returns(list)
def foo(a1, a2, a3, **kwargs):
    ...