Python Decorators with function arguments - python

I have a simple function, defined as follows:
def simple_function(x):
""" x is an input numpy array"""
return x + 0.1
I want to modify this function by applying some boundary conditions to it. These boundary conditions are themselves functions of x:
def upper_bound(x):
return x**2
def lower_bound(x):
return np.zeros(len(x))
In particular, if the simple_function(x) exceeds the value of upper_bound(x), or falls below lower_bound(x), I want the decorated version of simple_function(x) to return the value upper_bound(x), and likewise for lower_bound. How can I accomplish this behavior using the #decorator syntax in python?

If your arguments, bounds and results are all numpy arrays, you can do a couple of array assignments to clamp each element between the corresponding values returned by your upper_bound and lower_bound functions. The core part is:
r = f(x)
l = lower_bound(x)
u = upper_bound(x)
i = r < l
j = r > u
r[i] = l
r[j] = u
i and j will be Boolean arrays that say which indexes need to be clamped to the lower and upper bounds, respectively. To make this code work as a decorator, you just need to put it inside a pair of nested functions, like so:
def clamp(f):
#functools.wraps(f)
def wrapper(x):
r = f(x)
l = lower_bound(x)
u = upper_bound(x)
i = r < l
j = r > u
r[i] = l
r[j] = u
return r
return wrapper
functools.wraps makes it so the wrapper function copies the name, annotations and docstring of the decorated function.
The code above assumes that you're always using the same upper_bound and lower_bound functions. If you need those to be customizable for different functions you're decorating, you can add an extra layer of nesting and define a "decorator factory" like in Ignacio Vazquez-Abrams's answer:
def clamp(lower_bound, upper_bound): # this is the decorator factory function
def decotator(f): # this is the decorator function
#functools.wraps(f)
def wrapper(x): # this is the wrapper function
... # same code here as above
return r
return wrapper
return decorator

Other than modifying __doc__ et alia, here you are:
def constrain(lower, upper):
def outer(f):
def inner(x):
r = f(x)
u = upper(x)
if r > u:
return u
l = lower(x)
if r < l:
return l
return r
return inner
return outer
...
#constrain(lower_bound, upper_bound)
def simple_function(x):
...
Differing types and the lower bound being higher than the upper bound are not handled.

Related

How to package a sequence functions that act on parameter in order in Python

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

Closing over a variable in Python

In Scheme I can say
(define f
(let ((a (... some long computation ...)))
(lambda (args)
(...some expression involving a ...))))
Then the long computation that computes a will be performed only once, and a will be available inside the lambda. I can even set! a to some different value.
How do I accomplish the same thing in Python?
I've looked at lots of Google references to 'Python closures' and all of them refer to multiple local procedures inside an outer procedure, which is not what I want.
EDIT: I want to write a function that determines if a number is a perfect square. This code works using quadratic residues to various bases, and is quite fast, calling the expensive square root function only 6 times out of 715 (less than 1%) on average:
def iroot(k, n): # newton
u, s = n, n+1
while u < s:
s = u
t=(k-1)*s+n//pow(s,k-1)
u = t // k
return s
from sets import Set
q64 = Set()
for k in xrange(0,64):
q64.add(pow(k,2,64))
q63 = Set()
for k in xrange(0,63):
q63.add(pow(k,2,63))
q65 = Set()
for k in xrange(0,65):
q65.add(pow(k,2,65))
q11 = Set()
for k in xrange(0,11):
q11.add(pow(k,2,11))
def isSquare(n):
if n % 64 not in q64:
return False
r = n % 45045
if r % 63 not in q63:
return False
if r % 65 not in q65:
return False
if r % 11 not in q11:
return False
s = iroot(2, n)
return s * s == n
I want to hide the computations of q64, q63, q65 and q11 inside the isSquare function, so no other code can modify them. How can I do that?
A typical Python closure combined with the fact that functions are first-class citizens in this language looks almost like what you're requesting:
def f(arg1, arg2):
a = tremendously_long_computation()
def closure():
return a + arg1 + arg2 # sorry, lack of imaginantion
return closure
Here, a call to f(arg1, arg2) will return a function which closes over a and has it already computed. The only difference is that a is read-only since a closure is constructed using static program's text (this is, however, may be evaded with ugly solutions, which involve using mutable containers).
As for Python 3, the latter seems to be achievable with nonlocal keyword.
EDIT: for your purpose, a caching decorator seems the best choice:
import functools
def memoize(f):
if not hasattr(f, "cache"):
f.cache = {}
#functools.wraps(f)
def caching_function(*args, **kwargs):
key = (args, tuple(sorted(kwargs.items())))
if key not in f.cache:
result = f(*args, **kwargs)
f.cache[key] = result
return f.cache[key]
return caching_function
#memoize
def q(base):
return set(pow(k, 2, base) for k in xrange(0, base))
def test(n, base):
return n % base in q(base)
def is_square(n):
if not test(n, 64):
return False
r = n % 45045
if not all((test(r, 63), test(r, 65), test(r, 11))):
return False
s = iroot(2, n)
return s * s == n
This way, q(base) is calculated exactly once for every base. Oh, and you could have made iroot and is_square cache-able as well!
Of course, my implementation of a caching decorator is error-prone and doesn't look after memory it consumes -- better make use of functools.lru_cache (at least in Python 3), but it gives a good understanding of what goes on.

