How to pass (multiple) regex parsed function parameters to a python function - python

I'm trying to build a python class that parses a string and if it matches a regex that looks
like a function call attempt to call that function on the class, passing in any parameters.
For example a string like "foo("a", 20")" would translate to something like self.foo("a", 20).
Here is the code that I have so far..
class FooTranslate(object):
def create_string(self, letter, size):
return letter*size
def run_function(self, func_str):
match = re.match("([\w_]+)\((|[\W\d\w\,]+)\)", func_str)
if match == None:
print "Couldn't match a regex!"
return False
else:
func, fargs = match.groups()
try:
if fargs == "":
return self.__getattribute__(func)()
else:
return self.__getattribute__(func)(eval(fargs))
except AttributeError, e:
print "Invalid function call: %s" % (func)
return False
This code works in the basic cases...
In [1018]: foot = FooTranslate()
In [1019]: foot.run_function("foo()")
Foo!
In [1020]: foot.run_function("bar(2)")
FooFoo
However in the case of using 2 argument functions:
In [1021]: foot.run_function("create_string('a', 2)")
in run_function(self, func_str)
24 return self.__getattribute__(func)()
25 else:
---> 26 return self.__getattribute__(func)(eval(fargs))
27 except AttributeError, e:
28 print "Invalid function call: %s" % (func)
TypeError: create_string() takes exactly 3 arguments (2 given)
The reason why is that the eval() call returns fargs as a tuple, which create_string()
takes as only a single argument. Any idea how I can pass a variable number of arguments
through to a function call? Or have a better alternative way to do this?

You can use the * operator to explode a tuple into separate arguments to a function. For example:
def f(a, b, c):
print a, b, c
If I call f(...) like this:
f((1,2,3))
I get an error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes exactly 3 arguments (1 given)
But if I call it like this:
f(*(1,2,3))
I get:
1 2 3
The * operator will even work if the function takes a variable number of arguments. For example, given the following function:
def f2(a, b, *args):
print a, b,
for x in args:
print x,
print
If I call f2(*(1,2,3,4,5)) it prints:
1 2 3 4 5

Related

python use result of function to decide if function result should be used

Often you want to use None as a return value for functions. Is there a Python idiom to avoid calling a function two times if you want either do one thing if the function returns None and if not use the result of the function. Below is a silly example.
def foo(a, b):
if b == 0:
return(None)
else:
return(a/b)
a = b = 2
if foo(a, b) is None: #Do one thing. 1st call to function.
print('b cannot be null')
else: #Use the result of function. 2nd function call.
print('The result is: ' + str(foo(a,b)) )
Is this stateful way the alternative (with only one function call, but need to assign result, which could be huge, to a variable) ?:
res = foo(a, b)
if res is not None:
print('The result is: ' + str(res) )
else:
print('b cannot be null')
In your example, foo returns None to mean: "Something in the parameters is wrong, and I can't return a valid value".
In that case, it would be clearer to use an exception:
def foo(a, b):
if b == 0:
raise ValueError("b can't be zero")
else:
return a/b
So, if b is null, foo won't return anything - and you won't have to test the return value to check if it's valid, or if it means "something wrong happened". If foo returns something, you're certain that it is a valid result.
Now, to use foo, you would use a try ... except block:
a = 2
b = 0
try:
print('The result is: ' + str(foo(a,b)) )
except ValueError as msg:
print(msg)
# b can't be zero
If you don't put the call to foo in such a block, your program will stop with a nice, informative error message:
foo(a, b)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-36-89e9686ab4be> in <module>()
14 print(msg)
15
---> 16 foo(a, b)
<ipython-input-36-89e9686ab4be> in foo(a, b)
1 def foo(a, b):
2 if b == 0:
----> 3 raise ValueError("b can't be zero")
4 else:
5 return a/b
ValueError: b can't be zero
which is also good, because your program should fail immediately when something goes wrong.

A function that works on a function and returns a function

