Is there any possibility to specify how many arguments a lambda as a function argument can take?
For example:
def func(k=lambda x:return x**2):
return k
Could i specify, if k is not the standard lambda, that k is supposed to take exactly one argument?
Max
You could do something like this using inspect.getargspec:
import inspect
def func (k = lambda x: x ** 2):
if not callable(k) or len(inspect.getargspec(k).args) != 1:
raise TypeError('k must take exactly one argument.')
# Do whatever you want
Note that the above will miserably fail with something like (while it shouldn't):
func (lambda x, y = 8: x + y)
...so you will need something a bit more complicated if you want to handle this case:
import inspect
def func (k = lambda x: x ** 2):
if not callable(k):
raise TypeError('k must be callable.')
argspec = inspect.getfullargspec(k)
nargs = len(argspec.args)
ndeft = 0 if argspec.defaults is None else len(argspec.defaults)
if nargs != ndeft + 1:
raise TypeError('k must be callable with one argument.')
# Do whatever you want
Related
Imagine there are three functions, all them accept and return the same type args.
Normally, we can write it as fun3(fun2(fun1(args)), this can be say that a sequence function act on parameter in order, which likes one variety Higher-order functions "map".
You know in Mathematica, we can write this as fun3#fun2#fun1#args.
Now the question is that can we integrate fun3#fun2#fun1 as another fun without modifying their definition, so fun(args) can replace fun3(fun2(fun1(args)), this looks more elegant and concise.
def merge_steps(*fun_list):
def fun(arg):
result = arg
for f in fun_list:
result = f(result)
return result
return fun
def plus_one(arg):
return arg + 1
def double_it(arg):
return arg ** 2
def power_ten(arg):
return arg ** 10
combine1 = merge_steps(power_ten, plus_one, double_it)
combine2 = merge_steps(plus_one, power_ten, double_it)
combine1(3)
> 3486902500
or use lambda:
steps = [power_ten, plus_one, double_it]
reduce(lambda a, f: f(a), steps, 3)
> 3486902500
I think you can use Function Recursion in python to do this.
def function(args, times):
print(f"{times} Times - {args}")
if times > 0 :
function(args,times - 1)
function("test", 2)
Note: I just add times argument to not generate infinite loop.
I'm not certain I understand your question, but are you talking about function composition along these lines?
# Some single-argument functions to experiment with.
def double(x):
return 2 * x
def reciprocal(x):
return 1 / x
# Returns a new function that will execute multiple single-argument functions in order.
def compose(*funcs):
def g(x):
for f in funcs:
x = f(x)
return x
return g
# Demo.
double_recip_abs = compose(double, reciprocal, abs)
print(double_recip_abs(-2)) # 0.25
print(double_recip_abs(.1)) # 5.0
I am implementing this requirement:
As part of a data processing pipeline, complete the implementation of the pipeline method:
The method should accept a variable number of functions, and it
should return a new function that accepts one parameter arg.
The returned function should call the first function in the pipeline
with the parameter arg, and call the second function with the result
of the first function.
The returned function should continue calling each function in the
pipeline in order, following the same pattern, and return the value
from the last function.
For example, pipeline(lambda x: x * 3, lambda x: x + 1, lambda x: x / 2) then calling the returned function with 3 should return 5.0.
My code
def pipeline(*funcs):
def helper(arg):
argCount = len(funcs)
if argCount > 0:
# Iterate over all the arguments and call each lamba's function
res = []
for elem in funcs:
if(len(res) > 0):
helper = elem(res.pop())
else:
helper = elem(arg)
res.append(helper)
helper = res.pop()
else:
return helper
print('before returning, helper value is: ', helper)
return helper
fun = pipeline(lambda x: x * 3, lambda x: x + 1, lambda x: x / 2)
print('final result: ', fun(3)) #should print 5.0
Question
None is returned. Why?
before returning, helper value is: 5.0
final result: None
The problem is that you don't execute a return right after you print. You do have a return in the else branch just before it, but not in the if block. Also, the return helper you have further below does not belong to the def helper function block, so you need one more return helper. I would in fact omit the else block, and just always do the return, like this:
def pipeline(*funcs):
def helper(arg):
argCount = len(funcs)
if argCount > 0:
# Iterate over all the arguments and call each lamba's function
res = []
for elem in funcs:
if(len(res) > 0):
helper = elem(res.pop())
else:
helper = elem(arg)
res.append(helper)
helper = res.pop()
print('before returning, helper value is: ', helper)
return helper # <-------
return helper
It is not really clear why you have a list res, since there is only one value to pass from one function to the next. You could just use arg for this purpose. Furthermore, you use helper in two different senses (function & value) which is quite confusing. The code can be simplified to this:
def pipeline(*funcs):
def helper(arg):
for elem in funcs:
arg = elem(arg)
return arg
return helper
Do not invent what is already available in Python
from functools import reduce
pipeline = [lambda x: x * 3, lambda x: x + 1, lambda x: x / 2]
val = reduce(lambda x, f: f(x), pipeline, 3)
print(val) # 5.0
You do: print('before returning, helper value is: ', helper)... and then do not actually return anything from helper, so it implicitly returns None.
def pipeline(*args):
def helper(num):
for i in args:
total=i(num)
num=total
return total
return helper
fun = pipeline(lambda x: x * 3, lambda x: x + 1, lambda x: x / 2)
print(fun(3)) #should print 5.0
For now I have something in my code that looks like this:
def f(x):
if x == 5:
raise ValueError
else:
return 2 * x
interesting_values = range(10)
result = []
for i in interesting_values:
try:
result.append(f(i))
except ValueError:
pass
f is actually a more complex function and it fails for specific values in an unpredictible manner (I can't know if f(x) will fail or not before trying it).
What I am interested in is to have this result: the list of all the valid results of f.
I was wondering if there is a way to make the second part like a list comprehension. Of course I can't simply do this:
def f(x):
if x == 5:
raise ValueError
else:
return 2 * x
interesting_values = range(10)
result = [f(i) for i in interesting_values]
because the call for f(5) will make everything fail, but maybe there is a way to integrate the try-except structure in a list comprehension. Is it the case?
EDIT: I have control over f.
It seems like you have control of f and can modify how it handles errors.
If that's the case, and None isn't a valid output for the function, I would have it return None on an error instead of throwing:
def f(x):
if x == 5: return None
else: return 2*x
Then filter it:
results = (f(x) for x in interesting_values) # A generator expression; almost a list comptehension
valid_results = filter(lambda x: x is not None, results)
This is a stripped down version of what's often referred to as the "Optional Pattern". Return a special sentinal value on error (None in this case), else, return a valid value. Normally the Optional type is a special type and the sentinal value is a subclass of that type (or something similar), but that's not necessary here.
I'm going to assume here that you have no control over the source of f. If you do, the first suggestion is to simply rewrite f not to throw exceptions, as it's clear that you are expecting that execution path to occur, which by definition makes it not exceptional. However, if you don't have control over it, read on.
If you have a function that might fail and want its "failure" to be ignored, you can always just wrap the function
def safe_f(x):
try:
return f(x)
except ValueError:
return None
result = filter(lambda x: x is not None, map(safe_f, values))
Of course, if f could return None in some situation, you'll have to use a different sentinel value. If all else fails, you could always go the route of defining your own _sentinel = object() and comparing against it.
You could add another layer on top of your function. A decorator if you will, to transform the exception into something more usable. Actually this is a function that returns a decorator, so two additional layers:
from functools import wraps
def transform(sentinel=None, err_type=ValueError):
def decorator(f):
#wraps(f)
def func(*args, **kwargs):
try:
return f(*args, **kwargs)
except err_type:
return sentinel
return func
return decorator
#transform()
def f(...): ...
interesting = range(10)
result = [y for y in (f(x) for x in interesting) if y is not None]
This solution is tailored for the case where you get f from somewhere else. You can adjust transform to return a decorator for a given set of exceptions, and a sentinel value other than None, in case that's a valid return value. For example, if you import f, and it can raise TypeError in addition to ValueError, it would look like this:
from mystuff import f, interesting
sentinel = object()
f = transform(sentinel, (ValueError, TypeError))(f)
result = [y for y in (f(x) for x in interesting) if y is not sentinel]
You could also use the functional version of the comprehension elements:
result = list(filter(sentinel.__ne__, map(f, interesting)))
Suppose I have the following function
def f(x,y,**kwargs):
if 'z' in kwargs:
z = kwargs['z']
else:
z = 0
print(x + y + z)
which takes two arguments and an optional keyword argument. I now want to get a function g that works just as f but for which the value of z is predetermined. Hence, I could do the following
def g(x,y):
z = 3
f(x,y, z = 3)
But what can I do if I do not know the number of non-keyword arguments that f takes. I can get the list of these arguments by
args = inspect.getargspec(f)[0]
But, if I now define g as
g(args):
z = 3
f(args, z=z)
this of course does not work as only one mandatory argument is passed to f. How do I get around this? That is, if I have a function that takes keyword arguments, how do I define a second function exactly the same expect that the keyword arguments take predeterminde values?
You have a few options here:
Define g with varargs:
def g(*args):
return f(*args, z=3)
Or, if you need keyword arguments as well:
def g(*args, **kwargs):
kwargs['z'] = 3
return f(*args, **kwargs)
Use functools.partial:
import functools
g = functools.partial(f, z=3)
See also this related question: Python Argument Binders.
You can use functools.partial to achieve this
import functools
f = functools.partial(f, z=2)
# the following example is the usage of partial function f
x = f(1, 2)
y = f(1, 2, k=3)
z = f(1, 2, z=4)
def funct():
x = 4
action = (lambda n: x ** n)
return action
x = funct()
print(x(2)) # prints 16
... I don't quite understand why 2 is assigned to n automatically?
n is the argument of the anonymous function returned by funct. An exactly equivalent defintion of funct is
def funct():
x = 4
def action(n):
return x ** n
return action
Does this form make any more sense?
It's not assigned "automatically": it's assigned very explicitly and non-automatically by your passing it as the actual argument corresponding to the n parameter. That complicated way to set x is almost identical (net of x.__name__ and other minor introspective details) to def x(n): return 4**n.