在不修改函数定义的情况下调用函数时的可选参数

发布于 2024-08-21 00:10:02 字数 1546 浏览 3 评论 0原文

我想知道如何调用函数,传递它可能不期望的参数。

几天前我遇到了这个问题,并找到了解决方法。但今天,我决定看看我想做的事情是否可行。不幸的是,我不记得我使用它的上下文。所以这是一个愚蠢的例子,其中有很多更好的方法可以做到这一点,但忽略它:

def test(func, arg1, arg2):
    return func(arg1, arg2, flag1=True, flag2=False) #Only pass the flags if the function accepts them.

def func1(a, b, flag1, flag2):
    ret = a
    if flag1:
        ret *= b
    if flag2:
        ret += b
    return ret

def func2(a, b):
    return a*b

print test(func1, 5, 6) #prints 30

我想出的替代方案看起来像这样:

def test(func, arg1, arg2):
    numArgs = len(inspect.getargspec(func).args)
    if numArgs >= 4:
        return func(arg1, arg2, True, False)
    elif numArgs == 3:
        return func(arg1, arg2, True)
    else:
        return func(arg1, arg2)

print test(func2, 5, 6) #prints 30

或者try.. except.. block

但是必须有一个更好的方法来做到这一点而不改变 func1 和 func2,对吧?

(编辑):利用Max S提供的解决方案,我认为这是最好的方法:

def callWithOptionalArgs(func, *args):
    argSpec = inspect.getargspec(func)
    lenArgSpec = len(argSpec.args or ())
    argsToPass = args[:lenArgSpec] #too many args
    defaults = argSpec.defaults or ()
    lenDefaults = len(defaults)
    argsToPass += (None, )*(lenArgSpec-len(argsToPass)-lenDefaults) #too few args
    argsToPass += defaults[len(argsToPass)+len(defaults)-lenArgSpec:] #default args

    return func(*argsToPass)
print callWithOptionalArgs(func1, 5, 6, True) #prints 30
print callWithOptionalArgs(func2, 5, 6, True) #prints 30

I want to know how to call a function, passing a parameter that it might not be expecting.

I faced this problem a few days ago, and found a way around it. But today, I decided I'd see if what I wanted to do was possible. Unfortunately, I don't remember the context which I used it in. So here is a stupid example in which there are plenty of better ways to do this, but just ignore that:

def test(func, arg1, arg2):
    return func(arg1, arg2, flag1=True, flag2=False) #Only pass the flags if the function accepts them.

def func1(a, b, flag1, flag2):
    ret = a
    if flag1:
        ret *= b
    if flag2:
        ret += b
    return ret

def func2(a, b):
    return a*b

print test(func1, 5, 6) #prints 30

The alternative I came up with looked like this:

def test(func, arg1, arg2):
    numArgs = len(inspect.getargspec(func).args)
    if numArgs >= 4:
        return func(arg1, arg2, True, False)
    elif numArgs == 3:
        return func(arg1, arg2, True)
    else:
        return func(arg1, arg2)

print test(func2, 5, 6) #prints 30

or a try..except.. block

But there's got to be a better way of doing this without altering func1 and func2, right?

(Edit): Making use of the solution provided by Max S, I'm thinking this is the best approach:

def callWithOptionalArgs(func, *args):
    argSpec = inspect.getargspec(func)
    lenArgSpec = len(argSpec.args or ())
    argsToPass = args[:lenArgSpec] #too many args
    defaults = argSpec.defaults or ()
    lenDefaults = len(defaults)
    argsToPass += (None, )*(lenArgSpec-len(argsToPass)-lenDefaults) #too few args
    argsToPass += defaults[len(argsToPass)+len(defaults)-lenArgSpec:] #default args

    return func(*argsToPass)
print callWithOptionalArgs(func1, 5, 6, True) #prints 30
print callWithOptionalArgs(func2, 5, 6, True) #prints 30

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小伙你站住 2024-08-28 00:10:03

如果我理解你的意思,你希望能够使用 test 调用 func1 和 func2。

def test(func, arg1, arg2):
    try:
        return func(arg1, arg2, flag1=True, flag2=False)
    except TypeError:
        return func(arg1, arg2)


def func1(a, b, flag1, flag2):
    ret = a
    if flag1:
        ret *= b
    if flag2:
        ret += b
    return ret

def func2(a, b):
    return a*b

print test(func1, 5, 6) #prints 30
print test(func2, 5, 6) #prints 30

If I understand you, you want to be able to call both func1 and func2 using test.

def test(func, arg1, arg2):
    try:
        return func(arg1, arg2, flag1=True, flag2=False)
    except TypeError:
        return func(arg1, arg2)


def func1(a, b, flag1, flag2):
    ret = a
    if flag1:
        ret *= b
    if flag2:
        ret += b
    return ret

def func2(a, b):
    return a*b

print test(func1, 5, 6) #prints 30
print test(func2, 5, 6) #prints 30
最近可好 2024-08-28 00:10:02

检查函数是显式区分具有不同数量参数的函数而不改变或修饰原始函数的唯一方法。我对包装器所做的唯一更改是将其概括为任意数量的参数:

def padArgsWithTrue(func, *args):
    passed_args = list(args)
    num_args = len(inspect.getargspec(func).args)
    passed_args += [True] * (num_args - len(args))
    return func(*passed_args)

print padArgsWithTrue(lambda x,y,z,w: (x*y, z, w), 5, 6)

编辑:请注意,这不适应具有可变数量参数或关键字参数的函数。在编写完整的解决方案之前,您必须决定处理这些问题的策略。

Inspecting the function is the only way to explicitly differentiate between functions with different numbers of arguments without altering or decorating the originals. The only change I would do to your wrapper is to generalize it for any number of arguments:

def padArgsWithTrue(func, *args):
    passed_args = list(args)
    num_args = len(inspect.getargspec(func).args)
    passed_args += [True] * (num_args - len(args))
    return func(*passed_args)

print padArgsWithTrue(lambda x,y,z,w: (x*y, z, w), 5, 6)

EDIT: Note that this does not accommodate functions with variable number of args or keyword args. You'll have to decide on a policy to deal with those before a complete solution could be written.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文