调用另一个函数并可选择保留默认参数

时间:2015-12-10 15:31:28

标签: python

我有一个带有一个可选参数的函数,如下所示:

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方式吗?

6 个答案:

答案 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(解释herehere)。具体来说,您可以将所有关键字参数作为字典传递(通常称为**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,您可以创建一个新函数,在运行时指定默认值。你可以将所有这些放在一个装饰器中,这样在你编写代码的地方它会保持整洁,同时仍然让读者知道你想要完成什么。它还允许funBfunA完全相同的调用签名 - 所有参数都可以是位置的,或者所有参数都可以是关键字,或者任何有效的混合,并且任何具有默认值的参数都是可选的。应该与位置参数(*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])))