Confused with Functions and decorators
steve+comp.lang.python at pearwood.info
Sun Jul 20 08:41:08 CEST 2014
On Sat, 19 Jul 2014 03:52:18 -0700, Jerry lu wrote:
> Ok so i am trying to learn this and i do not understand some of it. I
> also tried to searched the web but i couldnt find any answers.
> 1. I dont understand when i will need to use a function that returns
> another function. eg
> def outer():
> def inner():
> x = 5
> return inner
> why not just use inner and forget about the whole outer function?
For the example given, there's no point in using an inner function.
(Especially since the inner function does nothing useful.) But there are
three common reasons for writing inner functions:
#1 Encapsulation and information hiding.
If you've ever programmed in Pascal, this may be familiar to you. You use
inner functions to hide them away from code outside of the function. Here
is a toy example that shows the basic idea:
return x + 1
y = increment(x)
print x, y
In Python, I would rarely bother to write code like that. I'd just make
the increment function a top-level function, marked as "private" with a
leading underscore: _increment.
One place where the Pascal-style nested function may be useful is with
if not isinstance(n, int):
raise TypeError("n must be an integer")
if not n >= 0:
raise ValueError("n must be zero or positive")
if n <= 1:
This has three advantages:
* The caller cannot (easily) bypass the outer function and call the inner
* The outer function performs all the argument checking and any pre-
processing once only, the inner function can safely assume the argument
is valid and eschew pointless error checking.
* The outer function can be renamed without breaking the recursion.
#2 Don't Repeat Yourself (DRY)
Sometimes you may have a big function that performs the same chunk of
code in two places. For example, you might write a function which
processes a file, and you want to accept either an open file object or a
for line in fp:
if isinstance(the_file, str):
with open(the_file, 'r') as f:
Again, it is common to put do_stuff as a private top-level function, but
if you want to hide it away as an internal function, you can.
#3 Closures and factory functions
But now we come to the most important reason to use internal functions.
All of the inner functions I've shown so far have been ordinary functions
that merely happened to be nested inside another function. But when we
come to closures, that is not the case.
A closure is an inner function which "remembers" the state of its
environment when called. Here's a basic example:
"""Make an new function which increments its argument by inc.
Examples of use:
>>> add_one = make_incrementer(1)
>>> add_two = make_incrementer(2)
return x + inc
This takes more effort to explain than to write!
The "make_incrementer" function is a *factory function*. It builds a new
function each time it is called, then returns it. What does this new,
inner, function do? It takes a single argument, x, and returns x + inc.
Where does the inner function get the value of inc from? This is what
makes it a closure -- it gets the value of inc from the outer function,
the factory. How it works is something like like this:
=> build a function "incrementer" which takes a single argument x
=> take a snap-shot of the state of make_incrementer function
which includes inc=3
=> stuff that snap-shot into the incrementer function
=> return the incrementer function
Now, whenever you call that newly returned function, it will always see
its own private snap-shot that includes inc=3.
The use of closures and factory functions is the most common, and
powerful, use for inner functions. 9 times out of 10, if you see a
the decorator is a factory function which takes an function as argument,
and returns a new function which which includes the old function inside
the closure. But that's now getting into more advanced territory.
> 2. This is more yes or no question when you pass in a func into another
> func as a parameter do you need to specify the parameter that the func
> is being passed into as func?
You can pass functions around from place to place until the cows come
how, stuff them into lists and dicts, extract them again, and not care
one iota about its arguments until you actually call it.
More information about the Python-list