如果存在另一个参数,则需要参数

Require parameter if another argument is present

以下是我想做的一个例子。

def f(a, b, c):
    if a == 'method1':
        c = 0
    return b + c

在这个函数中,如果满足条件a='method1',则不需要参数c。 不过,我可以用 f(a='method1', b=1, c=2) 调用该函数,这与 f(a='method1', b=1, c=0).

具有相同的效果

解决这个问题的方法是将参数 c 默认设置为 0

def f(a, b, c=0):
    if a == 'method1':
        c = 0
    return b + c

现在我可以调用 f(a='method1',b=1),这正是我想要的。问题是,我仍然可以在调用 f(a='method1',b=1,c=1) 中更改参数 c,我不希望用户能够这样做。

我能否在函数签名中强制执行此条件,而不是在主体中(即我不想在主体中使用 if)。或者如果有其他更好的解决方案,请告知。

类似

def f(a, b, c = 0 if a == 'method1', else c is required):
    return b + c

提前致谢。

嗯...这几乎看起来像是你应该能够用 functools.singledispatchtyping.Literal 做的事情,但我不能完全让它们一起工作至少在 python 3.7(Literal 来自 typing_extensions 模块)。我认为一般来说 singledispatch 可能是唯一能够真正满足您要求的工具,因为不同的注册函数可以具有完全不同的签名。但是,要做到这一点,我们的方法需要有所不同 类。

from functools import singledispatch

class Method1():
    pass

class OtherMethods():
    pass

@singledispatch
def f(method, b, c):
    return b + c

@f.register(Method1)
def _(method, b):
    return b

f(Method1(), 12)  # returns 12
f(Method1(), 12, 7) # raises an error
f(OtherMethods(), 12) # raises an error
f(OtherMethods(), 12, 7) # returns 19

现在这不是您所要求的,但参数在签名中是强制执行的。

如果对 singledispatchLiteral 的实现有更多了解的人过来,也许他们可以解释两者之间的相互作用。

一个更简单的方法是简单地定义 c 以默认为某个无效值。

def f(a, b, c=None):
    if a == 'method1':
        c = 0
    return b + c

这解决了如果用户忘记为 method1 之外的方法设置 c 的问题,他们将收到一条(可能是神秘的)错误消息。但是,如果他们在使用 method1 时设置 c,则该值将被默默忽略并可能导致混淆,这并没有解决这个问题。

abc 都是在运行时动态分配的。您无法在签名中弥补这一点。它需要在运行时检测到,您也可以像在其他任何地方一样在 if 中检测。不过,您可以专注于函数名称级别,python 将负责检测参数的数量。

def f(b,c):
    return b + c

def f_method1(b):
    return f(b, 0)

def f_method2(half_a_c):
    return f(0, half_a_c*2)