python wrap function with function - python

I have these two functions below. I want to run validate first then child but I want to decorate child with validate so I can tell it to run validate on the given input first and then pass the output to child to run on it.
def validate(x, y):
print(x, y)
x = x+2
y = y +1
return x, y
def child(x, y):
print(x)
print(y)
return x, y
How can I do it?
Obviously, this does not work:
def validate(x):
print(x)
x = x+2
return x
#validate
def child(x):
print(x)
return x
I want to achieve something like this but in decorator way:
child(validate(2))
EDIT:
I have some method 'data_parsing' that takes the input and does some login on the inputed data. The data may be malfunction so I have create a class with methods which validate the inputted data first. I instantiate the class and run the validation first raising exceptions if data is malformed. if successfull i step to next function call data_parsing() which takes data and processes it. so the logic is:
def execute(data):
validator_object(data).run()
data_parsing(data)
EDIT:
def validator(fnc):
def inner(*aaa):
a,b = aaa
a += 4
return fnc(a,b)
return inner
#validator
def child(*aaa):
a,b = aaa
print(a)
return a
a = 1
b = 2
child(a, b)

Be aware that #decorator form is applied on function declaration phase, it'll wrap the target function at once.
You may use the following implementation for your case:
def validate(f):
#functools.wraps(f)
def decor(*args, **kwargs):
x, y = args
if x <= 0 or y <= 0:
raise ValueError('values must be greater than 0')
print('--- validated value', x)
print('--- validated value y', y)
x = x+2
y = y+1
res = f(x, y, **kwargs)
return res
return decor
#validate
def child(x, y):
print('child got value x:', x)
print('child got value y:', y)
return x, y
child(3, 6)
child(0, 0)
Sample output:
--- validated value x 3
--- validated value y 6
child got value x: 5
child got value y: 7
Traceback (most recent call last):
File "/data/projects/test/functions.py", line 212, in <module>
child(0, 0)
File "/data/projects/test/functions.py", line 195, in decor
raise ValueError('values must be greater than 0')
ValueError: values must be greater than 0

Related

Init a generator

I have the following generator function which adds two numbers:
def add():
while True:
x = yield "x="
y = yield "y="
print (x+y)
And I can call it like this:
x=add()
next(x)
'x='
x.send(2)
'y='
x.send(3)
# 5
I thought it would be trivial to add in an init so that I don't have to do the next and I can just start sending it values, and so I did:
def init(_func):
def func(*args, **kwargs):
x=_func(*args, **kwargs)
next(x)
return x
return func
Or, simplifying it to receive no input variables like the function above:
def init(func):
x=func()
next(x)
return x
I thought that doing:
x=init(add) # doesn't print the "x=" line.
x.send(2)
'y='
x.send(3)
5
Would work, but it seems it acts just like as if the init is not there at all. Why does this occur, and how can I get rid of that behavior?
It seems to work for me. Tried
def add():
while True:
x = yield 'x='
y = yield 'y='
print (x+y)
def init(func):
x=func()
next(x)
return x
a = init(add)
a.send(5)
a.send(10)
For me this returns 15, as expected.
[update]
After your update, I think you might just want to print out the a.send():
def add():
while True:
x = yield 'x='
y = yield 'y='
print (x+y)
def init(func):
x=func()
print(next(x))
return x
a = init(add)
print(a.send(5))
a.send(10)
Your code works as-is, however, if you want to print the output that occurs before the field yield statement, then you can adapt the init method to do just that. For example:
def init(func):
x=func()
a=next(x)
if a: print (a) # this line will print the output, in your case 'x='
return x
And now you have:
>>> x=init(add)
x=
>>> x.send(2)
'y='
>>> x.send(3)
5
And finally, to keep your more generalized approach, you can do something like the following with a decorator:
def init_coroutine(_func):
def func(*args, **kwargs):
x=_func(*args, **kwargs)
_ = next(x)
if _: print (_)
return x
return func
#init_coroutine
def add():
while True:
x = yield "x="
y = yield "y="
print (x+y)
>>> x=add()
x=
>>> x.send(2)
'y='
>>> x.send(3)
5

Calling one of multiple inner functions from one of the outer variables function in python

