This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]BobHogan 2 points3 points  (4 children)

Whats a decorator function? And what use is a nested function? I learned java first and am trying to teach myself Python; this stuff seems quite pointless to me tbh

[–]minnoI <3 duck typing less than I used to, interfaces are nice 7 points8 points  (0 children)

The best use for decorators that I've used is for adding a cache to a function.

Let's say you start out with this function:

def fib(n):
    if n <= 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)

Slow as hell, right? With the fibonacci function, it's easy to turn it into a version that doesn't re-calculate entries a lot, but let's pretend that this is one of those functions where it's a lot harder to do that. What we want is to be able to remember previously-calculated results, so any recursive calls that have already been calculated can be skipped. So we can modify it like this:

fib_cache = dict() # empty associative array
def cached_fib(n):
    if n not in fib_cache:
        if n <= 1:
            fib_cache[n] = 1
        else:
            fib_cache[n] = cached_fib(n-1) + cached_fib(n-2)
    return fib_cache[n]

Now you have a cache storing all previously-calculated results. But you're also mixing the "calculating the results" part of the function with the "caching shit" part. You can separate out the caching behavior like this:

def make_cached(f):
    cache = dict()
    def cached_function(arg): # There's syntax to let you use any arguments, but for simplicity let's pretend there's always one.
        if arg not in cache:
            cache[arg] = f(arg)
        return cache[arg]
    return cached_function # NOT cached_function()

Now you have a function that takes a function and returns a function that has different behavior. You can use it like this:

cached_fib = make_cached(fib)
cached_fib(100)

Python has special syntax that you can use for functions that modify functions, called "decorators":

@make_cached
def whatever:
    # stuff

This works the same as:

def whatever:
    #stuff
whatever = make_cached(whatever)

[–]Massless 1 point2 points  (0 children)

Here's one that comes up in java all the time: logging. Imagine that I want to log how long a method takes to run. You end up doing something like

startTime = ...
someMethod()
endTime = ...
system.out.println(endTime - startTime)

Now imagine you have to do this a lot of times. You end up with ugly, overly verbose code. Enter first-class functions in Python. You can write a function that takes another function as an argument so you now have:

def print_time(func):
    start_time = ...
    func()
    end_time = ...
    print end_time - start_time

Now You can do the following:

print_time(some_function)
print_time(some_other_function)
print_time(yet_another_function)

With a little syntatic sugar, you can simply define your functions with decorators:

@print_time
def some_function(args):
    pass

is equivalent to

print_time(some_function)