Reputation: 3430
I have a function that works like a real champ:
def example(
foo: str = None,
bar: str = None
):
return(foo, bar)
I want to wrap this function in another function and pass through the args. Is there a way to declare the function args outside the function, to reuse them in another function?
How I wish it would work:
# this does not work:
ExampleArgs = (foo: str = None, bar: str = None)
def example(ExampleArgs):
return(foo, bar)
def otherFunction(
exampleArgs: ExampleArgs,
other: str = "Yay"
):
list = example(exampleArgs)
# now I got list and can reuse its items / content
# How I would like to use it
result = otherFunction(
exampleArgs =(
foo = "Hey",
bar = "You"
)
)
I have searched for it, but I only did find a lot of information about global used variables.
Upvotes: 1
Views: 661
Reputation: 522015
The way this usually goes in Python is that you pass arguments through using the *args, **kwargs
mechanism:
def inner(foo, bar):
return foo, bar
def outer(other, *args, **kwargs):
res = inner(*args, **kwargs)
print(other, 'result from inner:', res)
outer(42, 'foo', 'bar') # or even outer(42, foo='foo', bar='bar')
outer
here is sort of a wrapper around inner
, accepting all its arguments plus additional arguments. This is hiding inner
as an implementation detail of outer
, but still requires the caller to sort of know about what kinds of arguments inner
accepts (or you need to mirror all of inner
's parameters at least in outer
's documentation, otherwise users may be somewhat lost as to what arguments they're supposed to pass).
An alternative approach would be to leave inner
up to the caller and accept it as a callback:
from functools import partial
def inner(foo, bar):
return foo, bar
def outer(other, inner):
res = inner()
print(other, 'result from inner:', res)
outer(42, partial(inner, 'foo', 'bar')) # alternatively: outer(42, lambda: inner('foo', 'bar'))
The correct design depends on your priorities and goals.
Upvotes: 0
Reputation: 106445
One Pythonic way to achieve what you want (type annotations included) is by defining the desired parameters as a typing.NamedTuple
:
from typing import NamedTuple
class ExampleArgs(NamedTuple):
foo: str = None
bar: str = None
def example(args: ExampleArgs):
return args.foo, args.bar
def otherFunction(
exampleArgs: ExampleArgs,
other: str = "Yay"
):
return example(exampleArgs)
result = otherFunction(
exampleArgs=ExampleArgs(
foo="Hey",
bar="You"
)
)
Upvotes: 1
Reputation: 11
You can define your arguments as a dictionary and then use kwargs of the function. For example:
ExampleArgs = {"foo": None, "bar": None}
Then following your idea:
def example(
foo: str = None,
bar: str = None):
print(foo, bar)
def otherFunction(
other: str = "Yay",
**exampleArgs
):
ex = example(**exampleArgs)
result = otherFunction(
**{"foo": "Hey",
"bar": "You"}
)
Example:
>>> ExampleArgs = {"foo": None, "bar": "Hello"}
>>> example(**ExampleArgs)
None Hello
>>> example(**{"foo": "Hello", "bar": "world!"})
Hello world!
>>> otherFunction(**ExampleArgs)
None Hello
>>> otherFunction(**{"foo": "Hello", "bar": "world!"})
Hello world!
You can even pass only one argument:
>>> otherFunction(**{"foo": "Hello"})
Hello None
>>> otherFunction(**{"bar": "world!"})
None world!
Upvotes: 1