pass return of a function into another - python

I have a question / problem and I don't know how to solve it. Suppose you have three functions, function 1, function 2 and function 3. In function 1 you do some operations and you give a specific return which will be used as input for the second function. In the second function you do some specific calculation and also finish with return, which you pass in a third function
My problem is that as soon as I pass the return of function 1 into function 2 all the calculation in function 1 is repeated (calculation is here in this case, several plots) The same goes for function two into three, now I get results from function 1 and function 2. I hope you do understand what I mean.
What I want is just the return value of func 1 for func 2 and return value of func 2 for three and not the entire function body.
Here is what my code looks like:
class test:
def __(self)__:
self.attribute1=pd.read_csv(...)
self.attribite2=pd.read_csv(...)
def func1(self):
plt.plot(a,b)
plt.plot(c,d)
return x
def func2(self):
self.data_2=self.func1()
plt.plot(e,f)
plt.plot(g,h)
return y
def func3(self):
self.data_3=self.func2()
plt.plot(i,j)
data_test=test()
print(data_test.func2())
My problem is that (let's focus on func2). If I use the input from func1 and execute my code for func2 I get also the two plots. I dont want to have that. I just want to see the plots(e,f) and plots(g,h) instead of plots(a,b), plots(c,d), plots(e,f) and plots(g,h)

Your class definition do not follow the OOP clean design, for which every method should performa the most atomic task possible.
Your methods func1, func2 and func3, they all do at least 2 tasks: plot something and return something else.
Consider changing your class so every method do one and only one thing, defining public APIS and private methods, for instance:
class test:
def __(self)__:
self.attribute1 = []
self.attribite2 = []
def _func1(self):
return x
def _func2(self):
self.data_2 = self._func1()
return y
def _func3(self):
self.data_3 = self._func2()
def func2(self):
self._func2()
plt.plot(e,f)
plt.plot(g,h)
def func3(self):
self._func3()
plt.plot(e,f)
plt.plot(g,h)
data_test=test()
data_test.func2()
This way func2 and func3 are public apis (aka: intended to be called from outside the class) that will "do the work" (setting stuff in self.data_2 and self.data_3) AND plot; while _func2 and _func3 are private methods (aka, methods that only the class itself is supposed to use) will only do the work.
Now, calling func2 will use methods _func1 and _func2, but only plot what's defined in func2.

You say that you "pass the return of function 1 into function 2", but you never do that.
You're not passing any results anywhere, and none of your functions take any input (except self) - you're calling the functions directly in each one.
In other words, every time you call function2, it calls function1, and every time you call function3, it calls function2, which in turn calls function1.
Code that matches your description would look like this:
class test:
def __(self)__:
self.attribute1=pd.read_csv(...)
self.attribite2=pd.read_csv(...)
def func1(self):
plt.plot(a,b)
plt.plot(c,d)
return x
def func2(self, a):
self.data_2 = a
plt.plot(e,f)
plt.plot(g,h)
return y
def func3(self, x):
self.data_3 = x
plt.plot(i,j)
return z
data_test = test()
print(data_test.func3(data_test.func2(data_test.func1())))

Related

How to user Python Mock side effect to return different value based on function being mocked

I have a common function that I want to use as a side effect for two different functions. Based on the function being mocked , they should return a different value.
The code is:
def sleep_three(*args, **kwargs):
logging.info('Sleeping 3 seconds')
time.sleep(3)
Used as a side effect for two different functions:
self.foo.side_effect = sleep_three
self.bar.side_effect = sleep_three
For foo, I want a specific return value, whereas for bar I want a different return value. I know how to obtain different return values based on different arguments being passed in to side_effect function. In this case though both foo and bar are being passed in the same argument, they just need to return different values.
My options are:
Write two different functions for side_effect : sleep_three_foo and sleep_three_bar and then match up return values accordingly. This goes against DRY principles though and I would like to avoid it.
My question is : Is there a way within sleep_three to obtain the original function being mocked?
Something like
if original_mocked_function == foo:
return a
elif original_mocked_function == bar:
return b
Any pointers appreciated!
Define a function that takes the desired return value of the side-effect function as an argument and returns the appropriate function.
def make_sleeper(rv):
def _(*args, **kwargs):
logging.info("Sleeping 3 seconds")
time.sleep(3)
return rv
return _
self.foo.side_effect = make_sleeper(5)
self.bar.side_effect = make_sleeper(9)

what is difference between foo=bar(foo) and something=bar(foo) in decorator in python?

I read about we can create reference of any function in python but i also read that while creating a decorator we use a special syntax called "#" : ex: #decorator_function
and this #decorator_function is equal to new_function=decorator_function(new_function)
so my doubt is in my view both :
anything = decorator_function(new_function)
new_function=decorator_function(new_function)
both are playing the role of closure but both result different output. so what is big difference between both of them?
example code :
def deco(fn):
def wrapper(*args):
print('called')
return fn(*args)
return wrapper
def something(x):
if x == 0:
print('first')
something(x+1)
else:
print('hello')
print('new name')
a = deco(something)
a(0)
print('\nreassigning to the same name')
something = deco(something)
something(0)
The original something function you wrote makes a recursive call to something, not a.
If you assign deco(something) to a, then something is still the original function, and the recursive call will call the original function:
new function calls original function
original function looks up something, finds original function
original function calls original function...
If you assign deco(something) to something, then something is now the new function, and the recursive call will call the new function:
new function calls original function
original function looks up something, finds new function
original function calls new function
new function calls original function...
For the first one, a = deco(something)
def deco(fn):
def wrapper(*args):
print('called')
return something(*args) # Notice here
return wrapper
The second one, something = deco(something) is just the same except your original function something now has become the wrapper function that deco returned.
>>> something
<function deco.<locals>.wrapper at 0x7fbae4622f28>
>>> a
<function deco.<locals>.wrapper at 0x7fbae4622ea0>
Both something and a wrap the original something before it was overridden by something = deco(something) assignment. Python internally stored the original something function somewhere in the wrapper functions:
>>> something.__closure__[0].cell_contents
<function something at 0x7fbae4622bf8>
>>> a.__closure__[0].cell_contents
<function something at 0x7fbae4622bf8>
In the last assignment something has become something different:
>>> something
<function deco.<locals>.wrapper at 0x7fbae4622f28>
Both of your assignments using manual calls to the decorator work. But one of them (the one that rebinds something) replaces the original function so that it can't be reached by its original name any more. It's not any different than using any other assignment. For instance:
def foo(x):
return x + 1
a = 10
a = foo(a)
When you assign the result of foo(a) to a, it replaces the old value of 10 with a new value 11. You can't get the 10 any more.
Decorator syntax does the same thing.
def deco(fn):
def wrapper(*args):
print('called')
return fn(*args)
return wrapper
def func_1(x):
pass
func_1 = deco(func_1) # replace the old func_1 with a decorated version
#deco # the # syntax does the same thing!
def func_2(x):
pass
It's not forbidden to use a decorator to create a differently named function, it's just not normally as useful (and so there's no special syntax for it):
def func_3(x):
pass
func_4 = deco(func_3) # this works, creating a new function name without hiding the old one

Method Overriding?

I saw this particular piece of code:
def g(x,y):
return x+y
def g(x,y):
return x*y
x,y=6,7
print (g(x,y))
The output is obviously(but not to me) is 42. Can somebody please explain this behavior? This is method overriding I suppose, but I'm still not getting the flow here.
When you define a function, and you redefine it, it will use the last one you defined, even the parameter is different:
def g(x,y):
return x+y
def g(x,y):
return x*y
x,y=6,7
print (g(x,y))
def hello():
return 'hello'
def hello():
return 'bye'
print hello()
def withone(word):
return word
def withone():
return 1==1
print withone('ok')
Output:
42
bye
TypeError: withone() takes no arguments (1 given)
And function name in Python is more like simple variable:
def hello():
return 'hello'
iamhello = hello # bind to the old one
def hello():
return 'bye'
print hello() # here is the new guy
print iamhello()
OutPut:
bye
hello
The devil is in the order of function definitions.
This is not technically method overriding as that requires class inheritance, instead it's a result of how python declares and references functions.
When declaring a function, python stores a reference to that function in a variable named after the function definition. (e.g. variable would be "foo" for "def foo():")
By declaring the function twice, the value of that variable gets overwritten by the second definition.
A Python script is parsed from top till bottom.
So anytime the same name of a variable or function or class occurs, it overwrites any definitions that where associated with this name before.
def g(x,z):
print('first')
def g():
print('second')
g = 3
print g
print g()
So look at this example which will result in the printout of '3' and then in an Exception: 'TypeError: 'int' object is not callable'
The name g is at first a function with two parameters, then it gets redefined to be a function with no parameters, then it gets redefined to be an int.
Which cannot be called obviously :)
Everything in python is treated as object, whether it be a function name or class name. So, when we define a function using 'def', the memory allocation is done for that method. Then python points the name that we assign to the function, to this allocated memory location. So if we define a method :-
def demo():
print 'hi'
the memory is allocated for the method, and the name 'demo' is pointed to its memory location as follows :-
Now as described by zoosuck in his second example, when you assign the function name to another variable :-
demo2 = demo # bind to the old one
then in that case, the assigned memory location to demo, is assigned to demo2 as well. So both demo and demo2 points to same location 12506.
print id(demo) # will print 12506
print id(demo2) # will print 12506
Now if we modify the above piece of code and in the next line, define a new method with same name demo:-
def demo():
print 'hi'
demo2 = demo # bind to the old one
demo() # Will print hi
def demo():
print "hello"
demo() # Will print hello
demo2() # Will print hi
then a completely new memory location 12534 is allocated for this new method, and now demo will point to this new location 12534 instead of pointing to the old one i.e. to 12506. But demo2 is still pointing to the location 12506.
I hope this will give you a clear idea of what is going on and how the method name is over-written.
Order matters, if names are same,last function you defined is processing. In your case it's;
def g(x,y):
return x*y
g is just a variable. The fact that the object it refers to is a function doesn't make it special in Python, so you can assign and reassign it as you want. In this case, the second assignment (which is what a function definition is) simply replaces the object stored there with a different one.
Functions and methods are normal objects like any others. So in
def g(x, y):
return x + y
def g(x, y):
return x * y
the second object g will override(replace) the first one, just like object a does below:
a = 1
a = 2
The number, type or order of parameters does not make any difference, because Python does not support function/method override and does not allow two functions/methods to have the same name.
If you are familiar with lambda function, also often called anonymous\inline functions, this might clear things up a bit
These two code blocks are essentially equal
def g(x,y):
return x+y
def g(x,y):
return x*y
g = lambda x,y: x+y
g = lambda x,y: x*y

How should I call functions defined outside of the main function?

So I'm fairly new to python and I am working on an algorithm and I have let's say 2 functions
func1(x)
func2(x)
already defined outside the main function.
Now I want to call these functions inside the main functions one nested inside the other
Something like this
def funcmain(func1(func2(x)))
It obviously is not working I haven't been able to get it work anyway I want. Any tips on this?
Edit: What I meant to do is that I want to input a string, I want it to go through func2 first, then the return value from func2 to go through func1 and finally the return value of func1 to go through func main. I have tested each function separately and they are working as intended but I can't seem to get them interlinked together
I hope this code snippet will help to clarify things for you.
#!/usr/bin/python
def func1(x):
return x + 1
def func2(x):
return x + 2
def main(x):
print func1(func2(x))
if __name__ == '__main__':
main(0)
The output is 3.
Is this what you mean? Your question is not too clear. I assume x is also defined globally somewhere.
def funcmain():
return func1(func2(x))
take the following functions:
def func1(x):
return x+1
def func2(x):
return x*2
by itself you COULD do this: func1(func2(3)) which would return 3 times 2 plus 1. This works because by itself func1(func2(3)) actually returns a value, not a function.
BUT since you are trying to put it as the basic argument for the main function like this:
def main(func1(func2(x))): #dont do this, this is what you did, it is bad
return x*3
its not going to know what to do with that because there is no default for x...
you CAN DO THIS THOUGH:
def main(x=func1(func2(1)):
return x*3
this would do the appropriate math to 1 and then assign it as x (Because as we saw earlier, func1(func2(3))` would return THE RESULT OF FUNCTIONS not a function itself, then multiply it by 3. since you are defaulting x to equal a value ( which is func1(func2(1))
This is bad practice still, because you are defaulting to whatever func1(func2(1) comes out to.
what you probably want in the end is something simpler:
def main(x):
y = func1(func2(x))
return y*3
or maybe even simpler than that
def main(x):
return x*3
#and then just call it like this
main(func1(func2(1))

Passing objects around an event queue in Python

So i have a relatively convoluted setup for something I'm working on explained as follows:
This is is python. and more of a rough outline, but it covers everything I need. Though the process next function is the same so feel free to clean that up if you want.
#timer event that runs every .1 second and processes events in a queue
some_event_timer():
events.process_next()
class Event_queue:
def __init__(self):
self.events = []
def push(self, event, parameters):
self.events.insert(len(self.events), event, parameters)
def process_next(self):
event = self.pop(0)
event[0](event[1])
class Foo:
def __init__(self, start_value = 1):
self.value = start_value
def update_value(self, multiple):
self.value *= multiple
def return_bah(self)
return self.value + 3
class Bar:
def __init__(self, number1, number2):
self.init = number1
self.add = number2
def print_alt_value(self, in_value):
print in_value * (self.init + self.add)
That is a barebones of what I have, but it illustrates my problem:
Doing the below
events2 = Event_queue2()
foo1 = Foo(4) ----> foo1.value = 4 here
bar1 = Bar(4, 2)
events2.push(foo1.update_value,1.5)
events2.push(bar1.print_alt_value,foo1.value)
events2.push(bar.print_alt_value,foo1.return_bah())
events2.process_next() ----> should process update_value to change foo.value to 6
events2.process_next() ----> should process print_alt_value in bar class - expected 36
events2.process_next() ----> should process print_alt_value - expected 54
I initially expected my output to be 36 6 * (4 + 2)
I know why its not, foo1.value and foo1.return_bah() gets passed as an evaluated parameter (correct term?).
What I really want is to pass the reference to the variable or the reference to the method, rather than having it evaluate when I put it in my event queue.
Can anyone help me.
I tried searching, but I couldn't piece together what I wanted exactly.
TO get what I have now I initially looked at these threads:
Calling a function of a module from a string with the function's name in Python
Use a string to call function in Python
But I don't see how to support parameters from that properly or how to support passing another function or reference to a variable from those.
I suppose at least for the method call, I could perhaps pass the parameter as foo1.return.bah and evaluate in the process_next method, but I was hoping for a general way that would accept both standard variables and method calls, as the event_queue will take both.
Thank you for the help
Update edit:
So I following the suggestion below, and got really close, but:
Ok, so I followed your queue suggestion and got really close to what I want, but I don't completely understand the first part about multiple functions.
I want to be able to call a dictionary of objects with this as well.
for example:
names = ["test1", "test2"]
for name in names:
names_objs[name] = Foo(4)
Then when attempting to push via lambda
for name in names_list:
events2.push(lambda: names_objs[name].update_value(2))
doesn't work. When teh event actually gets processed it only runs on whatever name_objs[name] references, and if the name variable is no longer valid or has been modified outside the function, it is wrong.
This actually wasn't surprising, but adding a:
name_obj_hold = name_objs[name]
then pushing that didn't either. it again only operates on whatever name_obj_hold last referenced.
Can someone clarify the multiple funcs thing. I'm afraid I'm having trouble wrapping my head around it.
basically I need the initial method call evaluated, so something like:
names_objs[name].some_func(#something in here#)
gets the proper method and associated with the right class object instance, but the #something in here# doesn't get evaluated (whether it is a variable or another function) until it actually gets called from the event queue.
Instead of passing in the function to call func1 and the arguments that should be passed to the function, pass in a function func2 that calls func1 with the arguments that should be passed in.
d = {"a":1}
def p(val):
print val
def func1():
p(d["a"])
def call_it(func):
func()
call_it(func1)
d["a"] = 111
call_it(func1)
Within func1, d["a"] is not evaluated until func1 actually executes.
For your purposes, your queue would change to:
class EventQueue(object):
def __init__(self):
self.events = deque()
def push(self, callable):
self.events.append(callable)
def process_next(self):
self.events.popleft()()
collections.deque will be faster at popping from the front of the queue than a list.
And to use the EventQueue, you can use lambdas for quick anonymous function.
events2 = EventQueue()
foo1 = Foo(4)
bar1 = Bar(4, 2)
events2.push(lambda: foo1.update_value(1.5))
events2.push(lambda: bar1.print_alt_value(foo1.value))
events2.push(lambda: bar1.print_alt_value(foo1.return_bah()))
events2.process_next()
events2.process_next() # 36.0
events2.process_next() # 54.0
For Edit:
In this case you need to "capture" the value in a variable that is more tightly scoped than the loop. You can use a normal function and partial() to achieve this.
for name in names_list:
def update(name):
names_objs[name].update_value(2)
events2.push(partial(update, name))

Categories

Resources