A python wrapper specifically for for-loops and its actions
I write a lot FOR loops that are, well, pretty generic.
For eg:
for x in y:
do something
... and error-prone. eg forgetting the ":", or indentation probs.
Could we put the FOR loop in a def, and call it, supplying it with the something?
An interesting exercise if nothing else.
A basic wrapper...
def wrapper(func,*args):
def wrapped():
return func(*args)
return wrapped
wrapper(print,"bob")
wrapper()
...which works. ie prints bob out
but I don't know how to make the below work - returning a FOR function made lots of syntax errors.
eg something like:
def for_1(y, do_something):
def wrapped():
return for x in y:
do_something
return wrapped
for_1(range(3),print("bob\n"))
for_1()
...and didn't see bob on the screen 3 times.
Could someone point me in the right direction, please? A wrapper is not doing the returned function.
Perhaps use a class for the wrapper? Then have my own methods(??)
...or maybe point me to someone's page who has done this before. I have explored wrappers and decorators but not seen something for passing parameters to a FOR loop function
You can simply restructure your code to not return too early and not call to early.
For this split up the function and parameters as two parameters to your for_1 wrapper.
If you want return value, gather them in your for loop and return them as a list.
def for_1(y, do_something, with_param):
for x in y:
do_something(with_param)
for_1(range(3), print, "bob")
Why make it complicated?
def for_1(y, to_print):
for x in range(y):
print(to_print)
for_1(3, "bob")
OUTPUT:
bob
bob
bob
EDIT:
def square(x):
print(x*x)
def for_1(y, command, param):
for x in range(y):
command(param)
for_1(1, square, 3)
OUTPUT:
9
the print is evaluated immediately and its return value passed in. what you want here is to pass in a callable, and append () to the do_something inside the loop. than you can use lambda for the passed in function.
def for_1(y, do_something):
def wrapped():
return for x in y:
do_something() # so we call whatever is passed in to be executed at this point
return wrapped
f = for_1(range(3),lambda: print("bob\n"))
f()
# or equivalent:
def print_bob():
print("bob\n")
for_1(range(3),print_bob)
Related
Here is a sample decorator:
def smart_divide(func):
def inner(a,b):
print("I am going to divide",a,"and",b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a,b)
return inner
#smart_divide
def divide(a,b):
return a/b
If func is an object then how do the variables a and b get accessed from it?
Isn't it like trying to to do this?
def func(potato):
print(y, x)
Is there a fundamental concept I am not getting? Is what is happening here part of some pattern in Python or is it a special case situation where a and b know were to look because it is a generator?
Update
New example from another stack exchange answer
def my_shiny_new_decorator(a_function_to_decorate):
def the_wrapper_around_the_original_function():
print("Before the function runs")
a_function_to_decorate()
print("After the function runs")
return the_wrapper_around_the_original_function
def a_stand_alone_function():
print("I am a stand alone function, don't you dare modify me")
Generators the manual way
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
Generators the proper way
#my_shiny_new_decorator
def another_stand_alone_function():
print("Leave me alone")
According to the place where I got the new answer from the 'manual' way and the 'proper way' are the same .
I think this example may have caused me to get stuck as I was trying to extend it to when there were parameters involved.
I now realise that what I was imagining didn't make sense
I thought that the original code I posted was equivalent to this
divide = smart_divide(divide(a,b))
which if executed would look like this
def smart_divide(divide(a,b)):
def inner(a,b):
print("I am going to divide",a,"and",b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a,b)
return inner
But this would cause divide(a,b) to be executed right in the top line
in the new example 'a_stand_alone_function' did not have () on the end. Which means it was treated as an object.
So my idea of it looking like this def smart_divide(divide(a,b)): doesn't make sense because the function won't be treated as an object anymore
This leaves me confused as to how smart_devide get the information passed as a parameter.
smart_divide doesn't get a and b passed into it. It returns a function object (the inner function), and that function gets a and b passed into it.
You can see what's actually happening if you try this:
def smart_divide(func):
print("I am running in smart_divide; func=", func)
def inner(a,b):
print("I am going to divide",a,"and",b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a,b)
print("I am returning from smart_divide")
return inner
print("I am running at top level before declaring divide")
#smart_divide
def divide(a,b):
return a/b
print("The name 'divide' now refers to", divide)
print("I am now going to call the divide function")
divide(1, 2)
This outputs:
I am running at top level before declaring divide
I am running in smart_divide; func= <function divide at 0x108ff2bf8>
I am returning from smart_divide
the name 'divide' now refers to <function smart_divide.<locals>.inner at 0x10565db70>
I am now going to call the divide function
I am going to divide 1 and 2
No, your decorator returns inner as new implementaion for divide. Thus, you first call the function inner when your program executes divide(1, 2) for instance. Calls to divide have always to respect the signature of inner (and divide as in your code).
A function like
def divide(a, b): # signature
return a / b # implementation or body
consists of two parts. The signature describes the parameters, and the implementation what the function does.
Your decorator will only modify the implementation of your function as follows:
def divide(a, b): # signature remains unmodified
print("I am going to divide",a,"and",b) # implementation of inner
if b == 0:
print("Whoops! cannot divide")
return
return a / b # call to the original implementation of divide
The name and the signature of divide remains the same. Thus, the signature of inner matters, and not the signature of your decorator.
I have been hard pressed to answer a question we were recently asked as part of an exercise on higher-order functions in Python.
The question is to define two functions, one which takes no arguments, and passes three globally defined functions, c(), t() and f(), through if/else statements (if c() true, return t() else return f()). The other function is a higher-order function that we evaluate on c(), t() and f() that then passes them through the same if/else statements.
These functions are different and our task is to see how by defining three functions c(), t() and f() such that the first function returns 1 and the second returns something other than one.
So far I have come to the realization that the issue lies with the calling of the functions c(), t() and f() before passing them through the if/else statements. This however has not been enough to inspire a solution. Would anyone be able to steer me in the correct direction?
Here is the associated code:
def if_function(condition, true_result, false_result):
if condition:
return true_result
else:
return false_result
def with_if_statement():
if c():
return t()
else:
return f()
def with_if_function():
return if_function(c(), t(), f())
def c():
return []
def t():
return 1
def f():
return 1
You may easily pass callable as function arguments, without calling them.
def cond():
return True
def f():
return 2
def g():
time.sleep(60)
def if_function(condition_callable, call_if_true, call_if_false):
if condition_callable():
return call_if_true()
else:
return call_if_false()
if_function(cond, f, g) # evaluates immediately, does not sleep since g is never evaluated.
I have a recursive function (f calls itself):
def f(x) :
....
I want to run this function multiple times. I use the following decorator:
def iter_f(func) :
def newf(x):
for i in range(10):
func(x)
return newf
#iter_f
def f(x): a RECURSIVE function.
When i call f(x), I am calling a function that iterate itself infinite times.I am curious what is the solution still using decorator, without wrap f inside a new function g, and decorate g.
Thanks.
Thanks for point out that the problem was due to f is recursive.
Decorating recursive functions in python this post has a similar problem, maybe this is not a good place to use decorator?
This should work
def iter_f(func):
def newf(*args, **kwargs):
for i in range(10):
func(*args, **kwargs)
return newf
#iter_f
def f(x):
Try this:
def iter_f(func) :
def newf(x):
for i in range(10):
func(x)
newf._original = func
return newf
#iter_f
def f(x):
...
call f._original(y)
...
i have homework and we need to do something like iterator, the func work great but the techer told he run the func with (t=Make_iterator()) like this, what i do wrong? tnx!
global x
x=-1
def Make_iterator(fn):
global x
x+=1
return fn(x)
fn=lambda y:y*2
t=Make_iterator(fn)
print(t())
I think you want a closure, which is a function defined within the local namespace of anther function, so that it can access the outer function's variables:
def make_iterator(func):
x = -1
def helper():
nonlocal x
x += 1
return func(x)
return helper
The nonlocal statement allows the inner function to modify the variable declared in the outer function (otherwise you'd either get an error, or you'd bind your own local variable without changing the outer one). It was only added in Python 3, so if you're still using Python 2, you'll need to wrap the x value in a mutable data structure, like a list.
Another approach to the same idea is to write class, rather than a function. An instance of a class can be callable (just like a function) if the class defines a __call__ method:
class MyIterator(object):
def __init__(self, func):
self.index = -1
self.func = func
def __call__(self):
self.index += 1
return self.func(self.index)
This can be useful if the state you need to keep track of is more complicated (or should change in more complicated ways) than the simple integer index used in this example. It also works in Python 2 without annoying workarounds.
I think he wants your Make_iterator function to return a function that acts as an iterator. So you could wrap the contents of your current Make_iterator function within an inner function f and return that:
def Make_iterator(fn):
def f():
global x
x+=1
return fn(x)
return f
Now if you do t = Make_iterator(fn), every time you call t() it will return the next value of the iterator, in your case 0, 2, 4, 6, 8, etc...
Suppose I have the following class:
class MyGen(object):
def next(self):
return X()
def send(self, x):
return f(x)
Is it possible to express it as a single function, using the yield keyword? Suppose I have g = MyGen(). Note that g.next() shouldn't call f(), and g.send(x) shouldn't call X(), but f() and X() could share some code.
This code will be almost equivalent:
def my_gen(x=None):
while True:
if x is None:
x = yield X()
else:
x = yield f(x)
One difference is that you can't send a value (other than None) to a generator before calling next() for the first time. Another difference is that sending None won't trigger calling f(), since the generator can't distinguish send(None) and next().
Sven's formulation is exactly the way to go, I just wanted to add that if you want to know more about generators, coroutines and such in Python, this site is the place to go.