使用全局变量作为默认值

时间:2013-11-27 11:31:51

标签: python default-value optional-parameters currying

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

def f(a=None, b=None, c=None):
    print a,b,c
f('test', c=5, b='second param')
>>> test second param 5

现在,通常我一次只更改一个参数,所以我想只通过键入来调用该函数 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

我曾经为每个参数定义一个新函数,但我不喜欢这种方法,尽管它迄今为止效果最好

def fc(c_new):
    return f(a, b, c_new)

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

4 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:1)

为了完整起见,这里是我刚刚发现的另一个解决方案,它更像是一个肮脏的黑客,因为在大多数情况下使用exec是不受欢迎的*但是它更容易理解。

* )在这种情况下,用户可以控制代码,故意搞砸自己的工作不符合他的利益

def f(x=None, y=None, z=None):
    for  key,val in locals().items():
        if val==None: exec("%s = globals()[key]"%key)
    print x,y,z

答案 2 :(得分:0)

我认为你应该使用装饰器

import functools

_last_args = {}
def foo(f):
    @functools.wraps(f)
    def wrapper( *args, **kwargs):
        _last_args.update(kwargs)
        ret =  f(*args, **_last_args)
        return ret
    return wrapper

@foo
def bar(a=None,b=None,c=None):
    print(a,b,c)

bar(a=1,b=2,c=3)
bar(a=10,b=20)
bar(a=100)

打印:

1 2 3
10 20 3
100 20 3

答案 3 :(得分:-2)

要在python中初始化全局变量,它应该是全局密钥

试试这个:

def f(a=None, b=None, c=None):
    print a,b,c

global a=1
global b=2
global c=3
f(a=2, b=4, c=8)
>>>2,4,8