Reputation: 71
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!
Upvotes: 1
Views: 76
Reputation: 1989
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
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.
Upvotes: 0
Reputation: 155506
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).
Upvotes: 2
Reputation: 21
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
Upvotes: 0
Reputation: 8035
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!
Upvotes: 1
Reputation: 5242
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.
Upvotes: 1