How to chain Python function calls so the behaviour is as follows

This is my go at it:

def f(x=None, seq=''):
    if x:
        return 'f' + seq + x
    else:
        def g(y=None, p=seq + 'o'):
            return f(y, p)
        return g

Edit If you really need the function signature to be f(x=None), use this:

def f(x=None):
    def f_(x=None, seq=''):
        if x:
            return 'f' + seq + x
        else:
            def g(y=None, p=seq + 'o'):
                return f_(y, p)
            return g
    return f_(x)

:^)


An alternative to Nikola's answer is something like this:

def f(s=None):
    if s: return f'f{s}'

    def factory(prefix):
        def inner(s=None):
            return f'f{prefix}{s}' if s else factory(prefix + 'o')
        return inner
    return factory('o')

using a closure and no helper function.


You can try this:

def f(s=None):
    string = "f"
    def ret(p=None):
        nonlocal string
        string += "o"
        return ret if not p else string + p
    return ret if not s else string + s

Obviously, you need to store the number of 'o' somewhere in the memory (e.g. the code) of f. To achieve this, you can benefit from these 2 features of Python:

  1. You can define functions inside other functions
  2. There's this thing called argument binding which allows you to tell Python to fix the some or all of the arguments of your function. This is done through functools.partial

And here's the solution

from functools import partial

def f(s=None):
    # Define a new function g which takes the current text and takes s
    def g(current_text, s=None):
        if s is not None:
            return current_text + s
        else:
            # If called with an empty argument, just rebind current_text with an extra o
            return partial(g, current_text + "o")

    # Just call g with the initial conditions
    return g("f", s)

print(f()()()()()("s")) # fooooos
print(f("s")) # fs

Tags:

Python