Python: decorating simple recursive function - python

I wanted to practice recursive and decorators and try to do this simple function but it doesn't work:
def dec(func):
def wrapper(number):
print("Recursive count:")
rec_cou(number)
return wrapper
#dec
def rec_cou(number):
""" Count from 0 to a given number from 50 and up """
if number == 0:
print(number)
return number
num = rec_cou(number - 1)
print(num + 1)
return num + 1
rec_cou(53)
The recursive function alone works well, but when i add the decorator generates error: maximun recursion depth exceeded

There are two problems with your decorator:
You try to call the decorated function, effectively invoking the wrapper function again inside the decorator, thus you have an infinite recursive loop; call the original function func instead.
To the outside, the decorated function should behave just like the original function, particularly it should return its result; otherwise you will get type errors for trying to add numbers and None
Also, currently your decorator is not counting anything... try this:
def dec(func):
func.count = 0 # give each decorated function its own counter
def wrapper(number):
print("Recursive count: %d" % func.count)
func.count += 1 # increase counter
return func(number) # call original function 'func' and return result
return wrapper
Update: From your comments, it seems I misunderstood what your decorator is supposed to do, and you misunderstood how decorators work. The decorator is not called once when you first call the function, but it replaces the function with the one defined within the decorator. In other words,
#dec
def foo(...):
...
is equivalent to
def foo(...):
...
foo = dec(foo)
I.e. the decorator in invoked exactly once when the function is decorated, and the function constructed in the decorator is called each time the original function is called, replacing it. If you want to print only once, either use the decorator from the other answer, or rather use no decorator at all: Just create a wrapper that prints and then calls the function. This is not unusual for providing an 'entry point' to recursive functions.
def print_and_run(number):
print("Recursive count:")
rec_cou(number)
BTW, this is the decorator that I usually use to visualize recursive calls:
def trace(f):
trace.depth = 0
def _f(*args, **kwargs):
print " " * trace.depth, ">", f.__name__, args, kwargs
trace.depth += 1
res = f(*args, **kwargs)
trace.depth -= 1
print " " * trace.depth, "<", res
return res
return _f

To solve the maximum recursion depth problem, call the function passed into the decorator (func) rather than rec_cou and return the value of the function call. That is, on line 5, replace rec_cou(number) with return func(number).
Edit:
def decorate(function):
def wrapper(parameter):
if wrapper.initial:
print("Recursive count:")
wrapper.initial = False
result = function(parameter)
wrapper.initial = True
return result
wrapper.initial = True
return wrapper
#decorate
def count(number):
""" Prints integers on the interval [0, number] """
if number:
count(number - 1)
print(number)
count(53)
Without decorator:
def count(number):
""" Prints integers on the interval [0, number] """
if number:
count(number - 1)
else:
print("Recursive count:")
print(number)
count(53)