Mutiplication of n functions

I want to write a function in Python that returns the multiplication of n functions (f1(x) * f2(x) * f3(x) * ... * fn(x)).
I was thinking in something like:
def mult_func(*args):
return lambda x: args(0)(x) * args(1)(x) ...
but I don't know exactly how to loop through the n functions in args.
Thank you.
Its very simple - just use reduce:
from operator import mul
def mult_func(*args):
return lambda x: reduce(mul, (n(x) for n in args), 1)
That's just a generator expression looping through the functions, and reducing by multiplication.
args is just a tuple, but it will be difficult to iterate over them the way you need to in a lambda expression (unless you use reduce). Define a nested function instead.
def mult_func(*args):
def _(x):
rv = 1
for func in args:
rv *= func(x)
return rv
return _
def mult_func(x, *args):
total = 1
for func in args:
total *= func(x)
return total
Very simply returns the product of all args with input of x.
Quick example:
def square(n):
return n**2
>>> print mult_func(2, square, square)
16
>>> print mult_func(2, square, square, square)
64
It's that time of night, so here's a mutually recursive solution:
def multiply_funcs(funcs):
def inner(x):
if not funcs:
return 1
return funcs[0](x) * multiply_funcs(funcs[1:])(x)
return inner

How to compose to functions several times?

