2013-11-27 2 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] для k в getcallargs (f), если k в 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