使用全局变量作为默认值

Den*_*nDo 4 python currying default-value optional-parameters

我有一个函数,它需要很多参数,因为我不想记住它们的位置,所以我决定使用命名参数

def f(a=None, b=None, c=None):
    print a,b,c
f('test', c=5, b='second param')
>>> test second param 5
Run Code Online (Sandbox Code Playgroud)

现在,通常我一次只更改一个参数,所以我想通过只键入f(c = 3.14)来调用函数,其中预期结果为f(a = a,b = b,c = 3.14),即每个应该从本地范围读取未明确传递的参数.

但是当然它不起作用,因为使用命名参数我必须设置一个默认值,如果我使用**kwargs,它只是忽略参数

def f(**kwargs):
    print a,b,c
a=1; b=2; c=3
f(a=2, b=4, c=8)
>>> 1 2 3 # instead of 2 4 8
Run Code Online (Sandbox Code Playgroud)

我曾经为每个参数定义一个新函数,但我不喜欢这种方法,尽管到目前为止它是最有效的

def fc(c_new):
    return f(a, b, c_new)
Run Code Online (Sandbox Code Playgroud)

如何使函数使用当前作用域中的变量作为其命名参数的默认值?

Ale*_*kov 8

这是一个装饰器的解决方案:

from functools import wraps
from inspect import getcallargs


def defaults_from_globals(f):
    @wraps(f)
    def new(**kwargs):
        # filter only those vars, that are in the list of function's named args
        from_globals = {arg: globals()[arg] for arg in getcallargs(f)}
        # overwrite them with user supplied kwargs
        from_globals.update(kwargs)
        return f(**from_gobals)

    return new


@defaults_from_globals
def f(a=None, b=None, c=None):
    return a, b, c


a = 1
b = 2
c = 3

print f(a=2, b=4) # 2 4 3
Run Code Online (Sandbox Code Playgroud)

  • 它可能会导致很少的开销,只能检索与关键字参数同名的全局变量而不是你正在做的其他方式.即`globals_ = globals()`,`from_globals = {k:globals_ [k] for getcallargs(f),如果k in globals_}`.不管怎么说都很好 +1 (3认同)
  • 你已经了解它们(装饰者),你将获得一个非常强大的工具. (2认同)