Given one of those:
def operations(x, y, z):
def add(x,y):
return x+y
def sub(x,y):
return x-y
return z(x,y)
--------------------------------------------------
def operations(x, y, z):
if z == add:
def add(x,y):
return x+y
if z == sub:
def sub(x,y):
return x-y
res = z(x,y)
return res
I'm trying to call one of multiple inner functions from one of the outer variables function in python but I get this errors:
result = operations(10,5,add)
=>
NameError: name 'add' is not defined
--------------------------------------------------
result = operations(10,5,"add")
=>
TypeError: 'str' object is not callable
I know i could use this solution:
def add(x,y):
return x+y
def sub(x,y):
return x-y
def operations(x, y, z):
return z(x,y)
But for me it seems clearer to use nested functions.
I also read this:
Short description of the scoping rules?
But it didn't really helped me.
Your current approach unnecessarily redefines each of add, subtract, etc every time operations is called, not just once when operations is defined. If you want to isolate the individual operations to their own namespace, use a class.
class OperatorApplication:
#staticmethod
def add(x, y):
return x + y
#staticmethod
def subtract(x, y):
return x - y
OperatorApplication.add(x, y)
Here's what I could come up with:
def operations(x, y, z: str):
def add(x, y): return x + y
def sub(x, y): return x - y
# ...
if z == 'add':
return add(x, y)
elif z == 'sub':
return sub(x, y)
# elif ...
else:
print(f'Sorry, {z} is not a valid function.')
return
Let's break down the code:
def add(x, y): return x + y
def sub(x, y): return x - y
# ...
This defined all of the functions we can use. Note: I only made them one line to keep everything a bit more concise. This is not necessary.
if z == 'add':
return add(x, y)
elif z == 'sub':
return sub(x, y)
# elif ...
These are where we parse z, and return our values. These can go on as far as you want.
else:
print(f'Sorry, {z} is not a valid function.')
return
This is just a base case for when a use enters an invalid operation.
For example, if you ran operations(2, 2, 'not_real_function') would return Sorry, not_real_function is not a valid function..

Passing many arguments to the constructor in python

I am trying to pass many arguments to a constructor but when i try to call a method; i have an error. I did instantiate my class; but i get an error. What i have is for example in my main function is:
Points = Line(1,1,2,3)
a= Line.slope()
print("slope",a)
in my class i have
class Line(object):
def __init__(self,X1,Y1,X2,Y2):
self.k1=X1
self.k2=Y1
self.k3=X2
self.k4=Y2
''' Compute the slope of the line'''
def slope(self):
x1, y1, x2, y2 = self.k1, self.k2, self.k3, self.k4
try:
return (float(y2)-y1)/(float(x2)-x1)
except ZeroDivisionError:
# line is vertical
return None
'''Get the y intercept of a line segment'''
def yintercept(self, slope):
if slope != None:
x, y = self.k1, self.k2
return y - self.slope * x
else:
return None
'''Find Y cord using line equation'''
def solve_for_y(self, x, slope, yintercept):
if slope != None and yintercept != None:
return float(slope) * x + float(yintercept)
else:
raise Exception("impossible to get it")
'''Find X cord using line equation'''
def solve_for_x(self, y, slope, yintercept):
if slope != 0 and slope:
return float((y - float(yintercept))) / float(slope)
else:
raise Exception("Imposssible to get it ")
The error is have is: TypeError: Compute missing 1 required positional argument: 'self'.
I am not what the problem is.
That is my complete code
You've got a few issues with your existing class.
class TestClass():
def __init__(self,x1,x2,x3):
self.k1 = x1
self.k2 = x2
self.k3 = x3
def Compute(self):
return self.k1 * self.k2 + self.k3
>>> test = TestClass(2,2,3)
>>> test.Compute()
7
The method _init_ should be __init__ (note the double underscores)
Your Compute method should use the member variables k instead of the input variables x because the x versions don't exist in that scope
Your capitalization of Compute was incorrect when you called the method.
You are missing a : after your class declaration and the __init__ function definition

Passing arguments down recursive functions

I want to pass an argument from the first call of a recursive function down to the later ones:
Example:
def function(x):
if base_case:
return 4
else:
return function(x_from_the_first_call + x_from_this_call)
Is there any better way of doing this than a closure?
E.g.
def function(outer_x):
def _inner(x)
if base_case:
return 4
else:
return function(outer_x + x)
return _inner(outer_x)
If you will change x somehow in function, then this should work i think:
def function(x, *args):
if base_case:
return 4
else:
new_x = x+1 # some change to x
if args:
# in args all previous x values
# remove if in case if you need all previous values
if not args:
args.append(x)
return function(new_x, *args)

How to pass additional parameters (besides arguments) to a function?

