Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Real-world examples of nested functions

I asked previously how the nested functions work, but unfortunately I still don't quite get it. To understand it better, can someone please show some real-wold, practical usage examples of nested functions?

Many thanks

like image 755
eozzy Avatar asked Jan 06 '10 23:01

eozzy


4 Answers

They are useful when using functions that take other functions as input. Say you're in a function, and want to sort a list of items based on the items' value in a dict:

def f(items):
    vals = {}
    for i in items: vals[i] = random.randint(0,100)
    def key(i): return vals[i] 
    items.sort(key=key)

You can just define key right there and have it use vals, a local variable.

Another use-case is callbacks.

like image 155
Claudiu Avatar answered Nov 08 '22 13:11

Claudiu


Your question made me curious, so I looked in some real-world code: the Python standard library. I found 67 examples of nested functions. Here are a few, with explanations.

One very simple reason to use a nested function is simply that the function you're defining doesn't need to be global, because only the enclosing function uses it. A typical example from Python's quopri.py standard library module:

def encode(input, output, quotetabs, header = 0):
    ...
    def write(s, output=output, lineEnd='\n'):
        # RFC 1521 requires that the line ending in a space or tab must have
        # that trailing character encoded.
        if s and s[-1:] in ' \t':
            output.write(s[:-1] + quote(s[-1]) + lineEnd)
        elif s == '.':
            output.write(quote(s) + lineEnd)
        else:
            output.write(s + lineEnd)

    ...  # 35 more lines of code that call write in several places

Here there was some common code within the encode function, so the author simply factored it out into a write function.


Another common use for nested functions is re.sub. Here's some code from the json/encode.py standard library module:

def encode_basestring(s):
    """Return a JSON representation of a Python string

    """
    def replace(match):
        return ESCAPE_DCT[match.group(0)]
    return '"' + ESCAPE.sub(replace, s) + '"'

Here ESCAPE is a regular expression, and ESCAPE.sub(replace, s) finds all matches of ESCAPE in s and replaces each one with replace(match).


In fact, any API, like re.sub, that accepts a function as a parameter can lead to situations where nested functions are convenient. For example, in turtle.py there's some silly demo code that does this:

    def baba(xdummy, ydummy):
        clearscreen()
        bye()

    ...
    tri.write("  Click me!", font = ("Courier", 12, "bold") )
    tri.onclick(baba, 1)

onclick expects you to pass an event-handler function, so we define one and pass it in.

like image 39
Jason Orendorff Avatar answered Nov 08 '22 12:11

Jason Orendorff


Decorators are a very popular use for nested functions. Here's an example of a decorator that prints a statement before and after any call to the decorated function.

def entry_exit(f):
    def new_f(*args, **kwargs):
        print "Entering", f.__name__
        f(*args, **kwargs)
        print "Exited", f.__name__
    return new_f

@entry_exit
def func1():
    print "inside func1()"

@entry_exit
def func2():
    print "inside func2()"

func1()
func2()
print func1.__name__
like image 23
Mr Fooz Avatar answered Nov 08 '22 14:11

Mr Fooz


Nested functions avoid cluttering other parts of the program with other functions and variables that only make sense locally.

A function that return Fibonacci numbers could be defined as follows:

>>> def fib(n):
        def rec():
            return fib(n-1) + fib(n-2)

        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            return rec()

>>> map(fib, range(10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

EDIT: In practice, generators would be a better solution for this, but the example shows how to take advantage of nested functions.

like image 4
jbochi Avatar answered Nov 08 '22 14:11

jbochi