2013-11-27 109 views
3

我有需要大量的參數,因爲我不想記住它們的位置的功能,我決定使用命名參數使用全局變量的缺省值

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) 

如何使功能使用的變量在其目前的範圍爲默認值的命名參數?

+0

您沒有使用函數中的關鍵字參數! – volcano

+0

@volcano就是這一點。 – BartoszKP

+0

所有函數參數都有名稱。我認爲你的意思是關鍵字參數。 – martineau

回答

6

這是一個帶裝飾的解決方案:

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) 
     f(**from_gobals) 

    return new 


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


a = 1 
b = 2 
c = 3 

f(a=2, b=4) # 2 4 3 
+0

很好的答案!恕我直言,唯一一個點擊。 – BartoszKP

+0

花了我一段時間來弄清楚什麼是實際的目標)。 –

+3

它可能會導致僅僅檢索與關鍵字參數具有相同名稱的全局變量而不是其他方式的開銷,而不像您正在做的那樣。即'globals_ = globals()','from_globals = {k:globals_ [k] for k in getcallargs(f)if k in globals_}'。無論好的答案。 +1 – martineau

-2

在Python初始化的全局變量應該是全球性的keword

試試這個:

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 
+0

錯誤的,使用全局的唯一理由 - 在函數內,當你想要改變全局參數時,這總是一個壞主意。 – volcano

+0

我沒有投票給你,但有一件事,那不是''global''關鍵字的作用。 – martineau

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 
+0

使用裝飾器的好的呼叫,但這不是OP想要的 – BartoszKP

+0

我認爲當他說範圍時,他意味着要獲取以前的範圍,因爲如果它只是範圍中的默認值,他會將它們保存爲函數中的默認值,而不是沒有。也許是錯的 –

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