I need to write a function (say fun1) that has one argument, because it will be used in other function (fun2). The latter requires a function with a single argument. However, I need to pass other parameters to function fun1. How can I do this in Python without using global variables? Or this is the only way?
Addition: If it is important, fun2 is some optimization function from scipy.optimize. Below is an example of passing additional parameter c to function fun1 using global. In the first call, function fun2 takes fun1 as x+1, but in the second call, fun1 is x+2. I would like to make similar, but without using global. Hopefully, the example clarifies the question. (The example is changed).
def fun1(x) :
global c
return x + c
def fun2(f1, x) :
return f1(x)
# main program
global c
x0= 1
c= 1; y= fun2(fun1, x0); print(y) # gives 2
c= 2; y= fun2(fun1, x0); print(y) # gives 3
If I've understood your question correctly, there are quite a number of ways to do what you want and avoid using global variables. Here they are.
Given:
x0 = 1
def fun2(f1, x):
return f1(x)
All of these techniques accomplish your goal:
#### #0 -- function attributes
def fun1(x):
return x + fun1.c
fun1.c = 1; y = fun2(fun1, x0); print(y) # --> 2
fun1.c = 2; y = fun2(fun1, x0); print(y) # --> 3
#### #1 -- closure
def fun1(c):
def wrapper(x):
return x + c
return wrapper
y = fun2(fun1(c=1), x0); print(y) # --> 2
y = fun2(fun1(c=2), x0); print(y) # --> 3
#### #2 -- functools.partial object
from functools import partial
def fun1(x, c):
return x + c
y = fun2(partial(fun1, c=1), x0); print(y) # --> 2
y = fun2(partial(fun1, c=2), x0); print(y) # --> 3
#### #3 -- function object (functor)
class Fun1(object):
def __init__(self, c):
self.c = c
def __call__(self, x):
return x + self.c
y = fun2(Fun1(c=1), x0); print(y) # --> 2
y = fun2(Fun1(c=2), x0); print(y) # --> 3
#### #4 -- function decorator
def fun1(x, c):
return x + c
def decorate(c):
def wrapper(f):
def wrapped(x):
return f(x, c)
return wrapped
return wrapper
y = fun2(decorate(c=1)(fun1), x0); print(y) # --> 2
y = fun2(decorate(c=2)(fun1), x0); print(y) # --> 3
Note that writing c= arguments wasn't always strictly required in the calls -- I just put it in all of the usage examples for consistency and because it makes it clearer how it's being passed.
The fact that that function can be called even without those other parameters suggests, that they are optional and have some default value. So you should use default arguments.
def fun1(foo, bar='baz'):
# do something
This way you can call function fun1('hi') and bar will default to 'baz'. You can also call it fun1('hi', 15).
If they don't have any reasonable default, you can use None as the default value instead.
def fun1(foo, bar=None):
if bar is None:
# `bar` argument was not provided
else:
# it was provided
What you are looking for is a method in a class.
you define a class, with a method fun1 and an instance variable c. it is accessed from anywhere using the . notation:
class A:
def fun1(self, x):
return x + self.c
Let's define fun2, for the example:
def fun2(f, p):
return f(p)
We can now use a.c it like you did with the global varaible c:
>>> a = A() # create an instance and initialize it
>>> # "self.c" is undefined yet
>>>
>>> a.c = 1 # "self.c" will be 1
>>> fun2(a.fun1, 1)
2
>>> a.c = 2 # now "self.c" will be 2
>>> fun2(a.fun1, 1) # same arguments, different result
3
Here you can learn more about classes.
Just add the extra parameters with default values:
def fun1(param1, param2=None, param3=None):
...
Then you can call fun1 from fun2 like this:
def fun2():
something = fun1(42)
And from somewhere else you can call it like this:
fun1(42, param2=60)
You may use the decorators to pass it
the very decorators:
def jwt_or_redirect(fn):
#wraps(fn)
def decorator(*args, **kwargs):
...
return fn(*args, **kwargs)
return decorator
def jwt_refresh(fn):
#wraps(fn)
def decorator(*args, **kwargs):
...
new_kwargs = {'refreshed_jwt': 'xxxxx-xxxxxx'}
new_kwargs.update(kwargs)
return fn(*args, **new_kwargs)
return decorator
and the final function:
#jwt_or_redirect
#jwt_refresh
def home_page(*args, **kwargs):
return kwargs['refreched_jwt']

Categories

Resources