所以让我们定义一些函数:
def x(a, b, c): pass
def y(a, b=1, c=2): pass
def z(a=1, b=2, c=3): pass
Run Code Online (Sandbox Code Playgroud)
现在,给出一个指向,或(),一个args()元组和一个kwargs()字典的指针x,最好的方法是什么,检查是否yzpak
p(*a, **kw)
Run Code Online (Sandbox Code Playgroud)
会产生任何关于没有足够的参数或不正确的参数等的例外 - 没有实际调用p(*a, **kw)然后捕获引发的异常.
def valid(ptr, args, kwargs): ... #implementation here
valid(x, ("hello", "goodbye", "what?"), {}) # => True
valid(x, ("hello", "goodbye"), {}) # => False
valid(y, ("hello", "goodbye", "what?"), {}) # => True
valid(y, (), {"a": "hello", "b": "goodbye", "c": "what"}) #=> True
valid(y, ("hello", "goodbye"), {"c": "what?"}) #=> True
Run Code Online (Sandbox Code Playgroud)
您可以使用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.
我能想到的最好方法是创建一个具有完全相同的签名和默认值的新函数,并尝试调用它并捕获异常。新函数代码的主体应该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
Run Code Online (Sandbox Code Playgroud)
运行此代码会产生:
$ python argspec.py
True
False
True
True
True
Run Code Online (Sandbox Code Playgroud)