Marian Rick
Marian Rick

Reputation: 3430

Declare function params outside function to reuse in python

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

Answers (3)

deceze
deceze

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

blhsing
blhsing

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

Vitalii
Vitalii

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

Related Questions