If all you want is for the function rec_cou to print something before its recursive descent, just modify that function and don't bother with decorators.
def rec_cou(number, internal_call=False):
""" Count from 0 to a given number from 50 and up """
if not internal_call:
print "Now performing recursive count, starting with %d" % number
if number == 0:
return number
num = rec_cou(number - 1, internal_call=True)
return num + 1
As I mentioned in my comments, all I've done is take the idea behind Joel's answer (which was to add a variable--which I called a "flag"--indicating whether the function is being called externally or as part of the recursion) and moved the flag variable (which I've called internal_call, whereas Joel called it initial) inside the function itself.
Additionally, I'm not sure what all this num business is about. Note that:
For the 0 case, rec_cou returns 0.
For number > 0, num is set to the value returned by rec_cou(number-1), then 1+num is returned.
For example, in the case of rec_cou(1), num is set to rec_cou(0), which is 0, then 0 + 1 is returned, which is 1. Similarly, for rec_cou(2), one more than the value of rec_cou(1) is returned, so 2 is returned.
In short, for every natural number, rec_cou(number) returns the value of the input number. It's not clear what you're trying to achieve, but what you've got is an identity function, which seems unlikely to be what you want.

Related

Recursive function won't call another function n number of times

I am working on an exercise in Think Python 2nd edition. The directions are as follows:
Write a function called do_n that takes a function object and a number, n, as arguments, and that calls the given function n times.
Here is my code:
def print_once(s):
print(s)
def do_n(func, n):
if n <= 0:
return
else:
print_once(s)
do_n(func, n - 1)
do_n(print_once('Bob'), 3)
My function do_n was correct according to what I found online, but I cannot understand why it does not call print_once 3 times.
To the best of my knowledge the previous solution would not work, since it is not passing the callable to do_n, but instead calling the function print_once before moving to do_n. Here is a fully functional version with a slight change to the original code:
def print_once(s):
print(s)
def do_n(func, n):
if n <= 0:
return
else:
func('Bob')
do_n(func, n - 1)
do_n(print_once, 3)
You don't pass a function object to the recursive function. You only call the print_once() which returns None.
def print_once(s):
print(s)
def do_n(func, func_arg, n):
if n <= 0:
return
else:
func(func_arg)
do_n(func, func_arg, n - 1)
# this is a function call it returns
# nothing according to the definition
# of the print_once function
# do_n(print_once('Bob'), 3)
# this is a function object passed
# to the do_n function. The argument to
# the function is also passed to do_n
do_n(print_once, "Bob", 3)
If you want to call a function bound to its argument, you can use functools.partial
print_once_bob = functools.partial(print_once, "Bob")
do_n(print_once_bob, 3)

In Python, when/why should you return a function?

I am coming from c
The concept of first class function is interesting and exiting.
However, I am struggling to find a practical use-case to returning a function.
I have seen the examples of building a function that returns print a grating...
Hello = grating('Hello')
Hi = grating('Hi')
But why is this better then just using
grating('Hello') and grating('Hi')?
Consider:
def func_a():
def func_b():
do sonthing
return somthing
return func_b
When this is better then:
def func_b():
do sonthing
return somthing
def func_a():
res = func_b()
return (res)
can someone point me to a real world useful example?
Thanks!
Your examples aren't helpful as written. But there are other cases where it's useful, e.g. decorators (which are functions that are called on functions and return functions, to modify the behavior of the function they're called on for future callers) and closures. The closure case can be a convenience (e.g. some other part of your code doesn't want to have to pass 10 arguments on every call when eight of them are always the same value; this is usually covered by functools.partial, but closures also work), or it can be a caching time saver. For an example of the latter, imagine a stupid function that tests which of a set of numbers less than some bound are prime by computing all primes up to that bound, then filtering the inputs to those in the set of primes.
If you write it as:
def get_primes(*args):
maxtotest = max(args)
primes = sieve_of_eratosthenes(maxtotest) # (expensive) Produce set of primes up to maxtotest
return primes.intersection(args)
then you're redoing the Sieve of Eratosthenes every call, which swamps the cost of a set intersection. If you implement it as a closure, you might do:
def make_get_primes(initialmax=1000):
primes = sieve_of_eratosthenes(initialmax) # (expensive) Produce set of primes up to maxtotest
currentmax = initialmax
def get_primes(*args):
nonlocal currentmax
maxtotest = max(args)
if maxtotest > currentmax:
primes.update(partial_sieve_of_eratosthenes(currentmax, maxtotest)) # (less expensive) Fill in additional primes not sieved
currentmax = maxtotest
return primes.intersection(args)
return get_primes
Now, if you need a tester for a while, you can do:
get_primes = make_get_primes()
and each call to get_primes is cheap (essentially free if the cached primes already cover you, and cheaper if it has to compute more).
Imagine you wanted to pass a function that would choose a function based on parameters:
def compare(a, b):
...
def anticompare(a, b): # Compare but backwards
...
def get_comparator(reverse):
if reverse: return anticompare
else: return compare
def sort(arr, reverse=false):
comparator = get_comparator(reverse)
...
Obviously this is mildly contrived, but it separates the logic of choosing a comparator from the comparator functions themselves.
A perfect example of a function returning a function is a Python decorator:
def foo(func):
def bar():
return func().upper()
return bar
#foo
def hello_world():
return "Hello World!"
print(hello_world())
The decorator is the #foo symbol above the hello_world() function declaration. In essence, we tell the interpreter that whenever it sees the mention of hello_world(), to actually call foo(hello_world()), therefore, the output of the code above is:
HELLO WORLD!
The idea of a function that returns a function in Python is for decorators, which is a design pattern that allows to add new functionality to an existing object.
I recommend you to read about decorators
On example would be creating a timer function. Let's say we want a function that accepts another function, and times how long it takes to complete:
import time
def timeit(func, args):
st = time.time()
func(args)
return str('Took ' + str(time.time() - st) + ' seconds to complete.'
timeit(lambda x: x*10, 10)
# Took 1.9073486328125e-06 seconds to complete
Edit: Using a function that returns a function
import time
def timeit(func):
st = time.time()
func(10)
return str('Took ' + str(time.time() - st) + ' seconds to complete.')
def make_func(x):
return lambda x: x
timeit(make_func(10))
# Took 1.90734863281e-06 seconds to complete.

Optional yield or return in python3. How to?

I would like to have a function that can, optionally, return or yield the result.
Here is an example.
def f(option=True):
...
for...:
if option:
yield result
else:
results.append(result)
if not option:
return results
Of course, this doesn't work, I have tried with python3 and I always get a generator no matter what option value I set.
As far I have understood, python checks the body of the function and if a yield is present, then the result will be a generator.
Is there any way to get around this and make a function that can return or yield at will?
You can't. Any use of yield makes the function a generator.
You could wrap your function with one that uses list() to store all values the generator produces in a list object and returns that:
def f_wrapper(option=True):
gen = f()
if option:
return gen # return the generator unchanged
return list(gen) # return all values of the generator as a list
However, generally speaking, this is bad design. Don't have your functions alter behaviour like this; stick to one return type (a generator or an object) and don't have it switch between the two.
Consider splitting this into two functions instead:
def f():
yield result
def f_as_list():
return list(f())
and use either f() if you need the generator, and f_as_list() if you want to have a list instead.
Since list(), (and next() to access just one value of a generator) are built-in functions, you rarely need to use a wrapper. Just call those functions directly:
# access elements one by one
gen = f()
one_value = next(gen)
# convert the generator to a list
all_values = list(f())
What about this?
def make_f_or_generator(option):
def f():
return "I am a function."
def g():
yield "I am a generator."
if option:
return f
else:
return g
This gives you at least the choice to create a function or a generator.
class based approach
class FunctionAndGenerator:
def __init__(self):
self.counter = 0
def __iter__(self):
return self
# You need a variable to indicate if dunder next should return the string or raise StopIteration.
# Raising StopIteration will stop the loop from iterating more.
# You'll have to teach next to raise StopIteration at some point
def __next__(self):
self.counter += 1
if self.counter > 1 :
raise StopIteration
return f"I'm a generator and I've generated {self.counter} times"
def __call__(self):
return "I'm a function"
x = FunctionAndGenerator()
print(x())
for i in x:
print(i)
I'm a function
I'm a generator and I've generated 1 times
[Program finished]

Use output of one function and average it in another function

please keep in mind that while I showcase my code, that I am fairly new to programming. So please forgive any problems. I am writing a piece of python code that uses the output of one function and then averages it in another function. I am having troubling proceeding on how to do that, this is what I have so far:
def avg(A):
if not A:
return 0
return sum(A) / len(A)
Using the function above, I have to use it to calculate the average of the function produced below:
def SampleFunction(): # Example Function
A = list(range(300))
for i in range(300):
if i%2:
A[i] = 3.1*(i+1)**1.2 - 7.9*i
else:
A[i] = 4.2*(i+2)**.8 - 6.8*i
return A
Below this is a function I have trying to tie the two together.
def average(SampleFunction):
if len(SampleFunction) == 0: return 0
return sum(SampleFunction) / len(SampleFunction)
def avg(A):
if not A:
return 0
return sum(A) / len(A)
def SampleFunction(): # Example Function
A = list(range(300))
for i in range(300):
if i%2:
A[i] = 3.1*(i+1)**1.2 - 7.9*i
else:
A[i] = 4.2*(i+2)**.8 - 6.8*i
return avg(A) #Return the avg of A instead of just A
You are right at the moment of passing SampleFunction as parameter, but it's a function, you have to call invoke it inside average():
def average(some_function):
result = some_function() # invoke
return avg(result) # use the already defined function 'avg'
When you call it, pass the function you want to average():
print average(SampleFunction)
Note:
I would recommend you to follow Python naming conventions. Names like SomeName are used for classes, whereas names like some_name are used for functions.

Python - Passing a function into another function [duplicate]

This question already has answers here:
Python function as a function argument?
(10 answers)
Closed last month.
I am solving a puzzle using python and depending on which puzzle I am solving I will have to use a special set of rules. How can I pass a function into another function in Python?
Example
def Game(listA, listB, rules):
if rules == True:
do...
else:
do...
def Rule1(v):
if "variable_name1" in v:
return False
elif "variable_name2" in v:
return False
else:
return True
def Rule2(v):
if "variable_name3" and "variable_name4" in v:
return False
elif "variable_name4" and variable_name1 in v:
return False
else:
return True
This is just a pseudo code and therefore not specific but I get the code to compile but I need to know how to call the function Game and whether it's correctly defined since rules will be switched for either Rule1(v) or Rule2(v).
Just pass it in like any other parameter:
def a(x):
return "a(%s)" % (x,)
def b(f,x):
return f(x)
print b(a,10)
Treat function as variable in your program so you can just pass them to other functions easily:
def test ():
print "test was invoked"
def invoker(func):
func()
invoker(test) # prints test was invoked
For passing both a function, and any arguments to the function:
from typing import Callable
def looper(fn: Callable, n:int, *args, **kwargs):
"""
Call a function `n` times
Parameters
----------
fn: Callable
Function to be called.
n: int
Number of times to call `func`.
*args
Positional arguments to be passed to `func`.
**kwargs
Keyword arguments to be passed to `func`.
Example
-------
>>> def foo(a:Union[float, int], b:Union[float, int]):
... '''The function to pass'''
... print(a+b)
>>> looper(foo, 3, 2, b=4)
6
6
6
"""
for i in range(n):
fn(*args, **kwargs)
Depending on what you are doing, it could make sense to define a decorator, or perhaps use functools.partial.
Just pass it in, like this:
Game(list_a, list_b, Rule1)
and then your Game function could look something like this (still pseudocode):
def Game(listA, listB, rules=None):
if rules:
# do something useful
# ...
result = rules(variable) # this is how you can call your rule
else:
# do something useful without rules
A function name can become a variable name (and thus be passed as an argument) by dropping the parentheses. A variable name can become a function name by adding the parentheses.
In your example, equate the variable rules to one of your functions, leaving off the parentheses and the mention of the argument. Then in your game() function, invoke rules( v ) with the parentheses and the v parameter.
if puzzle == type1:
rules = Rule1
else:
rules = Rule2
def Game(listA, listB, rules):
if rules( v ) == True:
do...
else:
do...

Categories

Resources