Suppose I want to define a meta-function that accept a function as an argument and returns a new modified function. Something like
metaf(f) -> f**2
So whatever f would result, metaf would result with the answer to the power of two (and if the result cannot be raised to the power of 2, so be it. Raise an error).
Currently the way I've found to do that requires explicit reference to the argument of f in the definition of metaf, i.e. define
metaf = lambda f, x : f(x)**2
and then
mynewf = lambda x : metaf(f, x)
This works, but I wonder if it will hold for complex argument functions where there could be many variation to the input argument.
So I'm wondering if you can suggest a different way, especially one that does not require specifying the argument in metaf definition.
Edit: Both answers below were helpful. Just for reference, following the answers I've also realized the way to define metaf using lambda expression. Slightly cumbersome, but might still be worth noting:
metaf = lambda func: lambda *args, **kwargs : func(*args, **kwargs)**2
I believe this is what you are after:
def metaf(f):
def func(*r, **kw):
return f(*r, **kw) ** 2
return func
And now let's define some f...
def f(a, b):
return a + b
And here is converting it:
mynewf = metaf(f)
Try it:
In [148]: f(10, 20)
Out[148]: 30
In [149]: mynewf(10, b=20)
Out[149]: 900
Please note the use of both normal argument and keyword argument in the useage of mynewf. I works as you would expect.
You should be able to use *args and **kwargs to gobble up all other arguments and pass them on like so:
def squarer(f):
return lambda *args, **kwargs: f(*args, **kwargs)**2
>>> squarer(lambda x: x+1)(3)
16
>>> squarer(lambda x: x+1)(4)
25
>>> squarer(lambda x,y: x+1)(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in <lambda>
TypeError: <lambda>() takes exactly 2 arguments (1 given)
>>> squarer(lambda x,y=1: x+y)(4)
25
>>> squarer(lambda x,y=1: x+y)(4,2)
36

Apply function to permutations of lists of arguments

I have the need to take a function of n parameters and n lists of values and apply the function to each possible permutation of arguments. I have looked in itertools and none of the functions are quite right. The following is my attempt. Can someone explain what I am doing wrong? Thanks.
def CrossReference(f, *args):
result = []
def inner(g, *argsinner):
rest = argsinner[1:]
a = argsinner[0]
if type(a) is not list:
a = [a]
for x in a:
h = partial(g, x)
if len(rest) > 0:
inner(h, rest)
else:
result.append(h())
inner(f, args)
return result
Here is my example test and error:
def sums(x,y,z):
return x+y+z
CrossReference(sums, [1,2,3], 4, [5,6,7])
Traceback (most recent call last): File "", line 1,
in File "", line 13,
in CrossReference File "", line 12, in inner
TypeError: sums() takes exactly 3 arguments (1 given)
The problem is in the way you call your inner function. You define your function header as:
def inner(g, *argsinner):
But you call your function like:
inner(f, args)
And:
inner(h, rest)
This means that you will end up with a single tuple (monotuple?) containing the tuple of your args. You can either change your function definition to:
def inner(g, argsinner):
Or change your calling to:
inner(h, *rest)
def sums(x,y=0,z=0):
return x+y+z
def apply(fn,*args):
for a in args:
try:
yield fn(*a)
except TypeError:
try:
yield fn(**a)
except TypeError:
yield fn(a)
print list(apply(sums,[1,2,3], 4, [5,6,7]))
is one way you might do it (not the only way though)

How to use the values assigned to variables during string formatting?

So this works:
>>> x = 1
>>> y = 2
>>> "a={a}, b={b}, a+b={c}".format( a=x, b=y, c=x+y )
'a=1, b=2, a+b=3'
But this doesn't:
>>> "a={a}, b={b}, a+b={c}".format( a=x, b=y, c=a+b )
NameError: name 'a' is not defined
Is there any way to make the second one work? (Say for example that x and y are function calls and I don't want to recompute them during string formatting)
The most pythonic (readable, in this case) solution for this is not to use a lambda function, but to cache a and b before the format() call:
a = function_x()
b = function_y()
"a={a}, b={b}, a+b={c}".format(a=a, b=b, c=a+b)
You'll be thankful when looking at the code 6 months from now.
You can do it with lambda:
def x():
return 1
def y():
return 2
>>> "a={a},b={b}, a+b={c}".format(**(lambda a=x(),b=y():{'a':a,'b':b,'c':a+b})())
'a=1,b=2, a+b=3'
this lambda expression is equal to calling predefined function:
def twosumm(a, b):
return {'a':a, 'b':b, 'c': a+b}
>>> "a={a},b={b}, a+b={c}".format(**twosumm(x(), y()))
'a=1,b=2, a+b=3'
Im also think that it is better to use simple and readable solution and just call x() and y() to get results before formatiing:
>>> a, b = x(), y()
>>> "a={a},b={b}, a+b={c}".format(a=a, b=b, c=a+b)
'a=1,b=2, a+b=3'
x = 1
y = 2
def f(x,y):
return (x,y,x+y)
print "a={}, b={}, a+b={}".format( *f(x,y) )
# or
print "a={0[0]}, b={0[1]}, a+b={0[2]}".format( f(x,y) )
.
EDIT
I think your question is wrongly written and that induces blurry understanding of it, and then wrong answers.
x and y are not function calls. As they appear, they are just identifiers
If you evoke function calls, I think it is because, in fact, you wish to obtain the result of something like that:
"a={a}, b={b}, a+b={c}".format( a=f(), b=g(), c=f()+g() )
but without having to write c=f()+g() because it implies that f() and g() are each executed two times.
Firstly, it will forever be impossible in Python to write something like .format( a=x, b=y, c=a+b ) or .format( a=f(), b=g(), c=a+b ) where a and b in c=a+b will refer to the same objects as a and b in a=x and b=y.
Because any identifier at the left side of = is in the local namespace of format() while any identifier at the right side of = is in the namespace outside of the function format().
By the way, that's why the identifiers at the left are called parameters and the identifiers at the right are the identifiers of objects passed as arguments.
Secondly, if you want to avoid writing f() two times (one time as an alone argument and one time in the expression f()+g()), and the same for g(), that means you want to write each only one time, as alone argument.
So , if I understand you well, you essentially wish to write something like that:
"a={a}, b={b}, a+b={}".format( a=f(), b=g() )
With current method str.format , this expression with three replacement fields { } is evidently not correct.
No matter, let's redefine the method format ! And then it's possible to pass only two arguments to format().
def fx(): return 101
def fy(): return 45
class Pat(str):
def __init__(self,s):
self = s
def format(self,x,y):
return str.format(self,x,y,x+y)
p = Pat("a={}, b={}, a+b={}")
print 'p==',p
print p.format(fx(),fy())
result
p : a={}, b={}, a+b={}
a=101, b=45, a+b=146
We can even do more complex things:
from sys import exit
import re
def fx(): return 333
def fy(): return 6
class Pat(str):
def __init__(self,s):
for x in re.findall('(?<=\{)[^}]+(?=\})',s):
if x not in ('A','M'):
mess = " The replacement field {%s] isn't recognised" % x
exit(mess)
self.orig = s
self.mod = re.sub('\{[^}]*\}','{}',s)
def modif(self,R):
it = iter(R)
return tuple(sum(R) if x=='{A}'
else reduce(lambda a,b: a*b, R) if x=='{M}'
else next(it)
for x in re.findall('(\{[^}]*\})',self))
def format(self,*args):
return ''.join(self.mod.format(*self.modif(args)))
print Pat("a={}, b={}, a+b={A}").format(fx(),fy())
print '******************************************'
print Pat("a={}, b={}, c={}, a+b+c={A}").format(fx(),fy(),5000)
print '******************************************'
print Pat("a={}, b={}, a*b={M}").format(fx(),fy())
print '******************************************'
print Pat("a={}, b={}, axb={X}").format(fx(),fy())
result
a=333, b=6, a+b=339
******************************************
a=333, b=6, c=5000, a+b+c=5339
******************************************
a=333, b=6, a*b=1998
******************************************
Traceback (most recent call last):
File "I:\potoh\ProvPy\Copie de nb.py", line 70, in <module>
print Pat("a={}, b={}, axb={X}").format(fx(),fy())
File "I:\potoh\ProvPy\Copie de nb.py", line 51, in __init__
exit(mess)
SystemExit: The replacement field {X] isn't recognised

sqrt() argument after * must be a sequence

First of all, I'm super new to python and I actually search for my problem but the examples were to heavy to understand.
Here is my homework; I need a function which takes two functions as an argument and returns if the results of the two functions are same or not? Basically, it will give either TRUE of FALSE.
For that I wrote:
def f(x,y,z):
k=x(*z)
l=y(*z)
return k == l
The previos code I wrote for single function was working but when I modified it for two function as above, it gives an error as following :
import math
>>> f(math.sqrt,math.cos,5)
Traceback (most recent call last):
File "<pyshell#56>", line 1, in <module>
f(math.sqrt,math.cos,5)
File "D:/Users/karabulut-ug/Desktop/yalanmakinesi.py", line 2, in f
k=x(*z)
TypeError: sqrt() argument after * must be a sequence
>>>
I could not figured it out since the error giving function is normally does not take a sequence. So I dont think it makes a sense :) Any help is appreciated.. Thanks :)
z is just a single number, but the * argument expansion syntax requires that you pass in a sequence (like a list, tuple or str, for example).
Either remove the * (and make your function work for just single arguments), or use *z in the function signature to make z a tuple of 0 or more captured arguments:
def f(x, y, z):
k = x(z)
l = y(z)
return k == l
or
def f(x, y, *z):
k = x(*z)
l = y(*z)
return k == l
The latter now works for functions with more than one argument too:
f(math.pow, math.log, 10, 10)
If you added a **kw argument to the signature, then keyword arguments could be handled too:
def f(x, y, *args, **kwargs):
k = x(*args, **kwargs)
l = y(*args, **kwargs)
return k == l
Here I renamed z to args to better reflect its purpose.
The syntax *z invokes argument unpacking on z. When z is just an integer, there is no iterator behavior defined, and so you see this error. Try:
>>> f(math.sqrt, math.cos, [5])
You need to remove the *. Its for unpacking. So:
def f(x,y,z):
k=x(z)
l=y(z)
return k == l
You use the * operator when you want to pass in an iterable object, like a list or tuple as something thats split up. So, for example:
a = [1,2,3,4,5]
So, for an arbitrary function, f:
f(*a) = f(1,2,3,4,5)

Categories