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

Question:

I stumbled upon the following problem on a python challenge: Write a function that satisfies the following rule for any number of function calls.

f()()()()()(s) == 'fooooo' + s;

example:

f('it') == 'fit';
f()('x') == 'fox';
f()()('bar') == 'foobar';
f()()()('l') == 'foool';

The function should be stateless and should not use any variables outside the scope.

The function signature was:

def f(s=None):
    # Your code here

I thought that in order to be able to chain multiple calls we will have to return a function when no string is passed into the function, but can’t figure out how to build the expected string with no external variables. Suggestions?

def f(s=None):
    if s is None:
        # concatenate an 'o'?
        return f
    else:
        # Last call, return the result str.
        return s
Asked By: Javi

||

Answers:

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
Answered By: Nikola Dimitroff

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.

Answered By: sloth

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
Answered By: Olvin Roght

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)

:^)

Answered By: GBrandt

Just for printing the string:

def f(s=None):
    def fo(s=None):
        if s==None:
            print('o',end='')
            return fo
        else:
            print(s)
            return
    if s!=None:
        print('f',end='')
        print(s)
        return
    elif s==None:
        print('fo',end='')
        return fo
Answered By: Anay Khator

Cute problem. This is a compact way to do it:

def f(s=None, prefix="f"):
    if s: return prefix + s
    return lambda s=None: f(s, prefix=prefix+"o")
Answered By: fpbhb

FP:

f=lambda s=None,prefix='f':prefix+s  if s else lambda s=None,prefix=prefix+'o':f(s,prefix)  
Answered By: DevineLiu
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.