I'm supposed to write a code which gets a mathematical function and a number and gives me as an output a function that is composed n times.
For example if n=3 I would get f(f(f(x))).
When I run my code I get an error, what should I fix in it?
Running examples :
>>> repeated(lambda x:x*x, 2)(5)
624
>>> repeated(lambda x:x*x, 4)(3)
43046721
This is my code :
def repeated(f, n):
g=f
for i in range(n):
g=lambda x: (g(g(x)))
return (g)
Return a new function that does the repeated applying only when called:
def repeated(f, n):
def repeat(arg):
return reduce(lambda r, g: g(r), [f] * n, arg)
return repeat
The reduce() method uses the list of f function references to create the right number of nested calls, starting with arg as the first argument.
Demo:
>>> def repeated(f, n):
... def repeat(arg):
... return reduce(lambda r, g: g(r), [f] * n, arg)
... return repeat
...
>>> repeated(lambda x:x*x, 2)(5)
625
>>> repeated(lambda x:x*x, 4)(3)
43046721
A version that doesn't use reduce() would be:
def repeated(f, n):
def repeat(arg):
res = arg
for _ in range(n):
res = f(res)
return res
return repeat
Depending on the context of your task (e.g. programming class), you might be interested in following straightforward solution:
def repeated(f, n):
if n < 1:
raise ValueError()
elif n == 1:
return f
else:
return lambda x: repeated(f, n-1)(f(x))
This is a naive recursive solution, which maps more directly to the requirements. If you already know about higher functions, such as reduce I suggest to go with Martijn Pieters solutions. Nevertheless this does work:
>>> repeated(lambda x:x*x, 2)(5)
625
>>> repeated(lambda x:x*x, 4)(3)
43046721
I thought this was an interesting enough problem that I wanted to think about it for a couple days before answering. I've created a set of generalizable, pythonic (I think), ways for composing a function on itself in the way described in the question. The most generic solution is just nest, which returns a generator that yields successively nested values of the function on the initial argument. Everything else builds off that, but the decorators could be implemented using one of the above solutions, as well.
#!/usr/bin/env python
"""
Attempt to create a callable that can compose itself using operators
Also attempt to create a function-composition decorator.
f(x) composed once is f(x)
f(x) composed twice is f(f(x))
f(x) composed thrice is f(f(f(x)))
This only makes sense at all if the function takes at least one argument:
f() * 2 -> f(?)
But regardless of its arity, a function can only return exactly one value (even if that value is iterable). So I don't think it makes sense for the function to have >1 arity, either. I could unpack the result:
f(x, y) * 2 -> f(*f(x, y))
But that introduces ambiguity -- not every iterable value should be unpacked. Must I inspect the function to tell its arity and decide whether or not to unpack on the fly? Too much work!
So for now, I just ignore cases other than 1-arity.
"""
def nest(func, arg):
"""Generator that calls a function on the results of the previous call.
The initial call just returns the original argument."""
while True:
yield arg
arg = func(arg)
def compose(n):
"""Return a decorator that composes the given function on itself n times."""
if n < 1: raise ValueError
def decorator(func):
def nested(arg):
gen = nest(func, arg)
for i in range(n):
next(gen)
return next(gen)
return nested
return decorator
class composable(object):
"""A callable that can be added and multiplied."""
def __init__(self, func):
self.func = func
def __add__(self, func2):
"""self(func2(x))"""
def added(a):
return self(func2(a))
return composable(added)
def __mul__(self, n):
"""self * 3 => self(self(self(a)))"""
def nested(a):
gen = nest(self, a)
for i in range(n):
next(gen)
return next(gen)
return composable(nested)
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
#compose(2)
def sq(x):
return x*x
#compose(4)
def qu(x):
return x*x
#composable
def add1(x):
return x + 1
compset = composable(set)
assert (compset + str.split)('abc def') == set(['abc', 'def']), (compset + str.split)('abc def')
assert add1(1) == 2, add1(1)
assert (add1 + (lambda x: x * x))(4) == 17, (add1 + (lambda x: x * x))(4)
assert (add1 * 3)(5) == 8, (add1 * 3)(5)
assert 625 == sq(5), sq(5)
assert 43046721 == qu(3), qu(3)

Referencing a class' method, not an instance's

