here's my problem:
given any two functions, eg. f(x,a) and g(x,b), I want to build a new function, say F(f,g), which returns the product of the f and g. So:
F(f,g) = f*g = f(x, a) * g(x, b) = F(x, a, b)
I want to do this hardcoding the least possible. So, for h(x, c, d), I would get F(f,h) = F(x, a, c, d).
Given that then I want to minimize F, I thought of building a class. Here's a MWE:
import numpy as np
from inspect import getargspec
def f(x, a):
return np.tanh(x*a)
def g(x, b):
return np.power(x,b)
def h(x, c, d):
return x*c+np.log(x)
class fit_func(object):
def __init__(self, data, *args):
self.data = data
self.func_a = args[0]
self.func_b = args[1]
self.args_a = getargspec(args[0])[0][1:]
self.args_b = getargspec(args[1])[0][1:]
at this point, I thought of including the following __call__ method:
def __call__(self, *self.args_a, *self.args_b):
return self.func_a(self.data,self.args_a)*self.func_b(data,self.args_b)
I thought: this way an instance of the class, say F = fit_func(some_data_array,f,g), would be callable as F(a,b). However, python doesn't like the self.args_a and self.args_b among the arguments of __call__ and I understand why.
Does anybody know a clever way to obtain this? Thank you very much in advance
If you just accept positional arguments you better to save the length of arguments for each functions, and then pas proper slices of args to each function in call method:
import numpy as np
from inspect import getargspec
class fit_func(object):
def __init__(self, *args):
self.func_a = args[0]
self.func_b = args[1]
self.size_arg_a = len(getargspec(self.func_a)[0])
self.size_arg_b = len(getargspec(self.func_b)[0])
def __call__(self, *args):
return self.func_a(*args[:self.size_arg_a]) * self.func_b(*args[self.size_arg_b-1:])
Demo:
def f(x, a):
return np.tanh(x*a)
def h(x, c, d):
return x*c+np.log(x)
F = fit_func(f, h)
print(F(3, 4, 3, 5, 7))
16.0986122875
If you want to pass keyword arguments to final function:
import numpy as np
from inspect import getargspec
from operator import itemgetter
class fit_func(object):
def __init__(self, *args):
self.func_a = args[0]
self.func_b = args[1]
self.arg_a = getargspec(self.func_a)[0]
self.arg_b = getargspec(self.func_b)[0]
def __call__(self, **kwargs):
arg_a = itemgetter(*self.arg_a)(kwargs)
arg_b = itemgetter(*self.arg_b)(kwargs)
return self.func_a(*arg_a) * self.func_b(*arg_b)
Demo:
def f(x, a):
return np.tanh(x*a)
def h(x, c, d):
return x*c+np.log(x)
F = fit_func(f, h)
print(F(x=3, a=4, c=5, d=7))
16.0986122875
Related
If I have an expression x = Symbol('x') and f1=x**2 and I want to further add some f2 where f2 = interp1d(t, y) is scipy interpolation. How does one turn f2 into an expression such that I have somthing like f = x**2 + f2(x) so that I can later evaluate f as f.subs(x, some_number)?
Due to specification of the code, I can't evaluate f1 and f2 separatelly and then add the resulting numbers, I need to be able to add it to an existing sympy expression and evaluate it using something like .subs()
One way but it requires hard-coding the function to be called in the class:
f2 = lambda t: np.sin(t)
class MyFunc(Function):
#classmethod
def eval(cls, arg):
arg = sympify(arg, strict=True)
if arg.is_Number:
return sympify(f2(float(arg)), strict=True)
More like Davide's answer but with a couple of fixes:
class FuncWrapper(Symbol):
"""Wraps a python callable as a Basic instance"""
def __new__(cls, func, name):
obj = super().__new__(cls, name)
obj._wrapped = func
return obj
#property
def wrapped(self):
return self._wrapped
def _hashable_content(self):
return (self.wrapped,) # needed for __eq__
def eval(self, arg):
if arg.is_Number:
return sympify(self.wrapped(float(arg)))
def __call__(self, arg):
return Call(self, arg)
class Call(Function):
#classmethod
def eval(cls, func, arg):
arg = sympify(arg)
result = func.eval(arg)
if result is not None:
return result
With that you have:
In [61]: f = FuncWrapper(np.sin, 'f')
In [62]: x + f(x)
Out[62]: x + Call(f, x)
In [63]: _.subs(x, 1)
Out[63]: 1.84147098480790
One very risky way would be to create a wrapper object for your numerical function, like this:
from sympy import *
import numpy as np
var("x")
# symbolic expression
f1 = cos(x)
# numerical function
f2 = lambda t: np.sin(t)
class MyFunc(Expr):
"""Create a symbolic wrapper to a numerical function."""
def __new__(cls, arg, **kwargs):
obj = Expr.__new__(cls, **kwargs)
obj._custom_func = arg
return obj
def _subs(self, old, new, **hints):
return self._custom_func(float(new))
expr = f1 + MyFunc(f2)
expr.subs(x, np.pi/4)
# out: 1.41421356237309
I wanted to implement a sort of facade pattern in python. However because I need to do the same for all methods, I'd like to do it in a generic way. Let me use an example:
class MyObject:
def __init__(self, *args, **kwargs):
# do something with args/kwargs
def method1(self, x):
# do something
def method2(self, x, a):
# do something
def method3(self, x, a, b):
# do something
class MyFacade:
def __init__(self, *args, **kwargs):
self.x = SOMETHING
self.obj = MyObject(*args, **kwargs)
def method1(self):
return self.obj.method1(self.x)
def method2(self, a):
return self.obj.method2(self.x, a)
def method3(self, a, b):
return self.obj.method3(self.x, a, b)
Now because I have several classes like MyObject, I'd like a generic way of creating a MyFacade for each of them without having to write code for each method (they all do more or less the same). Also if MyObject changes, I'd like MyFacade not being impacted and rather handle any interface change in MyObject transparently.
Thanks for the help!
EDIT:
This works but methods inherited from MyInterface raise TypeError because of the extra argument.
class MyObject:
def method1(self, x):
print(x)
def method2(self, x, a):
print(x, a)
def method3(self, x, a, b):
print(x, a, b)
class MyInterface:
def methodX(self):
print("YAY!")
class MyFacade(MyInterface, MyObject):
def __init__(self):
self.x= "WHATEVER"
def __getattribute__(self, item):
result = super().__getattribute__(item)
if callable(result):
return lambda *args, **kwargs: result(self.x, *args, **kwargs)
return result
EDIT:
I modified condition this way and now problem with MyInterface is gone:
if callable(result) and result.__name__ in MyObject.__dict__:
The obvious way of doing this is to use the fact that class and function names are variables and can be assigned so MyFacade could be defined as follows:
class MyFacade:
def __init__(self,obj, *args, **kwargs):
self.x = SOMETHING
self.obj = obj(*args, **kwargs)
def method1():
return self.obj.method1(self.x)
def method2(a):
return self.obj.method2(self.x, a)
def method3(a, b):
return self.obj.method1(self.x, a, b)
and the set-up call would be eg:
fasc = MyFscade(MyOject,*args,**kwargs)
I have many class like SpaceA, SpaceB, SpaceC, and so on. These classes have some similar methods, for example method_1, method_2, ..., method_n. But for specific class, it maybe not been implement all the method_i. The following is an example:
import numpy as np
class SpaceA(object):
def method_1(self, array, b, c=None):
print('method_1', array, b, c)
def method_2(self, array, b, c=None):
print('method_2', array, b, c)
def method_3(self, array, b, c=None):
print('method_2', array, b, c)
... # many methods
class SpaceB(object):
...
def method_1(self, array, b, c=None):
print('method_1', array, b, c)
def method_2(self, array, b, c=None):
print('method_2', array, b, c)
def method_3(self, array, b, c=None):
print('method_2', array, b, c)
... # many methods
I want to define another class named Function like following:
class Function(np.ndarray):
def __new__(cls, space, array=None):
if array is None:
self = np.zeros(100).view(cls)
else:
self = array.view(cls)
self.space = space
return self
def method_1(self, b, c=None):
return self.space.method_1(self, b, c=c)
def method_2(self, b, c=None):
return self.space.method_2(self, b, c=c)
... # many wrapper
A = SpaceA()
B = SpaceB()
fA = Function(A)
fB = Function(B)
I want to automatically wrap every method_i of a specific class into Function class, is it possible? and how?
Maybe __metaclass__ can solve my problem, but I don't make it success.
Thanks very much for #quamrana's comment, I code a new Function class like following:
import numpy as np
from types import ModuleType
class Function(np.ndarray):
def __new__(cls, space, dim=None, array=None):
if array is None:
self = space.array(dim=dim).view(cls)
else:
self = array.view(cls)
self.space = space
return self
def index(self, i):
return Function(self.space, array=self[:, i])
def __call__(self, bc, index=None):
space = self.space
return space.value(self, bc, index=index)
def value(self, bc, index=None):
space = self.space
return space.value(self, bc, index=index)
def __getattr__(self, item):
def wrap(func):
def outer(*args, **kwargs):
val = func(self, *args, **kwargs)
return val
outer.coordtype = func.coordtype
return outer
if hasattr(self.space, item):
self.__dict__[item]= wrap(getattr(self.space, item))
return self.__dict__[item]
else:
print('The function space has not implemented method {}'.format(item))
which can solve my problem exactly.
I want to pass a function to a class when I initialize it. Here's a toy example I came up with and it works:
def addition(self):
return self.a + self.b
def multiplication(self):
return self.a * self.b
class Test:
def __init__(self, a, b, fcn):
self.a = a
self.b = b
self.fcn = fcn
t = Test(3, 3, addition)
print t.fcn(t)
t = Test(3, 3, multiplication)
print t.fcn(t)
Is it possible to simply call t.fcn() as you would any other class method?
did you try it?
the answer is yes
def do_op(x,y,fn):
return fn(x,y)
def add(a,b):
return a+b
print do_op(5,4,add)
same with a class
class whatever:
def __init__(self,fn):
self.fn = fn
def do_it(self,*args,**kwargs):
return self.fn(*args,**kwargs)
#if you wanted the fn to have self as the first argument
#return self.fn(self,*args,**kwargs) #just pass self as first argument
x = whatever(add)
print x.do_it(5,8)
further along what you are asking for (if im reading it right)
def add(self):
return self.a + self.b
class whatever:
def __init__(self,fn,a,b):
self.__dict__[fn.__name__] = fn
self.a,self.b = a,b
def do_it(self):
return self.fn(self)
x = whatever(add,6,7)
x.do_it()
or perhaps you want something like
from functools import partial
def add(self):
return self.a + self.b
class whatever:
def __init__(self,fn,a,b):
self.__dict__[fn.__name__] = partial(fn,self)
self.a,self.b = a,b
x = whatever(add,5,6)
x.add()
this kind of introspection is somewhat risky in deployed code ...
For the sake of learning, I'm trying to chain decorators that are defined by classes. I read this question about decorators, which has a lot of good information about chaining them with functions. They also link to the documentation, but I'm trying to figure out simpler examples.
Basically, I'm trying to mimic similar behaviour using classes. Here is my first decorator definition, which works perfectly.
class square_result(object):
def __init__(self, f):
pass
def __call__(self, x, y):
return (x+y)**2
#square_result
def add_two_numbers(x, y):
return x + y
print(add_two_numbers(2,5)) #Outputs 49, as expected
Then, I add another decorator to create this code snippet:
class square_result(object):
def __init__(self, f):
pass
def __call__(self, x, y):
return (x+y)**2
class append_abc(object):
def __init__(self, f):
pass
def __call__(self, *args):
return str(*args) + "abc"
#append_abc
#square_result
def add_two_numbers(x, y):
return x + y
print(add_two_numbers(2,5))
#Ideally, this should print "49abc" but prints "(2,5)abc" instead
what is the proper way of doing this? I guess what I want to do is create a decorator in the form of a class that takes the output of the function it decorates (in this case square_result) and appends "abc" to it.
I know that when I add a decorator to my code, the add_two_numbers() function is compiled and that function object is passed to the square_result class, which does something to create a function-like object which is substituted for the original add_two_numbers(). However, I'm not sure how to chain this.
This does what you want:
class square_result(object):
def __init__(self, f):
pass
def __call__(self, x, y):
return (x+y)**2
class append_abc(object):
def __init__(self, f):
self.f = f
def __call__(self, *args):
return str(self.f(*args)) + "abc"
#append_abc
#square_result
def add_two_numbers(x, y):
return x + y
print(add_two_numbers(2,5))
You need to actually run the inner function in the decorator if you want to use its output in the result of the decorator.
I didn't edit your first decorator, as it does what you want, but it actually isn't useful as a decorator. Since its output is not related in any way to the function it's decorating, it's just replacing the function. If you wanted to replace the function with that class, the way to do it would be
class square_result(object):
def __call__(self, x, y):
return (x+y)**2
# this has no effect at all after the reassignment
def add_two_numbers(x, y):
return x + y
add_two_numbers = square_result()
PEP8 also suggests CamelCase for your class names (SquareResult).
square_result doesn't "decorate" the add_two_numbers result, but overrides it (doing the addition as well as the squaring). It should instead treat the decorated function the same way that append_abc does, by storing it and then making use of the decorated function in its own implementation. Thus:
class square_result(object):
def __init__(self, f):
self.function = f
def __call__(self, *args):
return self.function(*args)**2
class append_abc(object):
def __init__(self, f):
self.function = f
def __call__(self, *args):
return str(self.function(*args)) + "abc"
#append_abc
#square_result
def add_two_numbers(x, y):
return x + y
print(add_two_numbers(2,5))