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
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:
- You can define functions inside other functions
- 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
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
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)
:^)
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
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")
FP:
f=lambda s=None,prefix='f':prefix+s if s else lambda s=None,prefix=prefix+'o':f(s,prefix)
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
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:
- You can define functions inside other functions
- 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
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
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)
:^)
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
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")
FP:
f=lambda s=None,prefix='f':prefix+s if s else lambda s=None,prefix=prefix+'o':f(s,prefix)