I'm writing a function that exponentiates an object, i.e. given a and n, returns an. Since a needs not be a built-in type, the function accepts, as a keyword argument, a function to perform multiplications. If undefined, it defaults to the objects __mul__ method, i.e. the object itself is expected to have multiplication defined. That part is sort of easy:
def bin_pow(a, n, **kwargs) :
mul = kwargs.pop('mul',None)
if mul is None :
mul = lambda x,y : x*y
The thing is that in the process of calculating an the are a lot of intermediate squarings, and there often are more efficient ways to compute them than simply multiplying the object by itself. It is easy to define another function that computes the square and pass it as another keyword argument, something like:
def bin_pow(a, n, **kwargs) :
mul = kwargs.pop('mul',None)
sqr = kwargs.pop('sqr',None)
if mul is None :
mul = lambda x,y : x*y
if sqr is None :
sqr = lambda x : mul(x,x)
The problem here comes if the function to square the object is not a standalone function, but is a method of the object being exponentiated, which would be a very reasonable thing to do. The only way of doing this I can think of is something like this:
import inspect
def bin_pow(a, n, **kwargs) :
mul = kwargs.pop('mul',None)
sqr = kwargs.pop('sqr',None)
if mul is None :
mul = lambda x,y : x*y
if sqr is None :
sqr = lambda x : mul(x,x)
elif inspect.isfunction(sqr) == False : # if not a function, it is a string
sqr = lambda x : eval('x.'+sqr+'()')
It does work, but I find it an extremely unelegant way of doing things... My mastery of OOP is limited, but if there was a way to have sqr point to the class' function, not to an instance's one, then I could get away with something like sqr = lambda x : sqr(x), or maybe sqr = lambda x: x.sqr(). Can this be done? Is there any other more pythonic way?
You can call unbound methods with the instance as the first parameter:
class A(int):
def sqr(self):
return A(self*self)
sqr = A.sqr
a = A(5)
print sqr(a) # Prints 25
So in your case you don't actually need to do anything specific, just the following:
bin_pow(a, n, sqr=A.sqr)
Be aware that this is early binding, so if you have a subclass B that overrides sqr then still A.sqr is called. For late binding you can use a lambda at the callsite:
bin_pow(a, n, sqr=lambda x: x.sqr())
here's how I'd do it:
import operator
def bin_pow(a, n, **kwargs) :
pow_function = kwargs.pop('pow' ,None)
if pow_function is None:
pow_function = operator.pow
return pow_function(a, n)
That's the fastest way. See also object.__pow__ and the operator module documentations.
Now, to pass an object method you can pass it directly, no need to pass a string with the name. In fact, never use strings for this kind of thing, using the object directly is much better.
If you want the unbound method, you can pass it just as well:
class MyClass(object):
def mymethod(self, other):
return do_something_with_self_and_other
m = MyClass()
n = MyClass()
bin_pow(m, n, pow=MyClass.mymethod)
If you want the class method, so just pass it instead:
class MyClass(object):
#classmethod
def mymethod(cls, x, y):
return do_something_with_x_and_y
m = MyClass()
n = MyClass()
bin_pow(m, n, pow=MyClass.mymethod)
If you want to call the class's method, and not the (possibly overridden) instance's method, you can do
instance.__class__.method(instance)
instead of
instance.method()
I'm not sure though if that's what you want.
If I understand the design goals of the library function, you want to provide a library "power" function which will raise any object passed to it to the Nth power. But you also want to provide a "shortcut" for efficiency.
The design goals seem a little odd--Python already defines the mul method to allow the designer of a class to multiply it by an arbitrary value, and the pow method to allow the designer of a class to support raising it to a power. If I were building this, I'd expect and require the users to have a mul method, and I'd do something like this:
def bin_or_pow(a, x):
pow_func = getattr(a, '__pow__', None)
if pow_func is None:
def pow_func(n):
v = 1
for i in xrange(n):
v = a * v
return v
return pow_func(x)
That will let you do the following:
class Multable(object):
def __init__(self, x):
self.x = x
def __mul__(self, n):
print 'in mul'
n = getattr(n, 'x', n)
return type(self)(self.x * n)
class Powable(Multable):
def __pow__(self, n):
print 'in pow'
n = getattr(n, 'x', n)
return type(self)(self.x ** n)
print bin_or_pow(5, 3)
print
print bin_or_pow(Multable(5), 5).x
print
print bin_or_pow(Powable(5), 5).x
... and you get ...
125
in mul
in mul
in mul
in mul
in mul
3125
in pow
3125
I understand it's the sqr-bit at the end you want to fix. If so, I suggest getattr. Example:
class SquarableThingy:
def __init__(self, i):
self.i = i
def squarify(self):
return self.i**2
class MultipliableThingy:
def __init__(self, i):
self.i = i
def __mul__(self, other):
return self.i * other.i
x = SquarableThingy(3)
y = MultipliableThingy(4)
z = 5
sqr = 'squarify'
sqrFunX = getattr(x, sqr, lambda: x*x)
sqrFunY = getattr(y, sqr, lambda: y*y)
sqrFunZ = getattr(z, sqr, lambda: z*z)
assert sqrFunX() == 9
assert sqrFunY() == 16
assert sqrFunZ() == 25

Categories

Resources