我有一个带有一个可选参数的函数,如下所示:
def funA(x, a, b=1):
return a+b*x
我想编写一个调用funA
的新函数,并且还有一个可选参数,但是如果没有传递参数,我想保留funA
中的默认值。
我在想这样的事情:
def funB(x, a, b=None):
if b:
return funA(x, a, b)
else:
return funA(x, a)
有更多的pythonic方式吗?
答案 0 :(得分:16)
我会将if b
替换为if b is not None
,这样如果您将b=0
(或任何其他“虚假”值)作为参数传递给funB
,它将被传递给funA
funB
。
除此之外,对我来说它似乎相当狡猾:清晰明确。 (虽然可能有点无用,取决于你想要做什么!)
更加神秘的方式依赖于使用正确的关键字参数调用funB(3, 2, b=4)
(例如def funB(x, a, **kwargs):
return funA(x, a, **kwargs)
:
#include <iostream>
using namespace std;
// Pass by value
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
};
答案 1 :(得分:8)
def funA(x, a, b=1):
return a+b*x
def funB(x, a, b=1):
return funA(x, a, b)
在b=1
中设置默认值funB()
,然后将其始终传递给funA()
答案 2 :(得分:3)
你这样做的方式很好。另一种方法是bff0e554
bff0e554
具有与funB
相同的默认值,因此您可以直接传递相同的参数。例如,如果你funA
,那么你可以随时拨打def funB(x, a, b=1)
。
对于简单的情况,上述方法可以正常工作。对于更复杂的情况,您可能希望使用return funA(x, a, b)
和*args
(解释here和here)。具体来说,您可以将所有关键字参数作为字典传递(通常称为**kwargs
)。在这种情况下,每个函数都会设置自己的独立默认值,您只需通过以下内容传递整个字典:
kwargs
如果传递给def funA(x, a, **kwargs):
b = kwargs.get("b", 1)
return a+b*x
def funB(x, a, **kwargs):
return funA(x, a, **kwargs)
时kwargs
为空(未指定funB
),则b
语句将funA
设置为默认值b = kwargs.get("b", 1)
}。如果指定了b
,它将按原样传递。请注意,在funB
中,您可以使用其自己的独立默认值访问b
,并仍然可以获得您要查找的行为。
虽然这对你的例子来说似乎有些过分,但如果函数足够复杂,在函数开头提取几个参数并不是什么大问题。它还为您提供了更大的灵活性(例如避免了许多常见的gotchas)。
答案 3 :(得分:2)
使用FunctionType
中的types
,您可以创建一个新函数,在运行时指定默认值。你可以将所有这些放在一个装饰器中,这样在你编写代码的地方它会保持整洁,同时仍然让读者知道你想要完成什么。它还允许funB
与funA
完全相同的调用签名 - 所有参数都可以是位置的,或者所有参数都可以是关键字,或者任何有效的混合,并且任何具有默认值的参数都是可选的。应该与位置参数(*args
)和关键字参数(**kwargs
)配合使用。
import inspect
from types import FunctionType
def copy_defaults(source_function):
def decorator(destination_function):
"""Creates a wrapper for the destination function with the exact same
signature as source_function (including defaults)."""
# check signature matches
src_sig = inspect.signature(source_function)
dst_sig = inspect.signature(destination_function)
if list(src_sig.parameters) != list(dst_sig.parameters):
raise ValueError("src func and dst func do not having matching " \
"parameter names / order")
return FunctionType(
destination_function.__code__,
destination_function.__globals__,
destination_function.__name__,
source_function.__defaults__, # use defaults from src
destination_function.__closure__
)
return decorator
def funA(x, a, b=1):
return a+b*x
@copy_defaults(funA)
def funB(x, a, b):
"""this is fun B"""
return funA(x, a, b)
assert funA(1, 2) == funB(1, 2)
assert funB.__name__ == "funB"
assert funB.__doc__ == "this is fun B"
答案 4 :(得分:1)
使用inspect.getargspec
,您可以获取默认值(返回的元组的第四项= defaults
):
import inspect
def funA(x, a, b=1):
return a + b * x
# inspect.getargspec(funA) =>
# ArgSpec(args=['x', 'a', 'b'], varargs=None, keywords=None, defaults=(1,))
def funcB(x, a, b=inspect.getargspec(funA)[3][0]):
return funA(x, a, b)
OR(在Python 2.7 +中)
def funcB(x, a, b=inspect.getargspec(funA).defaults[0]):
return funA(x, a, b)
在Python 3.5+中,建议改为使用inspect.signature
:
def funcB(x, a, b=inspect.signature(funA).parameters['b'].default):
return funA(x, a, b)
答案 5 :(得分:0)
您也可以使用:
def funA(x, a, b=1):
return a+b*x
def funB(x, a, b=None):
return funA(*filter(lambda o: o is not None, [x, a, b]))
如果x或a为None,则不会失败的版本:
def funB(x, a, b=None):
return funA(*([x, a]+filter(lambda o: o is not None, [b])))