Home > Mobile >  Function with keyword as default argument
Function with keyword as default argument

Time:09-21

I'm defining a function with some kwargs. I know having an undefined variable as a kwarg default value throws an error. For example:

# This is fine
def foo(word='Ni!'):
    print(word)
foo()
> Ni!

# This won't work
def foo(word=it):
    print(word)
it = 'Ni!'
foo()
> (gives an error)

But is there some way to use the keyword of a kwarg itself as the default value variable name, with the expectation that it will have been defined by the time the function is called?

# This is what I want
def foo(word=word):
    print(word)
word = 'Ni!'  # Note it's defined after function definition, but before function call
foo()
> Ni!

(I'm having trouble searching for answers to this, apologies if it's answered somewhere already!)

CodePudding user response:

Using a global would be an option. But I think using function attributes gives a more clean solution:

def foo(word=None):  # use 'None' as sentinel
    if word is not None:
        print(word)
    else:  # get the current default value from a function attribute
        print(getattr(foo, 'default_word', 'default'))


foo()  # use default first time
foo.default_word = 'changed default'  # change the default
foo()  # gets the new default
foo('hi')  # use argument

Result:

default
changed default
hi

CodePudding user response:

But is there some way to use the keyword of a kwarg itself as the default value variable name, with the expectation that it will have been defined by the time the function is called?

The short answer here is no, what you are trying to do isn't possible in this exact way. This is because the default value must be known at the time of the def when the interpreter sets the function name to the value of the function object.

CodePudding user response:

Decorator is a possible option:

from functools import wraps


def kwd_load_globals(**kwd2name):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            f_globals = func.__globals__
            for kwd in kwd2name.keys() - kwargs.keys():
                try:
                    kwargs[kwd] = f_globals[kwd2name[kwd]]
                except KeyError:
                    pass
            return func(*args, **kwargs)
        return wrapper
    return decorator


@kwd_load_globals(word='word')
def foo(word):
    print(word)


word = 1
foo()    # 1
  • Related